private void ConfigureUnities()

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