private List <Solution.ResolvedProject> ResolveSolutionProjects(Solution solution, List <Solution.Configuration> solutionConfigurations) { bool projectsWereFiltered; List <Solution.ResolvedProject> solutionProjects = solution.GetResolvedProjects(solutionConfigurations, out projectsWereFiltered).ToList(); // Ensure all projects are always in the same order to avoid random shuffles solutionProjects.Sort((a, b) => { int nameComparison = string.Compare(a.ProjectName, b.ProjectName, StringComparison.InvariantCultureIgnoreCase); if (nameComparison != 0) { return(nameComparison); } return(string.Compare(a.ProjectFile, b.ProjectFile, StringComparison.InvariantCultureIgnoreCase)); }); // Validate and handle startup project. IEnumerable <Solution.Configuration> confWithStartupProjects = solutionConfigurations.Where(conf => conf.StartupProject != null); var startupProjectGroups = confWithStartupProjects.GroupBy(conf => conf.StartupProject.Configuration.ProjectFullFileName).ToArray(); if (startupProjectGroups.Length > 1) { throw new Error("Solution {0} contains multiple startup projects; this is not supported. Startup projects: {1}", Path.Combine(solutionConfigurations[0].SolutionPath, solutionConfigurations[0].SolutionFileName), string.Join(", ", startupProjectGroups.Select(group => group.Key))); } Solution.Configuration.IncludedProjectInfo startupProject = startupProjectGroups.Select(group => group.First().StartupProject).FirstOrDefault(); if (startupProject != null) { //put the startup project at the top of the project list. Visual Studio will put it as the default startup project. Solution.ResolvedProject resolvedStartupProject = solutionProjects.FirstOrDefault(x => x.OriginalProjectFile == startupProject.Configuration.ProjectFullFileName); if (resolvedStartupProject != null) { solutionProjects.Remove(resolvedStartupProject); solutionProjects.Insert(0, resolvedStartupProject); } } // Read project Guid and append project extension foreach (Solution.ResolvedProject resolvedProject in solutionProjects) { Project.Configuration firstConf = resolvedProject.Configurations.First(); if (firstConf.ProjectGuid == null) { if (!firstConf.Project.GetType().IsDefined(typeof(Compile), false)) { throw new Error("cannot read guid from existing project, project must have Compile attribute: {0}", resolvedProject.ProjectFile); } firstConf.ProjectGuid = ReadGuidFromProjectFile(resolvedProject.ProjectFile); } resolvedProject.UserData["Guid"] = firstConf.ProjectGuid; resolvedProject.UserData["TypeGuid"] = ReadTypeGuidFromProjectFile(resolvedProject.ProjectFile); resolvedProject.UserData["Folder"] = GetSolutionFolder(resolvedProject.SolutionFolder); } return(solutionProjects); }
private bool IsFastBuildEnabled() { foreach (var solutionConfiguration in this) { foreach (var solutionProject in ResolvedProjects) { var project = solutionProject.Project; // Export projects do not have any bff if (project.GetType().IsDefined(typeof(Export), false)) { continue; } // When the project has a source file filter, only keep it if the file list is not empty if (project.SourceFilesFilters != null && (project.SourceFilesFiltersCount == 0 || project.SkipProjectWhenFiltersActive)) { continue; } Solution.Configuration.IncludedProjectInfo includedProject = solutionConfiguration.GetProject(solutionProject.Project.GetType()); bool perfectMatch = includedProject != null && solutionProject.Configurations.Contains(includedProject.Configuration); if (!perfectMatch) { continue; } var conf = includedProject.Configuration; if (!conf.IsFastBuildEnabledProjectConfig()) { continue; } return(true); } } return(false); }
private string Generate( Solution solution, IReadOnlyList <Solution.Configuration> solutionConfigurations, string solutionPath, string solutionFile, bool addMasterBff, out bool updated ) { // reset current solution state _rootSolutionFolders.Clear(); _solutionFolders.Clear(); FileInfo solutionFileInfo = new FileInfo(Util.GetCapitalizedPath(solutionPath + Path.DirectorySeparatorChar + solutionFile + SolutionExtension)); string solutionGuid = Util.BuildGuid(solutionFileInfo.FullName, solution.SharpmakeCsPath); DevEnv devEnv = solutionConfigurations[0].Target.GetFragment <DevEnv>(); List <Solution.ResolvedProject> solutionProjects = ResolveSolutionProjects(solution, solutionConfigurations); if (solutionProjects.Count == 0) { updated = solutionFileInfo.Exists; if (updated) { Util.TryDeleteFile(solutionFileInfo.FullName); } return(solutionFileInfo.FullName); } List <Solution.ResolvedProject> resolvedPathReferences = ResolveReferencesByPath(solutionProjects, solutionConfigurations[0].ProjectReferencesByPath); var guidlist = solutionProjects.Select(p => p.UserData["Guid"]); resolvedPathReferences = resolvedPathReferences.Where(r => !guidlist.Contains(r.UserData["Guid"])).ToList(); var fileGenerator = new FileGenerator(); // write solution header switch (devEnv) { case DevEnv.vs2010: fileGenerator.Write(Template.Solution.HeaderBeginVs2010); break; case DevEnv.vs2012: fileGenerator.Write(Template.Solution.HeaderBeginVs2012); break; case DevEnv.vs2013: fileGenerator.Write(Template.Solution.HeaderBeginVs2013); break; case DevEnv.vs2015: fileGenerator.Write(Template.Solution.HeaderBeginVs2015); break; case DevEnv.vs2017: fileGenerator.Write(Template.Solution.HeaderBeginVs2017); break; case DevEnv.vs2019: fileGenerator.Write(Template.Solution.HeaderBeginVs2019); break; default: Console.WriteLine("Unsupported DevEnv for solution " + solutionConfigurations[0].Target.GetFragment <DevEnv>()); break; } SolutionFolder masterBffFolder = null; if (addMasterBff) { masterBffFolder = GetSolutionFolder(solution.FastBuildMasterBffSolutionFolder); if (masterBffFolder == null) { throw new Error("FastBuildMasterBffSolutionFolder needs to be set in solution " + solutionFile); } } // Write all needed folders before the projects to make sure the proper startup project is selected. // Ensure folders are always in the same order to avoid random shuffles _solutionFolders.Sort((a, b) => { int nameComparison = string.Compare(a.Name, b.Name, StringComparison.InvariantCultureIgnoreCase); if (nameComparison != 0) { return(nameComparison); } return(a.Guid.CompareTo(b.Guid)); }); foreach (SolutionFolder folder in _solutionFolders) { using (fileGenerator.Declare("folderName", folder.Name)) using (fileGenerator.Declare("folderGuid", folder.Guid.ToString().ToUpper())) { fileGenerator.Write(Template.Solution.ProjectFolder); if (masterBffFolder == folder) { var bffFilesPaths = new SortedSet <string>(new FileSystemStringComparer()); foreach (var conf in solutionConfigurations) { string masterBffFilePath = conf.MasterBffFilePath + FastBuildSettings.FastBuildConfigFileExtension; bffFilesPaths.Add(Util.PathGetRelative(solutionPath, masterBffFilePath)); bffFilesPaths.Add(Util.PathGetRelative(solutionPath, FastBuild.MasterBff.GetGlobalBffConfigFileName(masterBffFilePath))); } // This always needs to be created so make sure it's there. bffFilesPaths.Add(solutionFile + FastBuildSettings.FastBuildConfigFileExtension); fileGenerator.Write(Template.Solution.SolutionItemBegin); { foreach (var path in bffFilesPaths) { using (fileGenerator.Declare("solutionItemPath", path)) fileGenerator.Write(Template.Solution.SolutionItem); } } fileGenerator.Write(Template.Solution.ProjectSectionEnd); } fileGenerator.Write(Template.Solution.ProjectEnd); } } Solution.ResolvedProject fastBuildAllProjectForSolutionDependency = null; if (solution.FastBuildAllSlnDependencyFromExe) { var fastBuildAllProjects = solutionProjects.Where(p => p.Project.IsFastBuildAll).ToArray(); if (fastBuildAllProjects.Length > 1) { throw new Error("More than one FastBuildAll project"); } if (fastBuildAllProjects.Length == 1) { fastBuildAllProjectForSolutionDependency = fastBuildAllProjects[0]; } } using (fileGenerator.Declare("solution", solution)) using (fileGenerator.Declare("solutionGuid", solutionGuid)) { foreach (Solution.ResolvedProject resolvedProject in solutionProjects.Concat(resolvedPathReferences).Distinct(new Solution.ResolvedProjectGuidComparer())) { FileInfo projectFileInfo = new FileInfo(resolvedProject.ProjectFile); using (fileGenerator.Declare("project", resolvedProject.Project)) using (fileGenerator.Declare("projectName", resolvedProject.ProjectName)) using (fileGenerator.Declare("projectFile", Util.PathGetRelative(solutionFileInfo.Directory.FullName, projectFileInfo.FullName))) using (fileGenerator.Declare("projectGuid", resolvedProject.UserData["Guid"])) using (fileGenerator.Declare("projectTypeGuid", resolvedProject.UserData["TypeGuid"])) { fileGenerator.Write(Template.Solution.ProjectBegin); Strings buildDepsGuids = new Strings(resolvedProject.Configurations.SelectMany( c => c.GenericBuildDependencies.Select( p => p.ProjectGuid ?? ReadGuidFromProjectFile(p.ProjectFullFileNameWithExtension) ) )); if (fastBuildAllProjectForSolutionDependency != null) { bool writeDependencyToFastBuildAll = (resolvedProject.Configurations.Any(conf => conf.IsFastBuild && conf.Output == Project.Configuration.OutputType.Exe)) || solution.ProjectsDependingOnFastBuildAllForThisSolution.Contains(resolvedProject.Project); if (writeDependencyToFastBuildAll) { buildDepsGuids.Add(fastBuildAllProjectForSolutionDependency.UserData["Guid"] as string); } } if (buildDepsGuids.Any()) { fileGenerator.Write(Template.Solution.ProjectDependencyBegin); foreach (string guid in buildDepsGuids) { using (fileGenerator.Declare("projectDependencyGuid", guid)) fileGenerator.Write(Template.Solution.ProjectDependency); } fileGenerator.Write(Template.Solution.ProjectSectionEnd); } fileGenerator.Write(Template.Solution.ProjectEnd); } } } // Write extra solution items // TODO: What happens if we define an existing folder? foreach (var items in solution.ExtraItems) { using (fileGenerator.Declare("folderName", items.Key)) using (fileGenerator.Declare("folderGuid", Util.BuildGuid(items.Key))) using (fileGenerator.Declare("solution", solution)) { fileGenerator.Write(Template.Solution.ProjectFolder); { fileGenerator.Write(Template.Solution.SolutionItemBegin); foreach (string file in items.Value) { using (fileGenerator.Declare("solutionItemPath", Util.PathGetRelative(solutionPath, file))) fileGenerator.Write(Template.Solution.SolutionItem); } fileGenerator.Write(Template.Solution.ProjectSectionEnd); } fileGenerator.Write(Template.Solution.ProjectEnd); } } fileGenerator.Write(Template.Solution.GlobalBegin); // Write source code control information if (solution.PerforceRootPath != null) { List <Solution.ResolvedProject> sccProjects = new List <Solution.ResolvedProject>(); foreach (Solution.ResolvedProject resolvedProject in solutionProjects) { if (resolvedProject.Project.PerforceRootPath != null) { sccProjects.Add(resolvedProject); } else { _builder.LogWriteLine(@"warning: cannot bind solution {0} to perforce, PerforceRootPath for project '{1}' is not set.", solutionFileInfo.Name, resolvedProject.Project.ClassName); } } if (sccProjects.Count == solutionProjects.Count) { using (fileGenerator.Declare("sccNumberOfProjects", sccProjects.Count)) { fileGenerator.Write(Template.Solution.GlobalSectionSolutionSourceCodeControlBegin); } for (int i = 0; i < sccProjects.Count; ++i) { Solution.ResolvedProject resolvedProject = sccProjects[i]; FileInfo projectFileInfo = new FileInfo(resolvedProject.ProjectFile); //SccProjectUniqueName7 = ..\\..\\extern\\techgroup\\framework\\gear\\private\\compilers\\win32\\vc9\\gear_win32_compile.vcproj string sccProjectUniqueName = Util.PathGetRelative(solutionFileInfo.Directory.FullName, projectFileInfo.FullName).Replace("\\", "\\\\"); //SccProjectTopLevelParentUniqueName7 = guildlib.sln string sccProjectTopLevelParentUniqueName = solutionFileInfo.Name; // sln to perforce file //SccLocalPath7 = ..\\..\\extern\\techgroup\\framework\\gear string sccLocalPath = Util.PathGetRelative(solutionPath, resolvedProject.Project.PerforceRootPath).Replace("\\", "\\\\"); //SccProjectFilePathRelativizedFromConnection7 = private\\compilers\\win32\\vc9\\ string sccProjectFilePathRelativizedFromConnection = Util.PathGetRelative(resolvedProject.Project.PerforceRootPath, projectFileInfo.DirectoryName).Trim('.', '\\').Replace("\\", "\\\\"); using (fileGenerator.Declare("i", i)) using (fileGenerator.Declare("sccProjectUniqueName", sccProjectUniqueName)) using (fileGenerator.Declare("sccProjectTopLevelParentUniqueName", sccProjectTopLevelParentUniqueName)) using (fileGenerator.Declare("sccLocalPath", sccLocalPath)) using (fileGenerator.Declare("sccProjectFilePathRelativizedFromConnection", sccProjectFilePathRelativizedFromConnection)) { fileGenerator.Write(Template.Solution.GlobalSectionSolutionSourceCodeControlProject); } } fileGenerator.Write(Template.Solution.GlobalSectionSolutionSourceCodeControlEnd); } } // write solution configurations string visualStudioExe = GetVisualStudioIdePath(devEnv) + Util.WindowsSeparator + "devenv.com"; var configurationSectionNames = new List <string>(); bool containsMultiDotNetFramework = solutionConfigurations.All(sc => sc.Target.HaveFragment <DotNetFramework>()) && solutionConfigurations.Select(sc => sc.Target.GetFragment <DotNetFramework>()).Distinct().Count() > 1; var multiDotNetFrameworkConfigurationNames = new HashSet <string>(); fileGenerator.Write(Template.Solution.GlobalSectionSolutionConfigurationBegin); foreach (Solution.Configuration solutionConfiguration in solutionConfigurations) { string configurationName; string category; if (solution.MergePlatformConfiguration) { configurationName = solutionConfiguration.PlatformName + "-" + solutionConfiguration.Name; category = "All Platforms"; } else { configurationName = solutionConfiguration.Name; category = solutionConfiguration.PlatformName; } if (containsMultiDotNetFramework) { if (multiDotNetFrameworkConfigurationNames.Contains(configurationName)) { continue; } multiDotNetFrameworkConfigurationNames.Add(configurationName); } using (fileGenerator.Declare("configurationName", configurationName)) using (fileGenerator.Declare("category", category)) { configurationSectionNames.Add(fileGenerator.Resolver.Resolve(Template.Solution.GlobalSectionSolutionConfiguration)); } // set the compile command line if (File.Exists(visualStudioExe)) { solutionConfiguration.CompileCommandLine = string.Format(@"""{0}"" ""{1}"" /build ""{2}|{3}""", visualStudioExe, solutionFileInfo.FullName, configurationName, category); } } configurationSectionNames.Sort(); VerifySectionNamesDuplicates(solutionFileInfo.FullName, solutionConfigurations, configurationSectionNames); foreach (string configurationSectionName in configurationSectionNames) { fileGenerator.Write(configurationSectionName); } fileGenerator.Write(Template.Solution.GlobalSectionSolutionConfigurationEnd); if (containsMultiDotNetFramework) { multiDotNetFrameworkConfigurationNames.Clear(); } // write all project target and match then to a solution target fileGenerator.Write(Template.Solution.GlobalSectionProjectConfigurationBegin); var solutionConfigurationFastBuildBuilt = new Dictionary <Solution.Configuration, List <string> >(); foreach (Solution.ResolvedProject solutionProject in solutionProjects) { foreach (Solution.Configuration solutionConfiguration in solutionConfigurations) { ITarget solutionTarget = solutionConfiguration.Target; ITarget projectTarget = null; Solution.Configuration.IncludedProjectInfo includedProject = solutionConfiguration.GetProject(solutionProject.Project.GetType()); bool perfectMatch = includedProject != null && solutionProject.Configurations.Contains(includedProject.Configuration); if (perfectMatch) { projectTarget = includedProject.Target; } else { // try to find the target in the project that is the closest match from the solution one int maxEqualFragments = 0; int[] solutionTargetValues = solutionTarget.GetFragmentsValue(); Platform previousPlatform = Platform._reserved1; foreach (var conf in solutionProject.Configurations) { Platform currentTargetPlatform = conf.Target.GetPlatform(); int[] candidateTargetValues = conf.Target.GetFragmentsValue(); if (solutionTargetValues.Length != candidateTargetValues.Length) { continue; } int equalFragments = 0; for (int i = 0; i < solutionTargetValues.Length; ++i) { if ((solutionTargetValues[i] & candidateTargetValues[i]) != 0) { equalFragments++; } } if ((equalFragments == maxEqualFragments && currentTargetPlatform < previousPlatform) || equalFragments > maxEqualFragments) { projectTarget = conf.Target; maxEqualFragments = equalFragments; previousPlatform = currentTargetPlatform; } } // last resort: if we didn't find a good enough match, fallback to TargetDefault if (projectTarget == null) { projectTarget = solutionProject.TargetDefault; } } Project.Configuration projectConf = solutionProject.Project.GetConfiguration(projectTarget); if (includedProject != null && includedProject.Configuration.IsFastBuild) { solutionConfigurationFastBuildBuilt.GetValueOrAdd(solutionConfiguration, new List <string>()); } Platform projectPlatform = projectTarget.GetPlatform(); string configurationName; string category; if (solution.MergePlatformConfiguration) { configurationName = solutionConfiguration.PlatformName + "-" + solutionConfiguration.Name; category = "All Platforms"; } else { configurationName = solutionConfiguration.Name; category = solutionConfiguration.PlatformName; } if (containsMultiDotNetFramework) { if (multiDotNetFrameworkConfigurationNames.Contains(configurationName)) { continue; } multiDotNetFrameworkConfigurationNames.Add(configurationName); } using (fileGenerator.Declare("solutionConf", solutionConfiguration)) using (fileGenerator.Declare("projectGuid", solutionProject.UserData["Guid"])) using (fileGenerator.Declare("projectConf", projectConf)) using (fileGenerator.Declare("projectPlatform", Util.GetPlatformString(projectPlatform, solutionProject.Project, solutionConfiguration.Target, true))) using (fileGenerator.Declare("category", category)) using (fileGenerator.Declare("configurationName", configurationName)) { bool build = false; if (solution is PythonSolution) { // nothing is built in python solutions } else if (perfectMatch) { build = includedProject.ToBuild == Solution.Configuration.IncludedProjectInfo.Build.Yes; // for fastbuild, only build the projects that cannot be built through dependency chain if (!projectConf.IsFastBuild) { build |= includedProject.ToBuild == Solution.Configuration.IncludedProjectInfo.Build.YesThroughDependency; } else { if (build) { solutionConfigurationFastBuildBuilt[solutionConfiguration].Add(projectConf.Project.Name + " " + projectConf.Name); } } } fileGenerator.Write(Template.Solution.GlobalSectionProjectConfigurationActive); if (build) { fileGenerator.Write(Template.Solution.GlobalSectionProjectConfigurationBuild); bool deployProject = includedProject.Project.DeployProject || includedProject.Configuration.DeployProject; if (deployProject) { fileGenerator.Write(Template.Solution.GlobalSectionProjectConfigurationDeploy); } } } } } foreach (var fb in solutionConfigurationFastBuildBuilt) { var solutionConfiguration = fb.Key; if (fb.Value.Count == 0) { Builder.Instance.LogErrorLine($"{solutionFile} - {solutionConfiguration.Name}|{solutionConfiguration.PlatformName} - has no FastBuild projects to build."); } else if (fb.Value.Count > 1) { Builder.Instance.LogErrorLine($"{solutionFile} - {solutionConfiguration.Name}|{solutionConfiguration.PlatformName} - has more than one FastBuild project to build ({string.Join(";", fb.Value)})."); } } fileGenerator.Write(Template.Solution.GlobalSectionProjectConfigurationEnd); fileGenerator.Write(Template.Solution.SolutionProperties); // Write nested folders if (_solutionFolders.Count != 0) { fileGenerator.Write(Template.Solution.NestedProjectBegin); foreach (SolutionFolder folder in _solutionFolders) { if (folder.Parent != null) { using (fileGenerator.Declare("nestedChildGuid", folder.Guid.ToString().ToUpper())) using (fileGenerator.Declare("nestedParentGuid", folder.Parent.Guid.ToString().ToUpper())) { fileGenerator.Write(Template.Solution.NestedProjectItem); } } } foreach (Solution.ResolvedProject resolvedProject in solutionProjects.Concat(resolvedPathReferences)) { SolutionFolder folder = resolvedProject.UserData["Folder"] as SolutionFolder; if (folder != null) { using (fileGenerator.Declare("nestedChildGuid", resolvedProject.UserData["Guid"].ToString().ToUpper())) using (fileGenerator.Declare("nestedParentGuid", folder.Guid.ToString().ToUpper())) { fileGenerator.Write(Template.Solution.NestedProjectItem); } } } fileGenerator.Write(Template.Solution.NestedProjectEnd); } fileGenerator.Write(Template.Solution.GlobalEnd); // Write the solution file updated = _builder.Context.WriteGeneratedFile(solution.GetType(), solutionFileInfo, fileGenerator.ToMemoryStream()); solution.PostGenerationCallback?.Invoke(solutionPath, solutionFile, SolutionExtension); return(solutionFileInfo.FullName); }
private static bool GenerateMasterBffFile(Builder builder, ConfigurationsPerBff configurationsPerBff) { string masterBffFilePath = Util.GetCapitalizedPath(configurationsPerBff.BffFilePathWithExtension); string masterBffDirectory = Path.GetDirectoryName(masterBffFilePath); string masterBffFileName = Path.GetFileName(masterBffFilePath); // Global configuration file is in the same directory as the master bff but filename suffix added to its filename. string globalConfigFullPath = GetGlobalBffConfigFileName(masterBffFilePath); string globalConfigFileName = Path.GetFileName(globalConfigFullPath); var solutionProjects = configurationsPerBff.ResolvedProjects; if (solutionProjects.Count == 0 && configurationsPerBff.ProjectsWereFiltered) { // We are running in filter mode for submit assistant and all projects were filtered out. // We need to skip generation and delete any existing master bff file. Util.TryDeleteFile(masterBffFilePath); return(false); } // Start writing Bff var fileGenerator = new FileGenerator(); var masterBffInfo = new MasterBffInfo(); var bffPreBuildSection = new Dictionary <string, string>(); var bffCustomPreBuildSection = new Dictionary <string, string>(); var bffMasterSection = new Dictionary <string, string>(); var masterBffCopySections = new List <string>(); var masterBffCustomSections = new UniqueList <string>(); // section that is not ordered bool mustGenerateFastbuild = false; var platformBffCache = new Dictionary <Platform, IPlatformBff>(); var verificationPostBuildCopies = new Dictionary <string, string>(); foreach (Solution.Configuration solutionConfiguration in configurationsPerBff) { foreach (var solutionProject in solutionProjects) { var project = solutionProject.Project; // Export projects do not have any bff if (project.GetType().IsDefined(typeof(Export), false)) { continue; } // When the project has a source file filter, only keep it if the file list is not empty if (project.SourceFilesFilters != null && (project.SourceFilesFiltersCount == 0 || project.SkipProjectWhenFiltersActive)) { continue; } Solution.Configuration.IncludedProjectInfo includedProject = solutionConfiguration.GetProject(solutionProject.Project.GetType()); bool perfectMatch = includedProject != null && solutionProject.Configurations.Contains(includedProject.Configuration); if (!perfectMatch) { continue; } var conf = includedProject.Configuration; if (!conf.IsFastBuildEnabledProjectConfig()) { continue; } mustGenerateFastbuild = true; IPlatformBff platformBff = platformBffCache.GetValueOrAdd(conf.Platform, PlatformRegistry.Query <IPlatformBff>(conf.Platform)); platformBff.AddCompilerSettings(masterBffInfo.CompilerSettings, conf); if (FastBuildSettings.WriteAllConfigsSection && includedProject.ToBuild == Solution.Configuration.IncludedProjectInfo.Build.Yes) { masterBffInfo.AllConfigsSections.Add(Bff.GetShortProjectName(project, conf)); } using (fileGenerator.Declare("conf", conf)) using (fileGenerator.Declare("target", conf.Target)) using (fileGenerator.Declare("project", conf.Project)) { var preBuildEvents = new Dictionary <string, Project.Configuration.BuildStepBase>(); if (conf.Output == Project.Configuration.OutputType.Exe || conf.ExecuteTargetCopy) { var copies = ProjectOptionsGenerator.ConvertPostBuildCopiesToRelative(conf, masterBffDirectory); foreach (var copy in copies) { var sourceFile = copy.Key; var sourceFileName = Path.GetFileName(sourceFile); var destinationFolder = copy.Value; var destinationFile = Path.Combine(destinationFolder, sourceFileName); // use the global root for alias computation, as the project has not idea in which master bff it has been included var destinationRelativeToGlobal = Util.GetConvertedRelativePath(masterBffDirectory, destinationFolder, conf.Project.RootPath, true, conf.Project.RootPath); { string key = sourceFileName + destinationRelativeToGlobal; string currentSourceFullPath = Util.PathGetAbsolute(masterBffDirectory, sourceFile); string previous; if (verificationPostBuildCopies.TryGetValue(key, out previous)) { if (previous != currentSourceFullPath) { builder.LogErrorLine("A post-build copy to the destination '{0}' already exist but from different sources: '{1}' and '{2}'!", Util.PathGetAbsolute(masterBffDirectory, destinationFolder), previous, currentSourceFullPath); } } else { verificationPostBuildCopies.Add(key, currentSourceFullPath); } } string fastBuildCopyAlias = UtilityMethods.GetFastBuildCopyAlias(sourceFileName, destinationRelativeToGlobal); { using (fileGenerator.Declare("fastBuildCopyAlias", fastBuildCopyAlias)) using (fileGenerator.Declare("fastBuildCopySource", sourceFile)) using (fileGenerator.Declare("fastBuildCopyDest", destinationFile)) { if (!bffMasterSection.ContainsKey(fastBuildCopyAlias)) { bffMasterSection.Add(fastBuildCopyAlias, fileGenerator.Resolver.Resolve(Bff.Template.ConfigurationFile.CopyFileSection)); } } } } foreach (var eventPair in conf.EventPreBuildExecute) { preBuildEvents.Add(eventPair.Key, eventPair.Value); } foreach (var buildEvent in conf.ResolvedEventPreBuildExe) { string eventKey = ProjectOptionsGenerator.MakeBuildStepName(conf, buildEvent, Vcxproj.BuildStep.PreBuild); preBuildEvents.Add(eventKey, buildEvent); } WriteEvents(fileGenerator, preBuildEvents, bffPreBuildSection, masterBffDirectory); } var customPreBuildEvents = new Dictionary <string, Project.Configuration.BuildStepBase>(); foreach (var eventPair in conf.EventCustomPrebuildExecute) { customPreBuildEvents.Add(eventPair.Key, eventPair.Value); } foreach (var buildEvent in conf.ResolvedEventCustomPreBuildExe) { string eventKey = ProjectOptionsGenerator.MakeBuildStepName(conf, buildEvent, Vcxproj.BuildStep.PreBuildCustomAction); customPreBuildEvents.Add(eventKey, buildEvent); } WriteEvents(fileGenerator, customPreBuildEvents, bffCustomPreBuildSection, masterBffDirectory); if (includedProject.ToBuild == Solution.Configuration.IncludedProjectInfo.Build.Yes) { MergeBffIncludeTreeRecursive(conf, ref masterBffInfo.BffIncludeToDependencyIncludes); } } } } if (!mustGenerateFastbuild) { throw new Error("Sharpmake-FastBuild : Trying to generate a MasterBff with none of its projects having a FastBuild configuration, or having a platform supporting it, or all of them having conf.DoNotGenerateFastBuild = true"); } masterBffCopySections.AddRange(bffMasterSection.Values); masterBffCopySections.AddRange(bffPreBuildSection.Values); masterBffCustomSections.AddRange(bffCustomPreBuildSection.Values); var result = new StringBuilder(); foreach (var projectBffFullPath in GetMasterIncludeList(masterBffInfo.BffIncludeToDependencyIncludes)) { string projectFullPath = Path.GetDirectoryName(projectBffFullPath); var projectPathRelativeFromMasterBff = Util.PathGetRelative(masterBffDirectory, projectFullPath, true); string bffKeyRelative = Path.Combine(Bff.CurrentBffPathKey, Path.GetFileName(projectBffFullPath)); string include = string.Join( Environment.NewLine, "{", $" {Bff.CurrentBffPathVariable} = \"{projectPathRelativeFromMasterBff}\"", $" #include \"{bffKeyRelative}\"", "}" ); result.AppendLine(include); } string fastBuildMasterBffDependencies = result.Length == 0 ? FileGeneratorUtilities.RemoveLineTag : result.ToString(); GenerateMasterBffGlobalSettingsFile(builder, globalConfigFullPath, masterBffInfo); using (fileGenerator.Declare("fastBuildProjectName", masterBffFileName)) using (fileGenerator.Declare("fastBuildGlobalConfigurationInclude", $"#include \"{globalConfigFileName}\"")) { fileGenerator.Write(Bff.Template.ConfigurationFile.HeaderFile); foreach (Platform platform in platformBffCache.Keys) // kind of cheating to use that cache instead of the masterBffInfo.CompilerSettings, but it works :) { using (fileGenerator.Declare("fastBuildDefine", Bff.GetPlatformSpecificDefine(platform))) fileGenerator.Write(Bff.Template.ConfigurationFile.Define); } fileGenerator.Write(Bff.Template.ConfigurationFile.GlobalConfigurationInclude); } WriteMasterCopySection(fileGenerator, masterBffCopySections); WriteMasterCustomSection(fileGenerator, masterBffCustomSections); using (fileGenerator.Declare("fastBuildProjectName", masterBffFileName)) using (fileGenerator.Declare("fastBuildOrderedBffDependencies", fastBuildMasterBffDependencies)) { fileGenerator.Write(Bff.Template.ConfigurationFile.Includes); } if (masterBffInfo.AllConfigsSections.Count != 0) { using (fileGenerator.Declare("fastBuildConfigs", UtilityMethods.FBuildFormatList(masterBffInfo.AllConfigsSections, 4))) { fileGenerator.Write(Bff.Template.ConfigurationFile.AllConfigsSection); } } // remove all line that contain RemoveLineTag fileGenerator.RemoveTaggedLines(); MemoryStream bffCleanMemoryStream = fileGenerator.ToMemoryStream(); // Write master .bff file FileInfo bffFileInfo = new FileInfo(masterBffFilePath); bool updated = builder.Context.WriteGeneratedFile(null, bffFileInfo, bffCleanMemoryStream); foreach (var confsPerSolution in configurationsPerBff) { confsPerSolution.Solution.PostGenerationCallback?.Invoke(masterBffDirectory, Path.GetFileNameWithoutExtension(masterBffFileName), FastBuildSettings.FastBuildConfigFileExtension); } return(updated); }
private string Generate( Solution solution, List <Solution.Configuration> solutionConfigurations, string solutionPath, string solutionFile, out bool updated ) { // reset current solution state _rootSolutionFolders.Clear(); _solutionFolders.Clear(); FileInfo solutionFileInfo = new FileInfo(Util.GetCapitalizedPath(solutionPath + Path.DirectorySeparatorChar + solutionFile + SolutionExtension)); string solutionGuid = Util.BuildGuid(solutionFileInfo.FullName, solution.SharpmakeCsPath); DevEnv devEnv = solutionConfigurations[0].Target.GetFragment <DevEnv>(); List <Solution.ResolvedProject> solutionProjects = ResolveSolutionProjects(solution, solutionConfigurations); if (solutionProjects.Count == 0) { updated = solutionFileInfo.Exists; if (updated) { Util.TryDeleteFile(solutionFileInfo.FullName); } return(solutionFileInfo.FullName); } List <Solution.ResolvedProject> resolvedPathReferences = ResolveReferencesByPath(solutionProjects, solutionConfigurations[0].ProjectReferencesByPath); var guidlist = solutionProjects.Select(p => p.UserData["Guid"]); resolvedPathReferences = resolvedPathReferences.Where(r => !guidlist.Contains(r.UserData["Guid"])).ToList(); var fileGenerator = new FileGenerator(); // write solution header switch (devEnv) { case DevEnv.vs2010: fileGenerator.Write(Template.Solution.HeaderBeginVs2010); break; case DevEnv.vs2012: fileGenerator.Write(Template.Solution.HeaderBeginVs2012); break; case DevEnv.vs2013: fileGenerator.Write(Template.Solution.HeaderBeginVs2013); break; case DevEnv.vs2015: fileGenerator.Write(Template.Solution.HeaderBeginVs2015); break; case DevEnv.vs2017: fileGenerator.Write(Template.Solution.HeaderBeginVs2017); break; default: Console.WriteLine("Unsupported DevEnv for solution " + solutionConfigurations[0].Target.GetFragment <DevEnv>()); break; } // Write all needed folders before the projects to make sure the proper startup project is selected. _solutionFolders.Sort((a, b) => string.Compare(a.Name, b.Name, StringComparison.InvariantCultureIgnoreCase)); // Ensure folders are always in the same order to avoid random shuffles foreach (SolutionFolder folder in _solutionFolders) { using (fileGenerator.Declare("folderName", folder.Name)) using (fileGenerator.Declare("folderGuid", folder.Guid.ToString().ToUpper())) { fileGenerator.Write(Template.Solution.ProjectFolder); } } using (fileGenerator.Declare("solution", solution)) using (fileGenerator.Declare("solutionGuid", solutionGuid)) { foreach (Solution.ResolvedProject resolvedProject in solutionProjects.Concat(resolvedPathReferences)) { FileInfo projectFileInfo = new FileInfo(resolvedProject.ProjectFile); using (fileGenerator.Declare("project", resolvedProject.Project)) using (fileGenerator.Declare("projectName", resolvedProject.ProjectName)) using (fileGenerator.Declare("projectFile", Util.PathGetRelative(solutionFileInfo.Directory.FullName, projectFileInfo.FullName))) using (fileGenerator.Declare("projectGuid", resolvedProject.UserData["Guid"])) using (fileGenerator.Declare("projectTypeGuid", resolvedProject.UserData["TypeGuid"])) { fileGenerator.Write(Template.Solution.ProjectBegin); fileGenerator.Write(Template.Solution.ProjectEnd); } } } fileGenerator.Write(Template.Solution.GlobalBegin); // Write source code control informations if (solution.PerforceRootPath != null) { List <Solution.ResolvedProject> sccProjects = new List <Solution.ResolvedProject>(); foreach (Solution.ResolvedProject resolvedProject in solutionProjects) { if (resolvedProject.Project.PerforceRootPath != null) { sccProjects.Add(resolvedProject); } else { _builder.LogWriteLine(@"warning: cannot bind solution {0} to perforce, PerforceRootPath for project '{1}' is not set.", solutionFileInfo.Name, resolvedProject.Project.ClassName); } } if (sccProjects.Count == solutionProjects.Count) { using (fileGenerator.Declare("sccNumberOfProjects", sccProjects.Count)) { fileGenerator.Write(Template.Solution.GlobalSectionSolutionSourceCodeControlBegin); } for (int i = 0; i < sccProjects.Count; ++i) { Solution.ResolvedProject resolvedProject = sccProjects[i]; FileInfo projectFileInfo = new FileInfo(resolvedProject.ProjectFile); //SccProjectUniqueName7 = ..\\..\\extern\\techgroup\\framework\\gear\\private\\compilers\\win32\\vc9\\gear_win32_compile.vcproj string sccProjectUniqueName = Util.PathGetRelative(solutionFileInfo.Directory.FullName, projectFileInfo.FullName).Replace("\\", "\\\\"); //SccProjectTopLevelParentUniqueName7 = guildlib.sln string sccProjectTopLevelParentUniqueName = solutionFileInfo.Name; // sln to perforce file //SccLocalPath7 = ..\\..\\extern\\techgroup\\framework\\gear string sccLocalPath = Util.PathGetRelative(solutionPath, resolvedProject.Project.PerforceRootPath).Replace("\\", "\\\\"); //SccProjectFilePathRelativizedFromConnection7 = private\\compilers\\win32\\vc9\\ string sccProjectFilePathRelativizedFromConnection = Util.PathGetRelative(resolvedProject.Project.PerforceRootPath, projectFileInfo.DirectoryName).Trim('.', '\\').Replace("\\", "\\\\"); using (fileGenerator.Declare("i", i)) using (fileGenerator.Declare("sccProjectUniqueName", sccProjectUniqueName)) using (fileGenerator.Declare("sccProjectTopLevelParentUniqueName", sccProjectTopLevelParentUniqueName)) using (fileGenerator.Declare("sccLocalPath", sccLocalPath)) using (fileGenerator.Declare("sccProjectFilePathRelativizedFromConnection", sccProjectFilePathRelativizedFromConnection)) { fileGenerator.Write(Template.Solution.GlobalSectionSolutionSourceCodeControlProject); } } fileGenerator.Write(Template.Solution.GlobalSectionSolutionSourceCodeControlEnd); } } // write solution configurations string visualStudioExe = GetVisualStudioIdePath(devEnv) + Util.WindowsSeparator + "devenv.com"; List <string> configurationSectionNames = new List <string>(); fileGenerator.Write(Template.Solution.GlobalSectionSolutionConfigurationBegin); foreach (Solution.Configuration solutionConfiguration in solutionConfigurations) { string configurationName; string category; if (solution.MergePlatformConfiguration) { configurationName = solutionConfiguration.PlatformName + "-" + solutionConfiguration.Name; category = "All Platforms"; } else { configurationName = solutionConfiguration.Name; category = solutionConfiguration.PlatformName; } using (fileGenerator.Declare("configurationName", configurationName)) using (fileGenerator.Declare("category", category)) { configurationSectionNames.Add(fileGenerator.Resolver.Resolve(Template.Solution.GlobalSectionSolutionConfiguration)); } // set the compile command line if (File.Exists(visualStudioExe)) { solutionConfiguration.CompileCommandLine = string.Format(@"""{0}"" ""{1}"" /build ""{2}|{3}""", visualStudioExe, solutionFileInfo.FullName, configurationName, category); } } configurationSectionNames.Sort(); foreach (string configurationSectionName in configurationSectionNames) { fileGenerator.Write(configurationSectionName); } fileGenerator.Write(Template.Solution.GlobalSectionSolutionConfigurationEnd); // write all project target and match then to a solution target fileGenerator.Write(Template.Solution.GlobalSectionProjectConfigurationBegin); var pec = new Dictionary <Solution.Configuration, int>(); foreach (Solution.ResolvedProject solutionProject in solutionProjects) { foreach (Solution.Configuration solutionConfiguration in solutionConfigurations) { ITarget solutionTarget = solutionConfiguration.Target; ITarget projectTarget = null; Solution.Configuration.IncludedProjectInfo includedProject = solutionConfiguration.GetProject(solutionProject.Project.GetType()); bool perfectMatch = includedProject != null && solutionProject.Configurations.Contains(includedProject.Configuration); if (perfectMatch) { projectTarget = includedProject.Target; } else { // try to find the target in the project that is the closest match from the solution one int maxEqualFragments = 0; int[] solutionTargetValues = solutionTarget.GetFragmentsValue(); foreach (var conf in solutionProject.Configurations) { int[] candidateTargetValues = conf.Target.GetFragmentsValue(); if (solutionTargetValues.Length != candidateTargetValues.Length) { continue; } int equalFragments = 0; for (int i = 0; i < solutionTargetValues.Length; ++i) { if ((solutionTargetValues[i] & candidateTargetValues[i]) != 0) { equalFragments++; } } if (equalFragments > maxEqualFragments) { projectTarget = conf.Target; maxEqualFragments = equalFragments; } } // last resort: if we didn't find a good enough match, fallback to TargetDefault if (projectTarget == null) { projectTarget = solutionProject.TargetDefault; } } Project.Configuration projectConf = solutionProject.Project.GetConfiguration(projectTarget); Platform projectPlatform = projectTarget.GetPlatform(); string configurationName; string category; if (solution.MergePlatformConfiguration) { configurationName = solutionConfiguration.PlatformName + " " + solutionConfiguration.Name; category = "All Platforms"; } else { configurationName = solutionConfiguration.Name; category = solutionConfiguration.PlatformName; } using (fileGenerator.Declare("solutionConf", solutionConfiguration)) using (fileGenerator.Declare("projectGuid", solutionProject.UserData["Guid"])) using (fileGenerator.Declare("projectConf", projectConf)) using (fileGenerator.Declare("projectPlatform", Util.GetPlatformString(projectPlatform, solutionProject.Project, true))) using (fileGenerator.Declare("category", category)) using (fileGenerator.Declare("configurationName", configurationName)) { bool build = false; if (solution is PythonSolution) { // nothing is built in python solutions } else if (projectConf.IsFastBuild && !projectConf.IsMainProject) { // only one project can be built with FastBuild, the one marked with IsMainProject // TODO: deprecate IsMainProject, as the list of projects to build is known } else if (perfectMatch) { build = includedProject.ToBuild == Solution.Configuration.IncludedProjectInfo.Build.Yes; // for fastbuild, only build the projects that cannot be built through dependency chain if (!projectConf.IsFastBuild) { build |= includedProject.ToBuild == Solution.Configuration.IncludedProjectInfo.Build.YesThroughDependency; } } fileGenerator.Write(Template.Solution.GlobalSectionProjectConfigurationActive); if (build) { fileGenerator.Write(Template.Solution.GlobalSectionProjectConfigurationBuild); bool deployProject = includedProject.Project.DeployProject || includedProject.Configuration.DeployProject; if (deployProject) { fileGenerator.Write(Template.Solution.GlobalSectionProjectConfigurationDeploy); } } } } } fileGenerator.Write(Template.Solution.GlobalSectionProjectConfigurationEnd); fileGenerator.Write(Template.Solution.SolutionProperties); // Write nested folders if (_solutionFolders.Count != 0) { fileGenerator.Write(Template.Solution.NestedProjectBegin); foreach (SolutionFolder folder in _solutionFolders) { if (folder.Parent != null) { using (fileGenerator.Declare("nestedChildGuid", folder.Guid.ToString().ToUpper())) using (fileGenerator.Declare("nestedParentGuid", folder.Parent.Guid.ToString().ToUpper())) { fileGenerator.Write(Template.Solution.NestedProjectItem); } } } foreach (Solution.ResolvedProject resolvedProject in solutionProjects.Concat(resolvedPathReferences)) { SolutionFolder folder = resolvedProject.UserData["Folder"] as SolutionFolder; if (folder != null) { using (fileGenerator.Declare("nestedChildGuid", resolvedProject.UserData["Guid"].ToString().ToUpper())) using (fileGenerator.Declare("nestedParentGuid", folder.Guid.ToString().ToUpper())) { fileGenerator.Write(Template.Solution.NestedProjectItem); } } } fileGenerator.Write(Template.Solution.NestedProjectEnd); } fileGenerator.Write(Template.Solution.GlobalEnd); // Write the solution file updated = _builder.Context.WriteGeneratedFile(solution.GetType(), solutionFileInfo, fileGenerator.ToMemoryStream()); solution.PostGenerationCallback?.Invoke(solutionPath, solutionFile, SolutionExtension); return(solutionFileInfo.FullName); }