Пример #1
0
        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);
        }
Пример #2
0
            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);
            }
Пример #3
0
        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);
        }
Пример #4
0
        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);
        }
Пример #5
0
        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);
        }