Example #1
0
        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();
            }
        }
Example #2
0
        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));
            }
        }
Example #3
0
        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);
            }
        }
Example #4
0
        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");
        }
Example #5
0
        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));
                    }
                }
            }
        }
Example #6
0
 public (bool, VirtualDirectory) EnsureConfigured(BuildInformation buildInformation, ChangeObservable observable = null, bool throwOnError = false,
                                                  bool showMessagesToUser = true)
 {
     return(EnsureConfigured(buildInformation, showMessagesToUser, observable, throwOnError, showMessagesToUser));
 }