public void ExecuteBuild(BuildInformation buildInformation, ChangeObservable observable) { if (string.IsNullOrEmpty(binariesLocator.GetExecutableCommand("cmake"))) { throw new FormattableException("CMake cannot be found. Please install a new version of CMake and ensure that it will be added to the search path settings."); } (bool _, VirtualDirectory cmakeFolder) = EnsureConfigured(buildInformation, observable, true); TouchMainCMakeFile(); CallCmake(cmakeFolder, "--build . --target install", true, true); void TouchMainCMakeFile() { if (buildInformation.RootProjectEntity.Version > new Version(1, 0)) { //do not touch newer project version cmake file return; } if (!buildInformation.RootFileEntity.Directory.FileExists("CMakeLists.txt")) { throw new CMakeFileNotFoundException(); } VirtualFile cmakeFile = buildInformation.RootFileEntity.Directory.File("CMakeLists.txt"); cmakeFile.Touch(); } }
public void Build(BuildInformation buildInfo, ChangeObservable observable, IEnumerable <string> targets) { if (!targets.Any()) { TargetsResult projectTargets = targetParser.Targets(buildInfo.RootProjectEntity); projectTargets.Errors.ThrowIfNotEmpty(); if (!projectTargets.ValidTargets.Any()) { throw new NoAssignedTargetsException(buildInfo.RootEntity.Name); } BuildProjectForTargets(buildInfo, observable, projectTargets.ValidTargets); } else { //build for selected target(s) BuildProjectForTargets(buildInfo, observable, targetParser.GetSpecificTargets(targets).Select(t => t.Item1)); } }
public BuildSystemProperties RetrieveBuildSystemProperties(Entity rootEntity, Target projectTarget, ChangeObservable observable) { BuildInformation buildInformation = new BuildInformation(rootEntity, null, false, false, string.Empty, null) { Target = projectTarget, SdkInformation = sdkRepository.GetSdk(projectTarget) }; (bool success, VirtualDirectory cmakeFolder) = cmakeExecuter.EnsureConfigured( buildInformation, showWarningsToUser: true, observable, showMessagesToUser: false); JArray codeModel = buildInformation.BuildEntity.BuildSystem.Value <JArray>(); IEnumerable <string> includePaths = GetIncludePathsFromCodeModel(); return(new BuildSystemProperties(includePaths)); IEnumerable <string> GetIncludePathsFromCodeModel() { List <string> result = new List <string>(); JObject cmakeTarget = codeModel.GetProjectTarget(rootEntity.Name, false); if (cmakeTarget != null && cmakeTarget["fileGroups"] is JArray fileGroups) { foreach (JObject fileGroup in fileGroups.OfType <JObject>()) { if (fileGroup["includePath"] is JArray paths) { result.AddRange(paths.Select(path => path["path"]?.Value <string>()) .Where(include => !string.IsNullOrEmpty(include))); } } } return(result); } }
private void BuildProjectForTargets(BuildInformation buildInfo, ChangeObservable observable, IEnumerable <Target> targets) { targets = targets.ToArray(); MultiDictionary <SdkInformation, Target> sdks = new MultiDictionary <SdkInformation, Target>(); List <FormattableException> exceptions = new List <FormattableException>(); foreach (Target target in targets) { try { sdks.Add(sdkRepository.GetSdk(target), target); } catch (FormattableException ex) { exceptions.Add(ex); } } if (exceptions.Any()) { throw new AggregateException(exceptions); } userInterface.WriteInformation($"Requested build for targets {String.Join(", ", targets.Select(x => x.GetFullName()).ToArray())}"); foreach (SdkInformation sdk in sdks.Keys) { foreach (Target target in sdks.Get(sdk)) { userInterface.WriteInformation($"Starting build for target {target.GetFullName()}"); buildInfo.SdkInformation = sdk; buildInfo.Target = target; buildExecuter.ExecuteBuild(buildInfo, observable); userInterface.WriteInformation($"Successfully built the project {buildInfo.RootEntity.Name} for target {target.GetFullName()}."); } } userInterface.WriteInformation($"Finished build for all targets"); }
public (bool, VirtualDirectory) EnsureConfigured(BuildInformation buildInformation, bool showWarningsToUser, ChangeObservable observable = null, bool throwOnError = false, bool showMessagesToUser = true) { if (!CmakeFileExists()) { GenerateCmakeFile(); } VirtualDirectory cmakeFolder = CreateCmakeFolder(); bool success = ConfigureCMake(); return(success, cmakeFolder); void GenerateCmakeFile() { VirtualFile cMakeFile = buildInformation.RootFileEntity.Directory.File(Constants.CMakeFileName); //TODO Generate cmakefile with template system //TODO Set src folders in cmake file (consider foreign project structure) CMakeFileGenerator.WriteCMakeFile(cMakeFile, buildInformation.RootEntity.Name); observable?.OnNext(new Change(() => { /*Do not delete, because user need to make changes perhaps*/ }, $"Generated cmake file {cMakeFile.FullName}")); } bool CmakeFileExists() { return(buildInformation.RootFileEntity.Directory.FileExists(Constants.CMakeFileName)); } VirtualDirectory CreateCmakeFolder() { VirtualDirectory result = buildInformation.BuildEntity.BuildSystemDirectory; if (buildInformation.Configure && !buildInformation.NoConfigure) { result.Clear(); observable?.OnNext(new Change(() => result.UnClear(), $"Cleared cmake directory.")); } return(result); } string GetRealBuildType() { string buildType = !string.IsNullOrEmpty(buildInformation.BuildType) ? buildInformation.BuildType : Constants.ReleaseFolderName; return(buildType); } bool ConfigureCMake() { executionContext.WriteInformation("Checking if CMake needs to be reconfigured...", showMessagesToUser); if ((!cmakeFolder.FileExists("CMakeCache.txt") || buildInformation.Configure || !IsCorrectlyConfigured() || OutputOptionDiffersFromStagingPrefix()) && !buildInformation.NoConfigure) { string cmakeCommand = GenerateCmakeCommand(buildInformation.Target.Name, buildInformation.Target.LongVersion); if (showMessagesToUser) { executionContext.WriteInformation("Configuring CMake..."); } return(CallCmake(cmakeFolder, cmakeCommand, showMessagesToUser, throwOnError, showWarningsToUser)); } if (!string.IsNullOrEmpty(buildInformation.BuildProperties)) { executionContext.WriteWarning($"The specified build options will not be used, " + $"because no reconfiguration is necessary. " + $"To force a reconfiguration please use the '--configure' command option.", showMessagesToUser); } return(true); string GenerateCmakeCommand(string target, string version) { List <string> commandParts = new List <string>(); string sdkRoot = buildInformation.SdkInformation.Root.FullName.Replace("\\", "/"); if (!buildInformation.BuildProperties.Contains("-DCMAKE_TOOLCHAIN_FILE ")) { commandParts.Add(ToolchainFileOption.Replace("%SDK_ROOT%", sdkRoot)); } if (!buildInformation.BuildProperties.Contains("-DARP_TOOLCHAIN_ROOT ")) { commandParts.Add(ToolchainRootOption.Replace("%SDK_ROOT%", sdkRoot)); } if (!buildInformation.BuildProperties.Contains("-DCMAKE_BUILD_TYPE ")) { commandParts.Add(BuildTypeOption.Replace("%BUILD_TYPE%", GetRealBuildType())); } if (!buildInformation.BuildProperties.Contains("-DARP_DEVICE ")) { commandParts.Add(DeviceOption.Replace("%TARGET%", $"\"{target}\"")); } if (!buildInformation.BuildProperties.Contains("-DARP_DEVICE_VERSION ")) { commandParts.Add(DeviceVersionOption.Replace("%VERSION%", $"\"{version}\"")); } if (!buildInformation.BuildProperties.Contains("-DCMAKE_STAGING_PREFIX ")) { commandParts.Add(StagingPrefixOption.Replace("%STAGING_PREFIX%", GenerateStagingPrefixForTarget())); } if (!buildInformation.BuildProperties.Contains("-DCMAKE_PREFIX_PATH ") && IsIncludePathAvailable(out string includePath)) { commandParts.Add(PrefixPathOption.Replace("%PREFIX_PATH%", includePath)); } if (!buildInformation.BuildProperties.Contains("-G ")) { commandParts.Add(GeneratorOption); if (buildInformation.SdkInformation.MakeFile != null && !buildInformation.BuildProperties.Contains("-DCMAKE_MAKE_PROGRAM ")) { commandParts.Add(MakeFileOption.Replace("%MAKE_EXE%", $"\"{buildInformation.SdkInformation.MakeFile.FullName.Replace("\\", "/")}\"")); } } if (!string.IsNullOrEmpty(buildInformation.BuildProperties)) { commandParts.Add(buildInformation.BuildProperties); } commandParts.Add($"\"{buildInformation.RootFileEntity.Directory.FullName.Replace("\\", "/")}\""); return(string.Join(" ", commandParts)); string GenerateStagingPrefixForTarget() { string basePath = buildInformation.RootFileEntity.Directory.FullName; return(buildInformation.Output != null ? OutputOptionFullPath() : Path.Combine(basePath, Constants.LibraryFolderName) .Replace(Path.DirectorySeparatorChar, '/')); } bool IsIncludePathAvailable(out string path) { path = null; if (!buildInformation.RootFileEntity.Directory.DirectoryExists("external")) { return(false); } Dictionary <Version, VirtualDirectory> versions = new Dictionary <Version, VirtualDirectory>(); VirtualDirectory externalDirectory = buildInformation.RootFileEntity.Directory.Directory("external"); foreach (VirtualDirectory directory in externalDirectory.Directories) { Match patternMatch = IncludeDirectoryPattern.Match(directory.Name); if (!patternMatch.Success || !Version.TryParse(patternMatch.Groups["version"].Value, out Version includeVersion) || target != patternMatch.Groups["name"].Value) { continue; } versions.Add(includeVersion, directory); } Version actualVersion = Version.Parse(buildInformation.Target.Version); Version bestMatch = versions.Keys.Where(v => v <= actualVersion) .OrderByDescending(v => v) .FirstOrDefault(); if (bestMatch != null) { VirtualDirectory directory = versions[bestMatch]; if (directory.DirectoryExists(buildInformation.BuildType)) { path = directory.Directory(buildInformation.BuildType).FullName; } else if (directory.DirectoryExists(Constants.ReleaseFolderName)) { path = directory.Directory(Constants.ReleaseFolderName).FullName; } else { path = directory.FullName; } } else { path = externalDirectory.FullName; } return(true); } } string OutputOptionFullPath() { return(fileSystem.GetDirectory(buildInformation.Output, buildInformation.RootFileEntity.Directory.FullName) .FullName.Replace(Path.DirectorySeparatorChar, '/')); } bool OutputOptionDiffersFromStagingPrefix() { return(buildInformation.Output != null && !buildInformation.BuildEntity.BuildSystem.InstallationPaths.Any(p => p.StartsWith(OutputOptionFullPath(), StringComparison.Ordinal))); } bool IsCorrectlyConfigured() { try { return(buildInformation.BuildEntity.HasBuildSystem && buildInformation.BuildEntity.BuildSystem != null); } catch (Exception e) { if (!IsTimeout(e)) { executionContext.WriteVerbose($"The project is not correctly configured:{Environment.NewLine}{e}"); return(false); } } return(true); //this is a timeout so we dont know if it is correctly configured bool IsTimeout(Exception exception) { return(exception is TimeoutException || exception is AggregateException aggregate && aggregate.InnerExceptions.Any(e => e is TimeoutException)); } } } }
public (bool, VirtualDirectory) EnsureConfigured(BuildInformation buildInformation, ChangeObservable observable = null, bool throwOnError = false, bool showMessagesToUser = true) { return(EnsureConfigured(buildInformation, showMessagesToUser, observable, throwOnError, showMessagesToUser)); }