in Sharpmake.Generators/FastBuild/Bff.cs [208:1552]
public void Generate(
Builder builder,
Project project,
List<Project.Configuration> configurations,
string projectFile,
List<string> generatedFiles,
List<string> skipFiles
)
{
if (!FastBuildSettings.FastBuildSupportEnabled)
return;
//To make sure that all the projects are fastbuild
configurations = configurations.Where(x => x.IsFastBuild && !x.DoNotGenerateFastBuild).OrderBy(x => x.Platform).ToList();
if (!configurations.Any())
return;
Project.Configuration firstConf = configurations.First();
string projectName = firstConf.ProjectName;
string projectPath = new FileInfo(projectFile).Directory.FullName;
var context = new BffGenerationContext(builder, project, projectPath, configurations);
string projectBffFile = Bff.GetBffFileName(projectPath, firstConf.BffFileName); // TODO: bff file name could be different per conf, hence we would generate more than one file
List<Vcxproj.ProjectFile> filesInNonDefaultSection;
Dictionary<Project.Configuration, Dictionary<SubConfig, List<Vcxproj.ProjectFile>>> confSourceFiles;
using (builder.CreateProfilingScope("BffGenerator.Generate:GetGeneratedFiles"))
{
confSourceFiles = GetGeneratedFiles(context, configurations, out filesInNonDefaultSection);
}
// Generate all configuration options onces...
var options = new Dictionary<Project.Configuration, Options.ExplicitOptions>();
var cmdLineOptions = new Dictionary<Project.Configuration, ProjectOptionsGenerator.VcxprojCmdLineOptions>();
var dependenciesInfoPerConf = new Dictionary<Project.Configuration, DependenciesInfo>();
ProjectOptionsGenerator projectOptionsGen;
using (builder.CreateProfilingScope("BffGenerator.Generate:ProjectOptionsGenerator()"))
{
projectOptionsGen = new ProjectOptionsGenerator();
}
using (builder.CreateProfilingScope("BffGenerator.Generate:confs1"))
{
foreach (Project.Configuration conf in configurations)
{
context.Options = new Options.ExplicitOptions();
context.CommandLineOptions = new ProjectOptionsGenerator.VcxprojCmdLineOptions();
context.Configuration = conf;
GenerateBffOptions(projectOptionsGen, context, dependenciesInfoPerConf);
options.Add(conf, context.Options);
cmdLineOptions.Add(conf, (ProjectOptionsGenerator.VcxprojCmdLineOptions)context.CommandLineOptions);
// Validation of unsupported cases
if (conf.EventPreLink.Count > 0)
throw new Error("Sharpmake-FastBuild : Pre-Link Events not yet supported.");
if (context.Options["IgnoreImportLibrary"] == "true" && conf.ExportDllSymbols)
throw new Error("Sharpmake-FastBuild : IgnoreImportLibrary not yet supported, set ExportDllSymbols to false for similar behavior.");
if (conf.Output != Project.Configuration.OutputType.None && conf.FastBuildBlobbed)
{
ConfigureUnities(context, confSourceFiles);
}
}
}
ResolveUnities(project, projectPath);
// Start writing Bff
Resolver resolver = new Resolver();
var bffGenerator = new FileGenerator(resolver);
var bffGeneratorProject = new FileGenerator(resolver);
var bffWholeFileGenerator = new FileGenerator(resolver);
using (bffWholeFileGenerator.Declare("fastBuildProjectName", projectName))
{
bffWholeFileGenerator.Write(Template.ConfigurationFile.HeaderFile);
}
int configIndex = 0;
var allFileCustomBuild = new Dictionary<string, Project.Configuration.CustomFileBuildStepData>();
Dictionary<string, bool> confBffHasMasters = new Dictionary<string, bool>();
var configurationsToBuild = confSourceFiles.Keys.OrderBy(x => x.Platform).ToList();
foreach (Project.Configuration conf in configurationsToBuild)
{
if (!conf.Platform.IsSupportedFastBuildPlatform())
continue;
var platformBff = PlatformRegistry.Get<IPlatformBff>(conf.Platform);
var clangPlatformBff = PlatformRegistry.Query<IClangPlatformBff>(conf.Platform);
var applePlatformBff = PlatformRegistry.Query<IApplePlatformBff>(conf.Platform);
var microsoftPlatformBff = PlatformRegistry.Query<IMicrosoftPlatformBff>(conf.Platform);
var dotNetConf = Util.IsDotNet(conf);
if (conf.FastBuildMasterBffList.Any())
confBffHasMasters[conf.BffFullFileName] = true;
else
confBffHasMasters.TryAdd(conf.BffFullFileName, false);
// TODO: really not ideal, refactor and move the properties we need from it someplace else
var vcxprojPlatform = PlatformRegistry.Query<IPlatformVcxproj>(conf.Platform);
using (resolver.NewScopedParameter("conf", conf))
{
if (conf.IsBlobbed && conf.FastBuildBlobbed)
{
throw new Error("Sharpmake-FastBuild: Configuration " + conf + " is configured for blobbing by fastbuild and sharpmake. This is illegal.");
}
var confSubConfigs = confSourceFiles[conf];
ProjectOptionsGenerator.VcxprojCmdLineOptions confCmdLineOptions = cmdLineOptions[conf];
// We will need as many "sub"-libraries as subConfigs to generate the final library
int subConfigIndex = 0;
Strings subConfigObjectList = new Strings();
bool isUnity = false;
if (configIndex == 0 || configurationsToBuild[configIndex - 1].Platform != conf.Platform)
{
using (bffGenerator.Declare("fastBuildDefine", GetPlatformSpecificDefine(conf.Platform)))
bffGenerator.Write(Template.ConfigurationFile.PlatformBeginSection);
}
List<string> resourceFilesSections = new List<string>();
List<string> embeddedResourceFilesSections = new List<string>();
List<string> additionalLibs = new List<string>();
Options.ExplicitOptions confOptions = options[conf];
bool confUseLibraryDependencyInputs = Options.GetObject<Options.Vc.Linker.UseLibraryDependencyInputs>(conf) == Options.Vc.Linker.UseLibraryDependencyInputs.Enable;
string outputFile = confOptions["OutputFile"];
bool isOutputTypeExe = conf.Output == Project.Configuration.OutputType.Exe;
bool isOutputTypeAppleApp = conf.Output == Project.Configuration.OutputType.AppleApp;
bool isOutputTypeDll = conf.Output == Project.Configuration.OutputType.Dll;
bool isOutputTypeLib = conf.Output == Project.Configuration.OutputType.Lib;
bool isOutputTypeExeOrDllOrAppleApp = isOutputTypeExe || isOutputTypeDll || isOutputTypeAppleApp;
var dependenciesInfo = dependenciesInfoPerConf[conf];
OrderableStrings additionalDependencies = dependenciesInfo.AdditionalDependencies;
foreach (var subConfig in confSubConfigs.Keys)
{
var scopedOptions = new List<Options.ScopedOption>();
bool isDefaultSubConfig = s_DefaultSubConfig.Equals(subConfig);
bool isUsePrecomp = subConfig.IsUsePrecomp && conf.PrecompSource != null;
bool isCompileAsCFile = subConfig.Languages.HasFlag(Languages.C);
bool isCompileAsCPPFile = subConfig.Languages.HasFlag(Languages.CPP);
bool isCompileAsObjCFile = subConfig.Languages.HasFlag(Languages.ObjC);
bool isCompileAsObjCPPFile = subConfig.Languages.HasFlag(Languages.ObjCPP);
bool isCompileAsSwiftFile = subConfig.Languages.HasFlag(Languages.Swift);
bool isASMFileSection = subConfig.Languages.HasFlag(Languages.Asm);
bool isNASMFileSection = subConfig.Languages.HasFlag(Languages.Nasm);
bool isCompileAsCLRFile = subConfig.LanguageFeatures.HasFlag(LanguageFeatures.CLR);
bool isCompileAsNonCLRFile = subConfig.LanguageFeatures.HasFlag(LanguageFeatures.NonCLR);
bool isConsumeWinRTExtensions = subConfig.LanguageFeatures.HasFlag(LanguageFeatures.ConsumeWinRTExtensions) || (Options.GetObject<Options.Vc.Compiler.CompileAsWinRT>(conf) == Options.Vc.Compiler.CompileAsWinRT.Enable);
Options.Vc.Compiler.Exceptions exceptionsSetting = subConfig.Exceptions;
bool isFirstSubConfig = subConfigIndex == 0;
bool isLastSubConfig = subConfigIndex == confSubConfigs.Keys.Count - 1;
if (isConsumeWinRTExtensions)
{
if (isCompileAsCFile)
throw new Error("A C file cannot be marked to consume WinRT.");
isCompileAsCFile = false;
}
// For now, this will do.
if (conf.FastBuildBlobbed && isDefaultSubConfig && !isUnity)
{
isUnity = true;
}
else
{
isUnity = false;
}
var useClr = dotNetConf && !isCompileAsNonCLRFile || isCompileAsCLRFile;
var fastBuildSubConfigClrSupport = useClr ? "/clr" : FileGeneratorUtilities.RemoveLineTag;
Trace.Assert(!isCompileAsCLRFile || !isCompileAsNonCLRFile, "Sharpmake-FastBuild : a file cannot be simultaneously compiled with and without the CLR");
Strings fastBuildCompilerInputPatternList = isCompileAsCFile ? new Strings { ".c" } : project.SourceFilesCPPExtensions;
Strings fastBuildCompilerInputPatternTransformedList = new Strings(fastBuildCompilerInputPatternList.Select((s) => { return "*" + s; }));
string fastBuildCompilerInputPattern = UtilityMethods.FBuildCollectionFormat(fastBuildCompilerInputPatternTransformedList, 32);
string fastBuildPrecompiledSourceFile = FileGeneratorUtilities.RemoveLineTag;
string fastBuildCompileAsC = FileGeneratorUtilities.RemoveLineTag;
string fastBuildUnityName = isUnity ? GetUnityName(conf) : null;
switch (exceptionsSetting)
{
case Options.Vc.Compiler.Exceptions.Enable:
scopedOptions.Add(new Options.ScopedOption(confCmdLineOptions, "ExceptionHandling", "/EHsc"));
break;
case Options.Vc.Compiler.Exceptions.EnableWithExternC:
scopedOptions.Add(new Options.ScopedOption(confCmdLineOptions, "ExceptionHandling", "/EHs"));
break;
case Options.Vc.Compiler.Exceptions.EnableWithSEH:
scopedOptions.Add(new Options.ScopedOption(confCmdLineOptions, "ExceptionHandling", "/EHa"));
break;
}
bool isNoBlobImplicitConfig = false;
if (conf.FastBuildNoBlobStrategy == Project.Configuration.InputFileStrategy.Exclude &&
conf.IsBlobbed == false &&
conf.FastBuildBlobbed == false
)
{
if (isCompileAsCPPFile == false && isCompileAsCFile == false && !isConsumeWinRTExtensions)
{
isNoBlobImplicitConfig = true;
}
}
string fastBuildOutputFile = CurrentBffPathKeyCombine(Util.PathGetRelative(projectPath, outputFile, true));
fastBuildOutputFile = platformBff.GetOutputFilename(conf.Output, fastBuildOutputFile);
bool useObjectLists = confUseLibraryDependencyInputs;
string fastBuildOutputFileShortName = GetShortProjectName(project, conf);
var fastBuildProjectDependencies = new Strings();
var fastBuildBuildOnlyDependencies = new Strings();
var fastBuildProjectExeUtilityDependencyList = new Strings();
var fastBuildTargetSubTargets = new Strings();
bool mustGenerateLibrary = confSubConfigs.Count > 1 && !useObjectLists && isLastSubConfig && isOutputTypeLib;
if (!useObjectLists && confSubConfigs.Count > 1 && !isLastSubConfig)
{
useObjectLists = true;
}
if (isOutputTypeExeOrDllOrAppleApp)
{
var orderedProjectDeps = UtilityMethods.GetOrderedFlattenedProjectDependencies(conf, false);
foreach (var depProjConfig in orderedProjectDeps)
{
if (depProjConfig.Project == project)
throw new Error("Sharpmake-FastBuild : Project dependencies refers to itself.");
if (!conf.ResolvedDependencies.Contains(depProjConfig))
throw new Error("Sharpmake-FastBuild : dependency was not resolved.");
bool isExport = depProjConfig.Project.SharpmakeProjectType == Project.ProjectTypeAttribute.Export;
if (isExport)
continue;
if (depProjConfig.Output != Project.Configuration.OutputType.Exe &&
depProjConfig.Output != Project.Configuration.OutputType.AppleApp &&
depProjConfig.Output != Project.Configuration.OutputType.Utility)
{
string shortProjectName = GetShortProjectName(depProjConfig.Project, depProjConfig);
if (!dependenciesInfo.IgnoredLibraryNames.Contains(depProjConfig.TargetFileFullNameWithExtension))
fastBuildProjectDependencies.Add(shortProjectName + "_LibraryDependency");
if (depProjConfig.EventPostBuildExecute.Count != 0)
{
fastBuildTargetSubTargets.Add(shortProjectName);
}
}
else if (!depProjConfig.IsExcludedFromBuild)
{
fastBuildProjectExeUtilityDependencyList.Add(GetShortProjectName(depProjConfig.Project, depProjConfig));
}
}
orderedProjectDeps = UtilityMethods.GetOrderedFlattenedBuildOnlyDependencies(conf);
foreach (var depProjConfig in orderedProjectDeps)
{
if (depProjConfig.Project == project)
throw new Error("Sharpmake-FastBuild : Project dependencies refers to itself.");
bool isExport = depProjConfig.Project.SharpmakeProjectType == Project.ProjectTypeAttribute.Export;
if (isExport)
continue;
if (depProjConfig.Output != Project.Configuration.OutputType.Exe &&
depProjConfig.Output != Project.Configuration.OutputType.AppleApp &&
depProjConfig.Output != Project.Configuration.OutputType.Utility)
{
fastBuildBuildOnlyDependencies.Add(GetShortProjectName(depProjConfig.Project, depProjConfig));
}
else
{
fastBuildProjectExeUtilityDependencyList.Add(GetShortProjectName(depProjConfig.Project, depProjConfig));
}
}
}
string librarianAdditionalInputs = FileGeneratorUtilities.RemoveLineTag;
string outputType;
switch (conf.Output)
{
case Project.Configuration.OutputType.Lib:
outputType = "Library";
break;
case Project.Configuration.OutputType.Exe:
case Project.Configuration.OutputType.AppleApp:
outputType = "Executable";
break;
case Project.Configuration.OutputType.Dll:
outputType = "DLL";
break;
default:
outputType = "Unknown";
break;
}
if (confSubConfigs.Keys.Count > 1)
{
if (!isLastSubConfig)
{
fastBuildOutputFileShortName += "_" + subConfigIndex.ToString();
fastBuildOutputFile = Path.ChangeExtension(fastBuildOutputFile, null); // removes the extension
fastBuildOutputFile += "_" + subConfigIndex.ToString();
fastBuildOutputFile += vcxprojPlatform.StaticLibraryFileFullExtension;
subConfigObjectList.Add(fastBuildOutputFileShortName);
additionalLibs.Add(fastBuildOutputFileShortName + "_objects");
}
else
{
StringBuilder result = new StringBuilder();
foreach (string subConfigObject in subConfigObjectList)
{
if (!useObjectLists && conf.Output != Project.Configuration.OutputType.Dll && conf.Output != Project.Configuration.OutputType.Exe && conf.Output != Project.Configuration.OutputType.AppleApp)
fastBuildProjectDependencies.Add(subConfigObject + "_" + outputType);
else
fastBuildProjectDependencies.Add(subConfigObject + "_objects");
}
}
}
string fastBuildPCHForceInclude = FileGeneratorUtilities.RemoveLineTag;
string fastBuildCompilerPCHOptions = isUsePrecomp ? Template.ConfigurationFile.UsePrecomp : FileGeneratorUtilities.RemoveLineTag;
string fastBuildCompilerPCHOptionsClang = isUsePrecomp ? Template.ConfigurationFile.UsePrecompClang : FileGeneratorUtilities.RemoveLineTag;
string fastBuildCompilerDeoptimizeOptionClang = isCompileAsSwiftFile ? "-Onone" : "-O0";
string fastBuildLinkerOutputFile = fastBuildOutputFile;
string fastBuildStampExecutable = FileGeneratorUtilities.RemoveLineTag;
string fastBuildStampArguments = FileGeneratorUtilities.RemoveLineTag;
var postBuildEvents = new Dictionary<string, Project.Configuration.BuildStepBase>();
Strings preBuildTargets = new Strings();
var fastBuildTargetLibraryDependencies = new Strings();
{
if (isLastSubConfig) // post-build steps on the last subconfig
{
if (isOutputTypeExe || isOutputTypeAppleApp || conf.ExecuteTargetCopy)
{
if (conf.CopyDependenciesBuildStep != null)
throw new NotImplementedException("CopyDependenciesBuildStep are not supported with FastBuild");
var copies = ProjectOptionsGenerator.ConvertPostBuildCopiesToRelative(conf, projectPath);
foreach (var copy in copies)
{
var sourceFile = copy.Key;
var destinationFolder = copy.Value;
// 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(projectPath, destinationFolder, conf.Project.RootPath, true, conf.Project.RootPath);
string fastBuildCopyAlias = UtilityMethods.GetFastBuildCopyAlias(Path.GetFileName(sourceFile), destinationRelativeToGlobal);
fastBuildBuildOnlyDependencies.Add(fastBuildCopyAlias);
}
}
}
// When we have a Library/Dll/Executable section, put the prebuild dependencies there (which is the last subconfig).
// Otherwise put it on the first object list
var preBuildTargetsOnLastSubconfig = isOutputTypeExeOrDllOrAppleApp || (isOutputTypeLib && !confUseLibraryDependencyInputs);
if ((preBuildTargetsOnLastSubconfig && isLastSubConfig) || (!preBuildTargetsOnLastSubconfig && isFirstSubConfig))
{
// the pre-steps are written in the master bff, we only need to refer their aliases
preBuildTargets.AddRange(conf.EventPreBuildExecute.Select(e => e.Key));
preBuildTargets.AddRange(conf.ResolvedEventPreBuildExe.Select(e => ProjectOptionsGenerator.MakeBuildStepName(conf, e, Vcxproj.BuildStep.PreBuild, project.RootPath, projectPath)));
preBuildTargets.AddRange(conf.EventCustomPrebuildExecute.Select(e => e.Key));
preBuildTargets.AddRange(conf.ResolvedEventCustomPreBuildExe.Select(e => ProjectOptionsGenerator.MakeBuildStepName(conf, e, Vcxproj.BuildStep.PreBuildCustomAction, project.RootPath, projectPath)));
}
fastBuildTargetSubTargets.AddRange(fastBuildProjectExeUtilityDependencyList);
if (conf.Output == Project.Configuration.OutputType.Lib && useObjectLists)
{
string objectList = fastBuildOutputFileShortName + "_objects";
fastBuildTargetLibraryDependencies.Add(objectList);
fastBuildTargetSubTargets.Add(objectList);
}
else if (conf.Output == Project.Configuration.OutputType.None && project.IsFastBuildAll)
{
// filter to only get the configurations of projects that were explicitly added, not the dependencies
var minResolvedConf = conf.ResolvedPrivateDependencies.Where(x => conf.UnResolvedPrivateDependencies.ContainsKey(x.Project.GetType()));
foreach (var dep in minResolvedConf)
{
if (dep.Project.SharpmakeProjectType != Project.ProjectTypeAttribute.Export &&
dep.Output != Project.Configuration.OutputType.None &&
dep.Output != Project.Configuration.OutputType.Utility)
{
fastBuildTargetSubTargets.Add(GetShortProjectName(dep.Project, dep));
}
}
}
else
{
string targetId = fastBuildOutputFileShortName + "_" + outputType;
fastBuildTargetLibraryDependencies.Add(targetId);
fastBuildTargetSubTargets.Add(targetId);
}
if (isLastSubConfig) // post-build steps on the last subconfig
{
foreach (var eventPair in conf.EventPostBuildExecute)
{
fastBuildTargetSubTargets.Add(eventPair.Key);
postBuildEvents.Add(eventPair.Key, eventPair.Value);
}
var extraPlatformEvents = new List<Project.Configuration.BuildStepBase>();
if (!FastBuildSettings.FastBuildSupportLinkerStampList && isOutputTypeExeOrDllOrAppleApp)
extraPlatformEvents.AddRange(platformBff.GetExtraStampEvents(conf, fastBuildOutputFile).Select(step => { step.Resolve(resolver); return step; }));
extraPlatformEvents.AddRange(platformBff.GetExtraPostBuildEvents(conf, fastBuildOutputFile).Select(step => { step.Resolve(resolver); return step; }));
foreach (var buildEvent in extraPlatformEvents.Concat(conf.ResolvedEventPostBuildExe))
{
string eventKey = ProjectOptionsGenerator.MakeBuildStepName(conf, buildEvent, Vcxproj.BuildStep.PostBuild, project.RootPath, projectPath);
fastBuildTargetSubTargets.Add(eventKey);
postBuildEvents.Add(eventKey, buildEvent);
}
foreach (var eventPair in conf.EventCustomPostBuildExecute)
{
fastBuildTargetSubTargets.Add(eventPair.Key);
postBuildEvents.Add(eventPair.Key, eventPair.Value);
}
foreach (var buildEvent in conf.ResolvedEventCustomPostBuildExe)
{
string eventKey = ProjectOptionsGenerator.MakeBuildStepName(conf, buildEvent, Vcxproj.BuildStep.PostBuildCustomAction, project.RootPath, projectPath);
fastBuildTargetSubTargets.Add(eventKey);
postBuildEvents.Add(eventKey, buildEvent);
}
if (conf.PostBuildStepTest != null)
{
string eventKey = ProjectOptionsGenerator.MakeBuildStepName(conf, conf.PostBuildStepTest, Vcxproj.BuildStep.PostBuildCustomAction, project.RootPath, projectPath);
fastBuildTargetSubTargets.Add(eventKey);
postBuildEvents.Add(eventKey, conf.PostBuildStepTest);
}
}
if (conf.Output != Project.Configuration.OutputType.Dll && conf.Output != Project.Configuration.OutputType.Exe && conf.Output != Project.Configuration.OutputType.AppleApp)
{
foreach (var subConfigObject in subConfigObjectList)
{
string subTarget;
if (useObjectLists)
subTarget = subConfigObject + "_objects";
else
subTarget = subConfigObject + "_" + outputType;
if (!fastBuildTargetSubTargets.Contains(subTarget))
fastBuildTargetSubTargets.Add(subTarget);
if (!fastBuildTargetLibraryDependencies.Contains(subTarget))
fastBuildTargetLibraryDependencies.Add(subTarget);
}
}
}
if (additionalDependencies != null && additionalDependencies.Any())
scopedOptions.Add(new Options.ScopedOption(confCmdLineOptions, "AdditionalDependencies", string.Join($"'{Environment.NewLine} + ' ", additionalDependencies)));
else
scopedOptions.Add(new Options.ScopedOption(confCmdLineOptions, "AdditionalDependencies", FileGeneratorUtilities.RemoveLineTag));
string fastBuildConsumeWinRTExtension = isConsumeWinRTExtensions ? "/ZW" : FileGeneratorUtilities.RemoveLineTag;
string fastBuildUsingPlatformConfig = FileGeneratorUtilities.RemoveLineTag;
string fastBuildSourceFileType;
string clangFileLanguage = string.Empty;
if (isCompileAsCFile)
{
fastBuildUsingPlatformConfig = platformBff.CConfigName(conf);
// Do not take Cpp Language conformance into account while compiling in C
scopedOptions.Add(new Options.ScopedOption(confCmdLineOptions, "CppLanguageStd", FileGeneratorUtilities.RemoveLineTag));
scopedOptions.Add(new Options.ScopedOption(confOptions, "ClangCppLanguageStandard", FileGeneratorUtilities.RemoveLineTag));
// and remove the stdlib specification as well
scopedOptions.Add(new Options.ScopedOption(confCmdLineOptions, "StdLib", FileGeneratorUtilities.RemoveLineTag));
// MSVC
scopedOptions.Add(new Options.ScopedOption(confCmdLineOptions, "LanguageStandard", FileGeneratorUtilities.RemoveLineTag));
scopedOptions.Add(new Options.ScopedOption(confCmdLineOptions, "ClangEnableObjC_ARC", FileGeneratorUtilities.RemoveLineTag));
if (clangPlatformBff != null)
clangFileLanguage = "-x c "; // Compiler option to indicate that its a C file
fastBuildSourceFileType = "/TC";
}
else if (isCompileAsObjCFile)
{
// Do not take Cpp Language conformance into account while compiling in objc
scopedOptions.Add(new Options.ScopedOption(confCmdLineOptions, "CppLanguageStd", FileGeneratorUtilities.RemoveLineTag));
scopedOptions.Add(new Options.ScopedOption(confOptions, "ClangCppLanguageStandard", FileGeneratorUtilities.RemoveLineTag));
// and remove the stdlib specification as well
scopedOptions.Add(new Options.ScopedOption(confCmdLineOptions, "StdLib", FileGeneratorUtilities.RemoveLineTag));
// MSVC
scopedOptions.Add(new Options.ScopedOption(confCmdLineOptions, "LanguageStandard", FileGeneratorUtilities.RemoveLineTag));
if (clangPlatformBff != null)
clangFileLanguage = "-x objective-c ";
fastBuildUsingPlatformConfig = platformBff.CConfigName(conf);
fastBuildSourceFileType = "";
}
else if (isCompileAsObjCPPFile)
{
// Do not take C Language conformance into account while compiling in objcpp
scopedOptions.Add(new Options.ScopedOption(confCmdLineOptions, "CLanguageStd", FileGeneratorUtilities.RemoveLineTag));
scopedOptions.Add(new Options.ScopedOption(confCmdLineOptions, "ClangCLanguageStandard", FileGeneratorUtilities.RemoveLineTag));
// MSVC
scopedOptions.Add(new Options.ScopedOption(confCmdLineOptions, "LanguageStandard_C", FileGeneratorUtilities.RemoveLineTag));
if (clangPlatformBff != null)
clangFileLanguage = "-x objective-c++ ";
fastBuildUsingPlatformConfig = platformBff.CppConfigName(conf);
fastBuildSourceFileType = "";
}
else if (isCompileAsSwiftFile)
{
clangFileLanguage = "";
fastBuildUsingPlatformConfig = applePlatformBff.SwiftConfigName(conf);
fastBuildSourceFileType = "";
}
else
{
// Do not take C Language conformance into account while compiling in Cpp
scopedOptions.Add(new Options.ScopedOption(confCmdLineOptions, "CLanguageStd", FileGeneratorUtilities.RemoveLineTag));
scopedOptions.Add(new Options.ScopedOption(confOptions, "ClangCLanguageStandard", FileGeneratorUtilities.RemoveLineTag));
// MSVC
scopedOptions.Add(new Options.ScopedOption(confCmdLineOptions, "LanguageStandard_C", FileGeneratorUtilities.RemoveLineTag));
scopedOptions.Add(new Options.ScopedOption(confCmdLineOptions, "ClangEnableObjC_ARC", FileGeneratorUtilities.RemoveLineTag));
// if files are specifically c++, we need to add the language flag to make sure the compiler sees them as c++
if (isCompileAsCPPFile && clangPlatformBff != null)
clangFileLanguage = "-x c++ ";
fastBuildSourceFileType = "/TP";
fastBuildUsingPlatformConfig = platformBff.CppConfigName(conf);
}
// TODOANT: Add nasm/masm change
if (isASMFileSection)
{
fastBuildUsingPlatformConfig += Template.ConfigurationFile.MasmConfigNameSuffix;
}
if (isNASMFileSection)
{
fastBuildUsingPlatformConfig += Template.ConfigurationFile.NasmConfigNameSuffix;
}
string fastBuildCompilerExtraOptions = Template.ConfigurationFile.CPPCompilerExtraOptions;
if (isASMFileSection)
{
fastBuildCompilerExtraOptions = Template.ConfigurationFile.MasmCompilerExtraOptions;
}
if (isNASMFileSection)
{
fastBuildCompilerExtraOptions = Template.ConfigurationFile.NasmCompilerExtraOptions;
}
string fastBuildCompilerOptionsDeoptimize = FileGeneratorUtilities.RemoveLineTag;
if (!isASMFileSection && conf.FastBuildDeoptimization != Project.Configuration.DeoptimizationWritableFiles.NoDeoptimization)
fastBuildCompilerOptionsDeoptimize = Template.ConfigurationFile.CPPCompilerOptionsDeoptimize;
string compilerOptions = Template.ConfigurationFile.CompilerOptionsCPP;
if (isASMFileSection)
{
compilerOptions = Template.ConfigurationFile.CompilerOptionsMasm;
}
if (isNASMFileSection)
{
compilerOptions = Template.ConfigurationFile.CompilerOptionsNasm;
}
compilerOptions += Template.ConfigurationFile.CompilerOptionsCommon;
string compilerOptionsClang = Template.ConfigurationFile.CompilerOptionsClang;
if (isNASMFileSection)
{
compilerOptionsClang = Template.ConfigurationFile.CompilerOptionsNasm;
}
compilerOptionsClang += Template.ConfigurationFile.CompilerOptionsCommon;
string fastBuildDeoptimizationWritableFiles = null;
string fastBuildDeoptimizationWritableFilesWithToken = null;
Project.Configuration.DeoptimizationWritableFiles deoptimizeSetting = conf.FastBuildDeoptimization;
if (isASMFileSection)
deoptimizeSetting = Project.Configuration.DeoptimizationWritableFiles.NoDeoptimization;
switch (deoptimizeSetting)
{
case Project.Configuration.DeoptimizationWritableFiles.DeoptimizeWritableFiles:
fastBuildDeoptimizationWritableFiles = "true";
fastBuildDeoptimizationWritableFilesWithToken = FileGeneratorUtilities.RemoveLineTag;
break;
case Project.Configuration.DeoptimizationWritableFiles.DeoptimizeWritableFilesWithToken:
fastBuildDeoptimizationWritableFiles = FileGeneratorUtilities.RemoveLineTag;
fastBuildDeoptimizationWritableFilesWithToken = "true";
break;
default:
fastBuildDeoptimizationWritableFiles = FileGeneratorUtilities.RemoveLineTag;
fastBuildDeoptimizationWritableFilesWithToken = FileGeneratorUtilities.RemoveLineTag;
break;
}
string fastBuildCompilerForceUsing = FileGeneratorUtilities.RemoveLineTag;
string fastBuildAdditionalCompilerOptionsFromCode = FileGeneratorUtilities.RemoveLineTag;
if (conf.ReferencesByPath.Count > 0) // only ref by path supported
{
fastBuildAdditionalCompilerOptionsFromCode = "";
foreach (var refByPath in conf.ReferencesByPath)
{
string refByPathCopy = refByPath;
if (ShouldMakePathRelative(refByPath, context.Project))
refByPathCopy = CurrentBffPathKeyCombine(Util.PathGetRelative(context.ProjectDirectory, refByPath));
fastBuildAdditionalCompilerOptionsFromCode += "/FU\"" + refByPathCopy + "\" ";
}
}
string llvmClangCompilerOptions = null;
if (!isConsumeWinRTExtensions)
{
var platformToolset = Options.GetObject<Options.Vc.General.PlatformToolset>(conf);
if (platformToolset.IsLLVMToolchain() && Options.GetObject<Options.Vc.LLVM.UseClangCl>(context.Configuration) == Options.Vc.LLVM.UseClangCl.Enable)
{
switch (platformToolset)
{
case Options.Vc.General.PlatformToolset.LLVM:
case Options.Vc.General.PlatformToolset.ClangCL:
llvmClangCompilerOptions = "-m64"; // -m$(PlatformArchitecture)
fastBuildPCHForceInclude = @"/FI""[cmdLineOptions.PrecompiledHeaderThrough]""";
// <!-- Set the value of _MSC_VER and _MSC_FULL_VER to claim for compatibility -->
Project.Configuration.FastBuildClangMscVersionDetectionType detectionType = conf.FastBuildClangMscVersionDetectionInfo;
string overridenMscVer = Options.GetString<Options.Clang.Compiler.MscVersion>(conf);
Options.Vc.General.PlatformToolset overridenPlatformToolset = Options.Vc.General.PlatformToolset.Default;
Options.WithArgOption<Options.Vc.General.PlatformToolset>.Get<Options.Clang.Compiler.LLVMVcPlatformToolset>(conf, ref overridenPlatformToolset);
CompilerVersionForClangCl detectedVersion = DetectCompilerVersionForClangCl(
detectionType, overridenMscVer, overridenPlatformToolset, context.DevelopmentEnvironment, conf.Target.GetPlatform());
switch (detectedVersion.versionType)
{
case CompilerVersionForClangClType.MscVersion :
llvmClangCompilerOptions += string.Format(" -fmsc-version={0}", detectedVersion.mscVersion);
break;
case CompilerVersionForClangClType.MsCompatibilityVersion :
llvmClangCompilerOptions += string.Format(" -fms-compatibility-version={0}.{1}.{2}", detectedVersion.msCompatibilityVersion.Major, detectedVersion.msCompatibilityVersion.Minor, detectedVersion.msCompatibilityVersion.Build);
break;
}
break;
}
}
}
if (!string.IsNullOrEmpty(llvmClangCompilerOptions))
{
if (fastBuildAdditionalCompilerOptionsFromCode == FileGeneratorUtilities.RemoveLineTag)
fastBuildAdditionalCompilerOptionsFromCode = llvmClangCompilerOptions;
else
fastBuildAdditionalCompilerOptionsFromCode += " " + llvmClangCompilerOptions;
}
// c1xx: warning C4199: two-phase name lookup is not supported for C++/CLI, C++/CX, or OpenMP; use /Zc:twoPhase-
if (isConsumeWinRTExtensions && context.DevelopmentEnvironment >= DevEnv.vs2017)
{
if (conf.AdditionalCompilerOptions.Contains("/permissive-") && !conf.AdditionalCompilerOptions.Contains("/Zc:twoPhase-"))
{
if (fastBuildAdditionalCompilerOptionsFromCode == FileGeneratorUtilities.RemoveLineTag)
fastBuildAdditionalCompilerOptionsFromCode = "/Zc:twoPhase-";
else
fastBuildAdditionalCompilerOptionsFromCode += " /Zc:twoPhase-";
}
}
if (conf.ReferencesByName.Count > 0)
{
throw new Exception("Use ReferencesByPath instead of ReferencesByName for FastBuild support; ");
}
if (conf.ForceUsingDependencies.Any() || conf.DependenciesForceUsingFiles.Any() || conf.ForceUsingFiles.Any())
{
StringBuilder builderForceUsingFiles = new StringBuilder();
foreach (var fuConfig in conf.ForceUsingDependencies)
{
builderForceUsingFiles.AppendFormat(@" /FU""{0}.dll""", fuConfig.TargetFileFullName);
}
foreach (var f in conf.ForceUsingFiles.Union(conf.DependenciesForceUsingFiles))
{
string file = f;
if (ShouldMakePathRelative(f, context.Project))
file = CurrentBffPathKeyCombine(Util.PathGetRelative(context.ProjectDirectory, f));
builderForceUsingFiles.AppendFormat(@" /FU""{0}""", file);
}
fastBuildCompilerForceUsing = builderForceUsingFiles.ToString();
}
if (isOutputTypeExeOrDllOrAppleApp)
{
var extraPlatformEvents = new List<Project.Configuration.BuildStepExecutable>();
if (FastBuildSettings.FastBuildSupportLinkerStampList)
extraPlatformEvents.AddRange(platformBff.GetExtraStampEvents(conf, fastBuildOutputFile).Select(step => { step.Resolve(resolver); return step; }));
if (conf.PostBuildStampExe != null || conf.PostBuildStampExes.Any() || extraPlatformEvents.Any())
{
var fastbuildStampExecutableList = new List<string>();
var fastBuildStampArgumentsList = new List<string>();
foreach (var stampExe in extraPlatformEvents.Concat(conf.PostBuildStampExes.Prepend(conf.PostBuildStampExe)).Where(x => x != null))
{
fastbuildStampExecutableList.Add(CurrentBffPathKeyCombine(Util.PathGetRelative(projectPath, stampExe.ExecutableFile, true)));
fastBuildStampArgumentsList.Add(string.Format("{0} {1} {2}",
stampExe.ExecutableInputFileArgumentOption,
stampExe.ExecutableOutputFileArgumentOption,
stampExe.ExecutableOtherArguments));
}
fastBuildStampExecutable = UtilityMethods.FBuildFormatList(fastbuildStampExecutableList, 30);
fastBuildStampArguments = UtilityMethods.FBuildFormatList(fastBuildStampArgumentsList, 30);
}
}
bool linkObjects = false;
if (isOutputTypeExeOrDllOrAppleApp)
{
linkObjects = confUseLibraryDependencyInputs;
}
Strings fullInputPaths = new Strings();
string fastBuildInputPath = FileGeneratorUtilities.RemoveLineTag;
string fastBuildInputExcludedFiles = FileGeneratorUtilities.RemoveLineTag;
{
Strings excludedSourceFiles = new Strings();
if (isNoBlobImplicitConfig && isDefaultSubConfig)
{
fullInputPaths.Add(context.ProjectSourceCapitalized);
fullInputPaths.AddRange(project.AdditionalSourceRootPaths.Select(Util.GetCapitalizedPath));
excludedSourceFiles.AddRange(filesInNonDefaultSection.Select(f => f.FileName));
}
if (isDefaultSubConfig && conf.FastBuildBlobbingStrategy == Project.Configuration.InputFileStrategy.Exclude && conf.FastBuildBlobbed)
{
// Adding the folders excluded from unity to the folders to build without unity(building each file individually)
fullInputPaths.AddRange(project.SourcePathsBlobExclude.Select(Util.GetCapitalizedPath));
}
if (project.SourceFilesFiltersRegex.Count == 0)
{
var relativePaths = new Strings(fullInputPaths.Select(p => CurrentBffPathKeyCombine(Util.PathGetRelative(context.ProjectDirectory, p, true))));
fastBuildInputPath = UtilityMethods.FBuildCollectionFormat(relativePaths, 32);
}
else
{
fullInputPaths.Clear();
}
excludedSourceFiles.AddRange(conf.ResolvedSourceFilesBuildExclude);
excludedSourceFiles.AddRange(conf.PrecompSourceExclude);
// 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.
var excludedSourceFilesRelative = new Strings();
foreach (string file in excludedSourceFiles.SortedValues)
{
string fileExtension = Path.GetExtension(file);
if (project.SourceFilesCompileExtensions.Contains(fileExtension))
{
if (IsFileInInputPathList(fullInputPaths, file))
excludedSourceFilesRelative.Add(CurrentBffPathKeyCombine(Util.PathGetRelative(context.ProjectDirectoryCapitalized, file)));
}
}
if (excludedSourceFilesRelative.Count > 0)
{
Strings includedExtensions = isCompileAsCFile ? new Strings { ".c" } : project.SourceFilesCPPExtensions;
fastBuildInputExcludedFiles = UtilityMethods.FBuildCollectionFormat(excludedSourceFilesRelative, 34, includedExtensions);
}
}
bool projectHasResourceFiles = false;
bool projectHasEmbeddedResources = false;
string fastBuildSourceFiles = FileGeneratorUtilities.RemoveLineTag;
string fastBuildResourceFiles = FileGeneratorUtilities.RemoveLineTag;
string fastBuildEmbeddedResources = FileGeneratorUtilities.RemoveLineTag;
string fastBuildEmbeddedOutputPrefix = conf.EmbeddedResourceOutputPrefix;
{
List<string> fastbuildSourceFilesList = new List<string>();
List<string> fastbuildResourceFilesList = new List<string>();
List<string> fastbuildEmbeddedResourceFilesList = new List<string>();
var sourceFiles = confSubConfigs[subConfig];
foreach (var sourceFile in sourceFiles)
{
string sourceFileName = CurrentBffPathKeyCombine(sourceFile.FileNameProjectRelative);
if (isUsePrecomp && conf.PrecompSource != null && sourceFile.FileName.EndsWith(conf.PrecompSource, StringComparison.OrdinalIgnoreCase))
{
fastBuildPrecompiledSourceFile = sourceFileName;
}
else if (string.Compare(sourceFile.FileExtension, ".rc", StringComparison.OrdinalIgnoreCase) == 0)
{
if (microsoftPlatformBff != null && microsoftPlatformBff.SupportsResourceFiles)
{
fastbuildResourceFilesList.Add(sourceFileName);
projectHasResourceFiles = true;
}
}
else if (string.Compare(sourceFile.FileExtension, ".resx", StringComparison.OrdinalIgnoreCase) == 0)
{
if (microsoftPlatformBff != null && microsoftPlatformBff.SupportsResourceFiles)
{
fastbuildEmbeddedResourceFilesList.Add(sourceFileName);
projectHasEmbeddedResources = true;
}
}
else
{
bool isSourceFileExtension = project.SourceFilesCompileExtensions.Contains(sourceFile.FileExtension);
bool isBlobbed = project.SourceFilesBlobExtensions.Contains(sourceFile.FileExtension);
if ((isSourceFileExtension && !isBlobbed) ||
conf.ResolvedSourceFilesBlobExclude.Contains(sourceFile.FileName) ||
isNoBlobImplicitConfig ||
!isUnity)
{
if (!IsFileInInputPathList(fullInputPaths, sourceFile.FileName))
fastbuildSourceFilesList.Add(sourceFileName);
}
}
}
fastBuildSourceFiles = UtilityMethods.FBuildFormatList(fastbuildSourceFilesList, 32);
fastBuildResourceFiles = UtilityMethods.FBuildFormatList(fastbuildResourceFilesList, 30);
fastBuildEmbeddedResources = UtilityMethods.FBuildFormatList(fastbuildEmbeddedResourceFilesList, 30);
}
var fileCustomBuildKeys = new Strings();
UtilityMethods.WriteConfigCustomBuildStepsAsGenericExecutable(context.ProjectDirectoryCapitalized, bffGenerator, context.Project, conf,
key =>
{
if (!allFileCustomBuild.TryGetValue(key.Description, out var alreadyRegistered))
{
allFileCustomBuild.Add(key.Description, key);
bffGenerator.Write(Template.ConfigurationFile.GenericExecutableSection);
}
else if (key.Executable != alreadyRegistered.Executable ||
key.KeyInput != alreadyRegistered.KeyInput ||
key.Output != alreadyRegistered.Output ||
key.ExecutableArguments != alreadyRegistered.ExecutableArguments)
{
throw new Exception(string.Format("Command key '{0}' duplicates another command. Command is:\n{1}", key, bffGenerator.Resolver.Resolve(Template.ConfigurationFile.GenericExecutableSection)));
}
fileCustomBuildKeys.Add(key.Description);
return false;
});
Strings fastBuildPreBuildDependencies = new Strings();
var orderedForceUsingDeps = UtilityMethods.GetOrderedFlattenedProjectDependencies(conf, false, true);
fastBuildPreBuildDependencies.AddRange(orderedForceUsingDeps.Select(dep => GetShortProjectName(dep.Project, dep)));
// fastBuildBuildOnlyDependencies only gets added to exe/dll sections.
// Add the prebuild steps to fastBuildPreBuildDependencies if we are building a lib
if (isOutputTypeExeOrDllOrAppleApp)
{
fastBuildBuildOnlyDependencies.AddRange(preBuildTargets);
fastBuildBuildOnlyDependencies.AddRange(fileCustomBuildKeys);
}
else if (isOutputTypeLib)
{
fastBuildPreBuildDependencies.AddRange(preBuildTargets);
if (isLastSubConfig)
fastBuildPreBuildDependencies.AddRange(fileCustomBuildKeys);
}
if (projectHasResourceFiles)
resourceFilesSections.Add(fastBuildOutputFileShortName + "_resources");
if (projectHasEmbeddedResources)
{
embeddedResourceFilesSections.Add(fastBuildOutputFileShortName + "_embedded");
scopedOptions.Add(new Options.ScopedOption(confCmdLineOptions, "EmbedResources", "/ASSEMBLYRESOURCE:\"%3\""));
}
else
{
scopedOptions.Add(new Options.ScopedOption(confCmdLineOptions, "EmbedResources", FileGeneratorUtilities.RemoveLineTag));
}
if (mustGenerateLibrary)
{
librarianAdditionalInputs = UtilityMethods.FBuildFormatList(additionalLibs, 33);
}
// It is useless to have an input pattern defined if there is no input path
if (fastBuildInputPath == FileGeneratorUtilities.RemoveLineTag)
fastBuildCompilerInputPattern = FileGeneratorUtilities.RemoveLineTag;
fastBuildProjectDependencies.AddRange(resourceFilesSections);
fastBuildProjectDependencies.Add("[fastBuildOutputFileShortName]_objects");
string fastBuildObjectListEmbeddedResources = FormatListPartForTag(embeddedResourceFilesSections, 32, true);
string fastBuildInputFilesRootPath = FileGeneratorUtilities.RemoveLineTag;
if (conf.FastBuildInputFilesRootPath != null)
{
fastBuildInputFilesRootPath = CurrentBffPathKeyCombine(Util.PathGetRelative(context.ProjectDirectory, conf.FastBuildInputFilesRootPath));
}
using (bffGenerator.Declare("conf", conf))
using (bffGenerator.Declare("project", project))
using (bffGenerator.Declare("target", conf.Target))
{
switch (conf.Output)
{
case Project.Configuration.OutputType.Lib:
case Project.Configuration.OutputType.Exe:
case Project.Configuration.OutputType.AppleApp:
case Project.Configuration.OutputType.Dll:
using (bffGenerator.Declare("$(ProjectName)", projectName))
using (bffGenerator.Declare("options", confOptions))
using (bffGenerator.Declare("cmdLineOptions", confCmdLineOptions))
using (bffGenerator.Declare("fastBuildUsingPlatformConfig", "Using( " + fastBuildUsingPlatformConfig + " )"))
using (bffGenerator.Declare("fastBuildProjectName", projectName))
using (bffGenerator.Declare("fastBuildClrSupport", fastBuildSubConfigClrSupport))
using (bffGenerator.Declare("fastBuildOutputFileShortName", fastBuildOutputFileShortName))
using (bffGenerator.Declare("fastBuildOutputFile", fastBuildOutputFile))
using (bffGenerator.Declare("fastBuildLinkerOutputFile", fastBuildLinkerOutputFile))
using (bffGenerator.Declare("fastBuildLinkerLinkObjects", linkObjects ? "true" : "false"))
using (bffGenerator.Declare("fastBuildInputPath", fastBuildInputPath))
using (bffGenerator.Declare("fastBuildCompilerInputPattern", fastBuildCompilerInputPattern))
using (bffGenerator.Declare("fastBuildInputExcludedFiles", fastBuildInputExcludedFiles))
using (bffGenerator.Declare("fastBuildSourceFiles", fastBuildSourceFiles))
using (bffGenerator.Declare("fastBuildResourceFiles", fastBuildResourceFiles))
using (bffGenerator.Declare("fastBuildEmbeddedResources", fastBuildEmbeddedResources))
using (bffGenerator.Declare("fastBuildPrecompiledSourceFile", fastBuildPrecompiledSourceFile))
using (bffGenerator.Declare("fastBuildProjectDependencies", UtilityMethods.FBuildFormatList(fastBuildProjectDependencies.Values, 30)))
using (bffGenerator.Declare("fastBuildBuildOnlyDependencies", UtilityMethods.FBuildFormatList(fastBuildBuildOnlyDependencies.Values, 30)))
using (bffGenerator.Declare("fastBuildPreBuildTargets", UtilityMethods.FBuildFormatList(fastBuildPreBuildDependencies.Values, 28)))
using (bffGenerator.Declare("fastBuildObjectListEmbeddedResources", fastBuildObjectListEmbeddedResources))
using (bffGenerator.Declare("fastBuildCompilerPCHOptions", fastBuildCompilerPCHOptions))
using (bffGenerator.Declare("fastBuildCompilerPCHOptionsClang", fastBuildCompilerPCHOptionsClang))
using (bffGenerator.Declare("fastBuildCompilerDeoptimizeOptionClang", fastBuildCompilerDeoptimizeOptionClang))
using (bffGenerator.Declare("fastBuildPCHForceInclude", isUsePrecomp ? fastBuildPCHForceInclude : FileGeneratorUtilities.RemoveLineTag))
using (bffGenerator.Declare("fastBuildConsumeWinRTExtension", fastBuildConsumeWinRTExtension))
using (bffGenerator.Declare("fastBuildOutputType", outputType))
using (bffGenerator.Declare("fastBuildLibrarianAdditionalInputs", librarianAdditionalInputs))
using (bffGenerator.Declare("fastBuildCompileAsC", fastBuildCompileAsC))
using (bffGenerator.Declare("fastBuildUnityName", fastBuildUnityName ?? FileGeneratorUtilities.RemoveLineTag))
using (bffGenerator.Declare("fastBuildInputFilesRootPath", fastBuildInputFilesRootPath))
using (bffGenerator.Declare("fastBuildClangFileLanguage", clangFileLanguage))
using (bffGenerator.Declare("fastBuildDeoptimizationWritableFiles", fastBuildDeoptimizationWritableFiles))
using (bffGenerator.Declare("fastBuildDeoptimizationWritableFilesWithToken", fastBuildDeoptimizationWritableFilesWithToken))
using (bffGenerator.Declare("fastBuildCompilerForceUsing", fastBuildCompilerForceUsing))
using (bffGenerator.Declare("fastBuildSourceFileType", fastBuildSourceFileType))
using (bffGenerator.Declare("fastBuildAdditionalCompilerOptionsFromCode", fastBuildAdditionalCompilerOptionsFromCode))
using (bffGenerator.Declare("fastBuildStampExecutable", fastBuildStampExecutable))
using (bffGenerator.Declare("fastBuildStampArguments", fastBuildStampArguments))
using (bffGenerator.Declare("fastBuildEmbeddedOutputPrefix", fastBuildEmbeddedOutputPrefix))
using (bffGenerator.Declare("fastbuildConcurrencyGroupName", conf.FastBuildLinkConcurrencyGroup ?? FileGeneratorUtilities.RemoveLineTag))
{
if (projectHasResourceFiles)
{
bffGenerator.Write(Template.ConfigurationFile.ResourcesBeginSection);
bffGenerator.Write(Template.ConfigurationFile.ResourceCompilerExtraOptions);
bffGenerator.Write(Template.ConfigurationFile.ResourceCompilerOptions);
bffGenerator.Write(Template.ConfigurationFile.EndSection);
}
if (projectHasEmbeddedResources)
{
// Only declare the compiler here to avoid potential exceptions caused by GetFragment in targets without a .Net framework
using (bffGenerator.Declare("fastBuildEmbeddedResourceCompiler", KitsRootPaths.GetNETFXToolsDir(conf.Target.GetFragment<DotNetFramework>()) + "resgen.exe"))
{
bffGenerator.Write(Template.ConfigurationFile.EmbeddedResourcesBeginSection);
bffGenerator.Write(Template.ConfigurationFile.EmbeddedResourceCompilerOptions);
bffGenerator.Write(Template.ConfigurationFile.EndSection);
}
}
// Exe, DLL and AppleApp will always add an extra objectlist
if (isOutputTypeExeOrDllOrAppleApp && isLastSubConfig // only last subconfig will generate objectlist
)
{
bffGenerator.Write(Template.ConfigurationFile.ObjectListBeginSection);
if (conf.Platform.IsMicrosoft())
{
bffGenerator.Write(fastBuildCompilerExtraOptions);
bffGenerator.Write(Template.ConfigurationFile.CPPCompilerOptimizationOptions);
if (isUsePrecomp)
bffGenerator.Write(Template.ConfigurationFile.PCHOptions);
bffGenerator.Write(compilerOptions);
if (conf.FastBuildDeoptimization != Project.Configuration.DeoptimizationWritableFiles.NoDeoptimization)
{
if (isUsePrecomp)
bffGenerator.Write(Template.ConfigurationFile.PCHOptionsDeoptimize);
bffGenerator.Write(fastBuildCompilerOptionsDeoptimize);
bffGenerator.Write(Template.ConfigurationFile.DeOptimizeOption);
}
}
else
{
if (isCompileAsSwiftFile)
applePlatformBff?.SetupSwiftOptions(bffGenerator);
else if (!isNASMFileSection)
clangPlatformBff?.SetupClangOptions(bffGenerator); // TODO: This checks twice if the platform supports Clang -- fix?
else
bffGenerator.Write(fastBuildCompilerExtraOptions);
if (conf.Platform.IsUsingClang())
{
if (isUsePrecomp)
bffGenerator.Write(Template.ConfigurationFile.PCHOptionsClang);
bffGenerator.Write(compilerOptionsClang);
if (conf.FastBuildDeoptimization != Project.Configuration.DeoptimizationWritableFiles.NoDeoptimization)
{
if (isUsePrecomp)
bffGenerator.Write(Template.ConfigurationFile.PCHOptionsDeoptimize);
bffGenerator.Write(Template.ConfigurationFile.ClangCompilerOptionsDeoptimize);
bffGenerator.Write(Template.ConfigurationFile.DeOptimizeOption);
}
}
}
if (fastBuildPreBuildDependencies.Any())
bffGenerator.Write(Template.ConfigurationFile.PreBuildDependencies);
bffGenerator.Write(Template.ConfigurationFile.EndSection);
}
if (isOutputTypeDll && !isLastSubConfig)
{
bffGenerator.Write(Template.ConfigurationFile.ObjectListBeginSection);
if (conf.Platform.IsMicrosoft())
{
bffGenerator.Write(fastBuildCompilerExtraOptions);
bffGenerator.Write(Template.ConfigurationFile.CPPCompilerOptimizationOptions);
if (isUsePrecomp)
bffGenerator.Write(Template.ConfigurationFile.PCHOptions);
bffGenerator.Write(compilerOptions);
if (conf.FastBuildDeoptimization != Project.Configuration.DeoptimizationWritableFiles.NoDeoptimization)
{
if (isUsePrecomp)
bffGenerator.Write(Template.ConfigurationFile.PCHOptionsDeoptimize);
bffGenerator.Write(fastBuildCompilerOptionsDeoptimize);
bffGenerator.Write(Template.ConfigurationFile.DeOptimizeOption);
}
}
else
{
if (isCompileAsSwiftFile)
applePlatformBff?.SetupSwiftOptions(bffGenerator);
else if (!isNASMFileSection)
clangPlatformBff?.SetupClangOptions(bffGenerator); // TODO: This checks twice if the platform supports Clang -- fix?
else
bffGenerator.Write(fastBuildCompilerExtraOptions);
if (conf.Platform.IsUsingClang())
{
if (isUsePrecomp)
bffGenerator.Write(Template.ConfigurationFile.PCHOptionsClang);
bffGenerator.Write(compilerOptionsClang);
if (conf.FastBuildDeoptimization != Project.Configuration.DeoptimizationWritableFiles.NoDeoptimization)
{
if (isUsePrecomp)
bffGenerator.Write(Template.ConfigurationFile.PCHOptionsDeoptimize);
bffGenerator.Write(Template.ConfigurationFile.ClangCompilerOptionsDeoptimize);
bffGenerator.Write(Template.ConfigurationFile.DeOptimizeOption);
}
}
// TODO: Add BFF generation for Win64 on Windows/Mac/Linux?
}
if (fastBuildPreBuildDependencies.Any())
bffGenerator.Write(Template.ConfigurationFile.PreBuildDependencies);
bffGenerator.Write(Template.ConfigurationFile.EndSection);
}
else
{
bool outputLib = false;
string beginSectionType = null;
switch (conf.Output)
{
case Project.Configuration.OutputType.AppleApp:
case Project.Configuration.OutputType.Exe:
{
if (isLastSubConfig)
{
beginSectionType = Template.ConfigurationFile.ExeDllBeginSection;
}
else
{
// in the case the lib has the flag force to be an objectlist, change the template
if (useObjectLists)
beginSectionType = Template.ConfigurationFile.ObjectListBeginSection;
else
beginSectionType = Template.ConfigurationFile.LibBeginSection;
outputLib = true;
}
}
break;
case Project.Configuration.OutputType.Dll:
{
beginSectionType = Template.ConfigurationFile.ExeDllBeginSection;
}
break;
case Project.Configuration.OutputType.Lib:
{
// in the case the lib has the flag force to be an objectlist, change the template
if (useObjectLists)
beginSectionType = Template.ConfigurationFile.ObjectListBeginSection;
else
beginSectionType = Template.ConfigurationFile.LibBeginSection;
outputLib = true;
}
break;
}
bffGenerator.Write(beginSectionType);
if (outputLib)
{
if (conf.Platform.IsMicrosoft())
{
bffGenerator.Write(fastBuildCompilerExtraOptions);
bffGenerator.Write(Template.ConfigurationFile.CPPCompilerOptimizationOptions);
if (isUsePrecomp)
bffGenerator.Write(Template.ConfigurationFile.PCHOptions);
bffGenerator.Write(compilerOptions);
if (!useObjectLists)
{
bffGenerator.Write(Template.ConfigurationFile.LibrarianAdditionalInputs);
bffGenerator.Write(Template.ConfigurationFile.LibrarianOptions);
}
if (conf.FastBuildDeoptimization != Project.Configuration.DeoptimizationWritableFiles.NoDeoptimization)
{
if (isUsePrecomp)
bffGenerator.Write(Template.ConfigurationFile.PCHOptionsDeoptimize);
bffGenerator.Write(fastBuildCompilerOptionsDeoptimize);
bffGenerator.Write(Template.ConfigurationFile.DeOptimizeOption);
}
}
else
{
if (isCompileAsSwiftFile)
applePlatformBff?.SetupSwiftOptions(bffGenerator);
else if (!isNASMFileSection)
clangPlatformBff?.SetupClangOptions(bffGenerator); // TODO: This checks twice if the platform supports Clang -- fix?
else
bffGenerator.Write(fastBuildCompilerExtraOptions);;
if (conf.Platform.IsUsingClang())
{
if (isUsePrecomp)
bffGenerator.Write(Template.ConfigurationFile.PCHOptionsClang);
bffGenerator.Write(compilerOptionsClang);
if (conf.FastBuildDeoptimization != Project.Configuration.DeoptimizationWritableFiles.NoDeoptimization)
{
if (isUsePrecomp)
bffGenerator.Write(Template.ConfigurationFile.PCHOptionsDeoptimize);
bffGenerator.Write(Template.ConfigurationFile.ClangCompilerOptionsDeoptimize);
bffGenerator.Write(Template.ConfigurationFile.DeOptimizeOption);
}
if (!useObjectLists)
{
bffGenerator.Write(Template.ConfigurationFile.LibrarianAdditionalInputs);
bffGenerator.Write(Template.ConfigurationFile.LibrarianOptionsClang);
}
}
}
if (fastBuildPreBuildDependencies.Any())
bffGenerator.Write(Template.ConfigurationFile.PreBuildDependencies);
}
else
{
platformBff.SetupExtraLinkerSettings(bffGenerator, conf, fastBuildOutputFile);
}
bffGenerator.Write(Template.ConfigurationFile.EndSection);
// Resolve node name of the prebuild dependency for PostBuildEvents.
string resolvedSectionNodeIdentifier;
if (beginSectionType == Template.ConfigurationFile.ObjectListBeginSection)
{
resolvedSectionNodeIdentifier = resolver.Resolve("[fastBuildOutputFileShortName]_objects");
}
else
{
resolvedSectionNodeIdentifier = resolver.Resolve("[fastBuildOutputFileShortName]_[fastBuildOutputType]");
}
// Convert build steps to Bff resolvable objects
var resolvableBuildSteps = UtilityMethods.GetBffNodesFromBuildSteps(postBuildEvents, new Strings(resolvedSectionNodeIdentifier));
// Resolve objects using the current project path
var resolvedBuildSteps = resolvableBuildSteps.Select(b => b.Resolve(project.RootPath, projectPath, resolver));
foreach (var buildStep in resolvedBuildSteps)
{
bffGenerator.Write(buildStep);
}
// Write Target Alias
if (isLastSubConfig)
{
string genLibName = "'" + fastBuildOutputFileShortName + "_" + outputType + "'";
using (bffGenerator.Declare("fastBuildTargetSubTargets", mustGenerateLibrary ? genLibName : UtilityMethods.FBuildFormatList(fastBuildTargetSubTargets.Values, 15)))
using (bffGenerator.Declare("fastBuildOutputFileShortName", fastBuildOutputFileShortName))
using (bffGenerator.Declare("fastBuildTargetLibraryDependencies", mustGenerateLibrary ? genLibName : UtilityMethods.FBuildFormatList(fastBuildTargetLibraryDependencies.Values, 15)))
{
bffGenerator.Write(Template.ConfigurationFile.TargetSection);
bffGenerator.Write(Template.ConfigurationFile.TargetForLibraryDependencySection);
}
}
}
}
break;
case Project.Configuration.OutputType.None:
{
// Write Target Alias
using (bffGenerator.Declare("fastBuildOutputFileShortName", fastBuildOutputFileShortName))
using (bffGenerator.Declare("fastBuildTargetSubTargets", UtilityMethods.FBuildFormatList(fastBuildTargetSubTargets.Values, 15)))
using (bffGenerator.Declare("fastBuildTargetLibraryDependencies", UtilityMethods.FBuildFormatList(fastBuildTargetLibraryDependencies.Values, 15)))
{
bffGenerator.Write(Template.ConfigurationFile.TargetSection);
if (!project.IsFastBuildAll)
bffGenerator.Write(Template.ConfigurationFile.TargetForLibraryDependencySection);
}
}
break;
}
}
scopedOptions.ForEach(scopedOption => scopedOption.Dispose());
string outputDirectory = Path.GetDirectoryName(fastBuildOutputFile);
bffGenerator.ResolveEnvironmentVariables(conf.Platform,
new VariableAssignment("ProjectName", projectName),
new VariableAssignment("outputDirectory", outputDirectory));
subConfigIndex++;
}
if (configIndex == (configurationsToBuild.Count - 1) || configurationsToBuild[configIndex + 1].Platform != conf.Platform)
{
using (bffGenerator.Declare("fastBuildDefine", GetPlatformSpecificDefine(conf.Platform)))
bffGenerator.Write(Template.ConfigurationFile.PlatformEndSection);
}
}
bffGenerator.WriteTo(bffGeneratorProject);
bffGenerator.Clear();
++configIndex;
}
foreach (string masterlessBff in confBffHasMasters.Where(x => !x.Value).Select(x => x.Key))
Builder.Instance.LogWarningLine("Bff {0} doesn't appear in any master bff, it won't be buildable.", masterlessBff + FastBuildSettings.FastBuildConfigFileExtension);
// Write all unity sections together at the beginning of the .bff just after the header.
if (_unities.Any())
{
foreach (var unityFile in _unities.Keys.OrderBy(u => u.UnityName))
{
using (bffWholeFileGenerator.Declare("unityFile", unityFile))
bffWholeFileGenerator.Write(Template.ConfigurationFile.UnitySection);
// Record the unities in the autocleanupdb to allow auto removal when they become stale.
// Note that can't record them as 'generated', since they are created by FastBuild and not by us.
int nbUnities = 1;
if (unityFile.UnityNumFiles != FileGeneratorUtilities.RemoveLineTag)
{
if (!int.TryParse(unityFile.UnityNumFiles, out nbUnities))
throw new Error("'{0}' cannot be converted to int!", unityFile.UnityNumFiles);
}
string outputPattern = unityFile.UnityOutputPattern == FileGeneratorUtilities.RemoveLineTag ? Sharpmake.Generators.FastBuild.Bff.Unity.DefaultUnityOutputPatternExtension : unityFile.UnityOutputPattern;
int wildcardIndex = outputPattern.IndexOf('*');
if (wildcardIndex == -1)
throw new Error("UnityOutputPattern must include a '*', but none was found in '{0}'!", unityFile.UnityNumFiles);
string firstStringChunk = outputPattern.Substring(0, wildcardIndex);
string lastStringChunk = outputPattern.Substring(wildcardIndex + 1);
for (int i = 1; i <= nbUnities; ++i)
{
string fullPath = Path.Combine(unityFile.UnityFullOutputPath, $"{firstStringChunk}{i}{lastStringChunk}");
Util.RecordInAutoCleanupDatabase(fullPath);
}
}
}
// Now combine all the streams.
bffGeneratorProject.WriteTo(bffWholeFileGenerator);
// remove all line that contain RemoveLineTag
bffWholeFileGenerator.RemoveTaggedLines();
// Write bff file
FileInfo bffFileInfo = new FileInfo(projectBffFile);
if (builder.Context.WriteGeneratedFile(project.GetType(), bffFileInfo, bffWholeFileGenerator))
{
Project.IncrementFastBuildGeneratedFileCount();
generatedFiles.Add(bffFileInfo.FullName);
}
else
{
Project.IncrementFastBuildUpToDateFileCount();
skipFiles.Add(bffFileInfo.FullName);
}
}