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);
}
}