in Sharpmake.Generators/FastBuild/Bff.cs [2165:2329]
private void ConfigureUnities(IGenerationContext context, Dictionary<Project.Configuration, Dictionary<SubConfig, List<Vcxproj.ProjectFile>>> confSourceFiles)
{
var conf = context.Configuration;
// Only add unity build to non blobbed projects -> which they will be blobbed by FBuild
if (!conf.FastBuildBlobbed)
return;
if (!confSourceFiles.ContainsKey(conf)) // no source files, so no unity section
return;
var confSubConfigs = confSourceFiles[conf];
var unitySubConfig = s_DefaultSubConfig;
var sourceFiles = confSubConfigs[unitySubConfig];
var project = context.Project;
const int spaceLength = 42;
string fastBuildUnityInputFiles = FileGeneratorUtilities.RemoveLineTag;
string fastBuildUnityInputExcludedfiles = FileGeneratorUtilities.RemoveLineTag;
string fastBuildUnityPaths = FileGeneratorUtilities.RemoveLineTag;
string fastBuildUnityInputPattern = FileGeneratorUtilities.RemoveLineTag;
string fastBuildUnityInputExcludePath = FileGeneratorUtilities.RemoveLineTag;
string fastBuildUnityCount = FileGeneratorUtilities.RemoveLineTag;
int unityCount = conf.FastBuildUnityCount > 0 ? conf.FastBuildUnityCount : conf.GeneratableBlobCount;
if (unityCount > 0)
fastBuildUnityCount = unityCount.ToString(CultureInfo.InvariantCulture);
var fastbuildUnityInputExcludePathList = new Strings(project.SourcePathsBlobExclude.Select(Util.GetCapitalizedPath));
string fastBuildUnityInputIsolateListFile = FileGeneratorUtilities.RemoveLineTag;
bool srcDirsAreEmpty = true;
var items = new List<string>();
// Fastbuild will process as unity all files contained in source Root folder and all additional roots.
var unityInputPaths = new Strings(context.ProjectSourceCapitalized);
unityInputPaths.AddRange(project.AdditionalSourceRootPaths.Select(Util.GetCapitalizedPath));
foreach (var file in sourceFiles)
{
bool isBlobbed = project.SourceFilesBlobExtensions.Contains(file.FileExtension);
if (isBlobbed &&
(conf.PrecompSource == null || !file.FileName.EndsWith(conf.PrecompSource, StringComparison.OrdinalIgnoreCase)) &&
!conf.ResolvedSourceFilesBlobExclude.Contains(file.FileName))
{
if (conf.FastBuildBlobbingStrategy == Project.Configuration.InputFileStrategy.Include || !IsFileInInputPathList(unityInputPaths, file.FileName))
{
string sourceFileRelative = CurrentBffPathKeyCombine(Util.PathGetRelative(context.ProjectDirectoryCapitalized, file.FileName));
items.Add(sourceFileRelative);
}
srcDirsAreEmpty = false;
}
}
// Conditional statement depending on the blobbing strategy
if (items.Count == 0 && srcDirsAreEmpty)
{
fastBuildUnityInputFiles = FileGeneratorUtilities.RemoveLineTag;
}
else if (conf.FastBuildBlobbingStrategy == Project.Configuration.InputFileStrategy.Include)
{
fastBuildUnityInputFiles = UtilityMethods.FBuildFormatList(items, spaceLength);
}
else
{
fastBuildUnityInputFiles = UtilityMethods.FBuildFormatList(items, spaceLength);
// check if there's some static blobs lying around to exclude
if (IsFileInInputPathList(unityInputPaths, conf.BlobPath))
fastbuildUnityInputExcludePathList.Add(conf.BlobPath);
// Remove any excluded paths(exclusion has priority)
unityInputPaths.RemoveRange(fastbuildUnityInputExcludePathList);
var unityInputRelativePaths = new Strings(unityInputPaths.Select(
p =>
{
if (ShouldMakePathRelative(p, context.Project))
return CurrentBffPathKeyCombine(Util.PathGetRelative(context.ProjectDirectoryCapitalized, p, true));
return p;
}
));
fastBuildUnityPaths = UtilityMethods.FBuildCollectionFormat(unityInputRelativePaths, spaceLength);
var excludedSourceFiles = new Strings(conf.ResolvedSourceFilesBlobExclude);
excludedSourceFiles.AddRange(conf.ResolvedSourceFilesBuildExclude);
excludedSourceFiles.AddRange(conf.PrecompSourceExclude);
var excludedSourceFilesRelative = new Strings();
// Converting the excluded filenames to relative path to the input path so that this
// can work properly with subst usage when running with fastbuild caching active.
//
// Also exclusion checks in fastbuild assume that the exclusion filenames are
// relative to the .UnityInputPath and checks that paths are ending with the specified
// path which means that any filename starting with a .. will never be excluded by fastbuild.
//
// Note: Ideally fastbuild should expect relative paths to the bff file path instead of the .UnityInputPath but
// well I guess we are stuck with this.
foreach (string file in excludedSourceFiles.SortedValues)
{
if (IsFileInInputPathList(unityInputPaths, file))
excludedSourceFilesRelative.Add(CurrentBffPathKeyCombine(Util.PathGetRelative(context.ProjectDirectoryCapitalized, file, true)));
}
if (excludedSourceFilesRelative.Count > 0)
fastBuildUnityInputExcludedfiles = UtilityMethods.FBuildCollectionFormat(excludedSourceFilesRelative, spaceLength, project.SourceFilesBlobExtensions);
}
if (fastBuildUnityInputFiles == FileGeneratorUtilities.RemoveLineTag &&
fastBuildUnityPaths == FileGeneratorUtilities.RemoveLineTag)
{
// completely drop the subconfig in case it was only a unity subConfig, without any files
if (sourceFiles.Count == 0)
confSubConfigs.Remove(unitySubConfig);
// no input path nor files => no unity
return;
}
if (fastbuildUnityInputExcludePathList.Any())
{
var unityInputExcludePathRelative = new Strings(fastbuildUnityInputExcludePathList.Select(p => CurrentBffPathKeyCombine(Util.PathGetRelative(context.ProjectDirectoryCapitalized, p, true))));
fastBuildUnityInputExcludePath = UtilityMethods.FBuildCollectionFormat(unityInputExcludePathRelative, spaceLength);
}
// only write UnityInputPattern if it's not FastBuild's default value of .cpp
if (project.SourceFilesBlobExtensions.Count != 1 || !project.SourceFilesBlobExtensions.Contains(Unity.DefaultUnityInputPatternExtension))
{
var inputPatterns = new Strings(project.SourceFilesBlobExtensions);
inputPatterns.InsertPrefix("*");
fastBuildUnityInputPattern = UtilityMethods.FBuildCollectionFormat(inputPatterns, spaceLength);
}
if (!string.IsNullOrEmpty(conf.FastBuildUnityInputIsolateListFile))
fastBuildUnityInputIsolateListFile = CurrentBffPathKeyCombine(Util.PathGetRelative(context.ProjectDirectoryCapitalized, conf.FastBuildUnityInputIsolateListFile, true));
Unity unityFile = new Unity
{
// Note that the UnityName and UnityOutputPattern are intentionally left empty: they will be set in the Resolve
UnityOutputPath = CurrentBffPathKeyCombine(Util.PathGetRelative(context.ProjectDirectoryCapitalized, conf.FastBuildUnityPath, true)),
UnityFullOutputPath = Path.Combine(context.ProjectDirectoryCapitalized, conf.FastBuildUnityPath),
UnityInputIsolateWritableFiles = conf.FastBuildUnityInputIsolateWritableFiles.ToString().ToLower(),
UnityInputIsolateWritableFilesLimit = conf.FastBuildUnityInputIsolateWritableFiles ? conf.FastBuildUnityInputIsolateWritableFilesLimit.ToString() : FileGeneratorUtilities.RemoveLineTag,
UnityInputIsolateListFile = fastBuildUnityInputIsolateListFile,
UnityPCH = conf.PrecompHeader ?? FileGeneratorUtilities.RemoveLineTag,
UnityInputExcludePath = fastBuildUnityInputExcludePath,
UnityNumFiles = fastBuildUnityCount,
UnityInputPath = fastBuildUnityPaths,
UnityInputFiles = fastBuildUnityInputFiles,
UnityInputExcludedFiles = fastBuildUnityInputExcludedfiles,
UnityInputPattern = fastBuildUnityInputPattern,
UseRelativePaths = conf.FastBuildUnityUseRelativePaths ? "true" : FileGeneratorUtilities.RemoveLineTag,
UnitySectionBucket = conf.FastBuildUnitySectionBucket,
};
// _unities being a dictionary, a new entry will be created only
// if the combination of options forming that unity was never seen before
var confListForUnity = _unities.GetValueOrAdd(unityFile, new List<Project.Configuration>());
// add the current conf in the list that this unity serves
confListForUnity.Add(conf);
}