private void MakeFastBuildAllProjectIfNeeded()

in Sharpmake/Solution.cs [510:666]


        private void MakeFastBuildAllProjectIfNeeded(Builder builder, Dictionary<Solution.Configuration, List<Project.Configuration>> unlinkedConfigurations)
        {
            if (!GenerateFastBuildAllProject)
            {
                return;
            }

            foreach (var solutionFile in SolutionFilesMapping)
            {
                var solutionConfigurations = solutionFile.Value;

                bool generateFastBuildAll = false;
                var projectsToBuildPerSolutionConfig = new List<Tuple<Solution.Configuration, List<Solution.Configuration.IncludedProjectInfo>>>();
                foreach (var solutionConfiguration in solutionConfigurations)
                {
                    var configProjects = solutionConfiguration.IncludedProjectInfos;

                    var fastBuildProjectConfsToBuild = configProjects.Where(
                        configProject => (
                            configProject.Configuration.IsFastBuild &&
                            configProject.ToBuild == Solution.Configuration.IncludedProjectInfo.Build.Yes
                        )
                    ).ToList();

                    if (fastBuildProjectConfsToBuild.Count == 0)
                        continue;

                    // if there's only one project to build, no need for the FastBuildAll
                    generateFastBuildAll |= ForceGenerateFastBuildAll || fastBuildProjectConfsToBuild.Count > 1;
                    projectsToBuildPerSolutionConfig.Add(Tuple.Create(solutionConfiguration, fastBuildProjectConfsToBuild));
                }

                if (!generateFastBuildAll)
                    continue;

                builder.LogWriteLine("    extra FastBuildAll project '" + FastBuildAllProjectName + "' added to solution " + Path.GetFileName(solutionFile.Key));

                // Use the target type from the first solution configuration, as they all should have the same anyway
                var firstSolutionConf = projectsToBuildPerSolutionConfig.First().Item1;

                Project fastBuildAllProject = null;
                foreach (var projectsToBuildInSolutionConfig in projectsToBuildPerSolutionConfig)
                {
                    var solutionConf = projectsToBuildInSolutionConfig.Item1;
                    var projectConfigsToBuild = projectsToBuildInSolutionConfig.Item2;

                    if (!ForceGenerateFastBuildAll && GenerateFastBuildAllOnlyForConfThatNeedIt && projectConfigsToBuild.Count == 1)
                        continue;

                    var solutionTarget = solutionConf.Target;
                    if (fastBuildAllProject == null)
                    {
                        var firstProject = projectConfigsToBuild.First();

                        // Use the target type from the current solution configuration, as they all should have the same anyway
                        fastBuildAllProject = new FastBuildAllProject(solutionConf.Target.GetType())
                        {
                            Name = FastBuildAllProjectName,
                            RootPath = firstProject.Project.RootPath,
                            SourceRootPath = firstProject.Project.RootPath,
                            IsFileNameToLower = firstProject.Project.IsFileNameToLower,
                            SharpmakeProjectType = Project.ProjectTypeAttribute.Generate
                        };
                    }
                    else
                    {
                        // validate the assumption made above
                        if (fastBuildAllProject.Targets.TargetType != firstSolutionConf.Target.GetType())
                            throw new Error("Target type must match between all solution configurations");
                    }

                    fastBuildAllProject.AddTargets(solutionTarget);
                }

                fastBuildAllProject.Targets.BuildTargets();
                fastBuildAllProject.InvokeConfiguration(builder.Context);

                // we need to iterate again after invoking the configure of all the projects so we can tweak their conf
                foreach (var projectsToBuildInSolutionConfig in projectsToBuildPerSolutionConfig)
                {
                    var solutionConf = projectsToBuildInSolutionConfig.Item1;
                    var projectConfigsToBuild = projectsToBuildInSolutionConfig.Item2;

                    if (!ForceGenerateFastBuildAll && GenerateFastBuildAllOnlyForConfThatNeedIt && projectConfigsToBuild.Count == 1)
                        continue;

                    var solutionTarget = solutionConf.Target;
                    var projectConf = fastBuildAllProject.GetConfiguration(solutionTarget);

                    // Re-link projects to the new All project
                    // TODO: We should do something to detect and avoid any circular references that this project can now theoretically create.
                    List<Project.Configuration> projectConfigsToRelink;
                    if (unlinkedConfigurations.TryGetValue(solutionConf, out projectConfigsToRelink))
                    {
                        foreach (Project.Configuration config in projectConfigsToRelink.Distinct())
                        {
                            ProjectsDependingOnFastBuildAllForThisSolution.Add(config.Project);
                        }
                    }

                    projectConf.IsFastBuild = true;

                    projectConf.AddMasterBff(solutionConf.MasterBffFilePath);

                    // output the project in the same folder as the solution, and the same name
                    projectConf.ProjectPath = solutionConf.SolutionPath;
                    if (string.IsNullOrWhiteSpace(FastBuildAllProjectFileSuffix))
                        throw new Error("FastBuildAllProjectFileSuffix cannot be left empty in solution " + solutionFile);
                    projectConf.ProjectFileName = solutionFile.Key + FastBuildAllProjectFileSuffix;
                    projectConf.SolutionFolder = FastBuildAllSolutionFolder;

                    // the project doesn't output anything
                    projectConf.Output = Project.Configuration.OutputType.None;

                    // get some settings that are usually global from the first project
                    // we could expose those, if we need to set them specifically for FastBuildAllProject
                    var firstProject = projectConfigsToBuild.First();
                    projectConf.FastBuildCacheAllowed = firstProject.Configuration.FastBuildCacheAllowed;
                    projectConf.FastBuildCustomArgs = firstProject.Configuration.FastBuildCustomArgs;
                    projectConf.FastBuildCustomActionsBeforeBuildCommand = firstProject.Configuration.FastBuildCustomActionsBeforeBuildCommand;
                    projectConf.FastBuildDistribution = firstProject.Configuration.FastBuildDistribution;
                    projectConf.WriteVcOverrides = firstProject.Configuration.WriteVcOverrides;
                    projectConf.Options.AddRange(firstProject.Configuration.Options);

                    // add all the projects to build as private dependencies, and OnlyBuildOrder
                    foreach (Configuration.IncludedProjectInfo projectConfigToBuild in projectConfigsToBuild)
                    {
                        // update the ToBuild, as now it is built through the "FastBuildAll" dependency
                        projectConfigToBuild.ToBuild = Configuration.IncludedProjectInfo.Build.YesThroughDependency;

                        // Relink any build-order dependencies
                        projectConf.GenericBuildDependencies.AddRange(projectConfigToBuild.Configuration.GenericBuildDependencies);
                        projectConf.GenericBuildDependencies.AddRange(projectConfigToBuild.Configuration.DotNetPublicDependencies.Select(d => d.Configuration).Where(c => !c.IsFastBuild));
                        projectConf.GenericBuildDependencies.AddRange(projectConfigToBuild.Configuration.DotNetPrivateDependencies.Select(d => d.Configuration).Where(c => !c.IsFastBuild));

                        projectConf.AddPrivateDependency(projectConfigToBuild.Target, projectConfigToBuild.Project.GetType(), DependencySetting.OnlyBuildOrder);
                    }

                    // add the newly generated project to the solution config
                    solutionConf.IncludedProjectInfos.Add(
                        new Configuration.IncludedProjectInfo
                        {
                            Project = fastBuildAllProject,
                            Configuration = projectConf,
                            Target = solutionTarget,
                            Type = fastBuildAllProject.GetType(),
                            ToBuild = Configuration.IncludedProjectInfo.Build.Yes
                        }
                    );
                }

                fastBuildAllProject.Resolve(builder, false);
                fastBuildAllProject.Link(builder);

                builder.RegisterGeneratedProject(fastBuildAllProject);
            }
        }