diff --git a/Sharpmake.Application/Program.cs b/Sharpmake.Application/Program.cs index 796880042..bf2eed461 100644 --- a/Sharpmake.Application/Program.cs +++ b/Sharpmake.Application/Program.cs @@ -243,6 +243,9 @@ private static int Main() CommandLine.ExecuteOnObject(platformCmdLine); platformCmdLine.Validate(); } + + CompilerFlagLookupTable.Init(); + LinkerFlagLookupTable.Init(); bool oneInstanceMutexCreated; string mutexName = string.Format("SharpmakeSingleInstanceMutex{0}", parameters.MutexSuffix); // Allow custom mutex name suffix. Useful to debug concurrently multiple sharpmake running from different branches @@ -393,7 +396,7 @@ private static int Main() if (Debugger.IsAttached) { LogWriteLine("Please look at the errors."); - Debugger.Break(); + Debugger.Break(); } } diff --git a/Sharpmake.Generators/Apple/XCodeProj.cs b/Sharpmake.Generators/Apple/XCodeProj.cs index 4786d331a..3e047df4b 100644 --- a/Sharpmake.Generators/Apple/XCodeProj.cs +++ b/Sharpmake.Generators/Apple/XCodeProj.cs @@ -46,6 +46,7 @@ private class XCodeGenerationContext : IGenerationContext public DevEnv DevelopmentEnvironment => Configuration.Compiler; public Options.ExplicitOptions Options { get; set; } = new Options.ExplicitOptions(); public IDictionary CommandLineOptions { get; set; } = new VisualStudio.ProjectOptionsGenerator.VcxprojCmdLineOptions(); + public IDictionary LinkerCommandLineOptions { get; set; } = new ProjectOptionsGenerator.VcxprojCmdLineOptions(); public string ProjectDirectoryCapitalized { get; } public string ProjectSourceCapitalized { get; } diff --git a/Sharpmake.Generators/FastBuild/Bff.cs b/Sharpmake.Generators/FastBuild/Bff.cs index 354da3106..ecfa997e2 100644 --- a/Sharpmake.Generators/FastBuild/Bff.cs +++ b/Sharpmake.Generators/FastBuild/Bff.cs @@ -42,6 +42,7 @@ private class BffGenerationContext : IBffGenerationContext public Options.ExplicitOptions Options { get; set; } = new Options.ExplicitOptions(); public IDictionary CommandLineOptions { get; set; } = new ProjectOptionsGenerator.VcxprojCmdLineOptions(); + public IDictionary LinkerCommandLineOptions { get; set; } = new ProjectOptionsGenerator.VcxprojCmdLineOptions(); public DevEnv DevelopmentEnvironment => Configuration.Compiler; diff --git a/Sharpmake.Generators/GeneratorManager.cs b/Sharpmake.Generators/GeneratorManager.cs index e48ad7354..da2f246be 100644 --- a/Sharpmake.Generators/GeneratorManager.cs +++ b/Sharpmake.Generators/GeneratorManager.cs @@ -56,6 +56,9 @@ public class GeneratorManager : IGeneratorManager private Makefile _makefileGenerator = null; public Makefile MakefileGenerator => _makefileGenerator ?? (_makefileGenerator = new Makefile()); + + private NinjaProject _ninjaProjectGenerator = null; + public NinjaProject NinjaProjectGenerator => _ninjaProjectGenerator ?? (_ninjaProjectGenerator = new NinjaProject()); #endregion // singleton @@ -114,6 +117,11 @@ public void Generate(Builder builder, BffGenerator.Generate(builder, project, configurations, projectFile, generatedFiles, skipFiles); break; } + case DevEnv.ninja: + { + NinjaProjectGenerator.Generate(builder, project, configurations, projectFile, generatedFiles, skipFiles); + break; + } default: { throw new Error("Generate called with unknown DevEnv: " + devEnv); @@ -139,34 +147,55 @@ public void Generate(Builder builder, } else { - DevEnv devEnv = configurations[0].Target.GetFragment(); - switch (devEnv) + Dictionary> devEnvToConfigs = new Dictionary>(); + + foreach (var config in configurations) { - case DevEnv.make: - { - if (configurations[0].Platform == Platform.android) - MakeApplicationGenerator.Generate(builder, solution, configurations, solutionFile, generatedFiles, skipFiles); - else - MakefileGenerator.Generate(builder, solution, configurations, solutionFile, generatedFiles, skipFiles); - break; - } - case DevEnv.vs2015: - case DevEnv.vs2017: - case DevEnv.vs2019: - case DevEnv.vs2022: - { - if (UtilityMethods.HasFastBuildConfig(configurations)) + DevEnv devEnv = config.Target.GetFragment(); + if (!devEnvToConfigs.ContainsKey(devEnv)) + { + devEnvToConfigs.Add(devEnv, new List()); + } + devEnvToConfigs[devEnv].Add(config); + } + + foreach (var devEnvAndConfigs in devEnvToConfigs) + { + DevEnv devEnv = devEnvAndConfigs.Key; + List devEnvConfigurations = devEnvAndConfigs.Value; + switch (devEnv) + { + case DevEnv.make: { - MasterBffGenerator.Generate(builder, solution, configurations, solutionFile, generatedFiles, skipFiles); + if (devEnvConfigurations[0].Platform == Platform.android) + MakeApplicationGenerator.Generate(builder, solution, devEnvConfigurations, solutionFile, generatedFiles, skipFiles); + else + MakefileGenerator.Generate(builder, solution, devEnvConfigurations, solutionFile, generatedFiles, skipFiles); + break; } + case DevEnv.vs2015: + case DevEnv.vs2017: + case DevEnv.vs2019: + case DevEnv.vs2022: + { + if (UtilityMethods.HasFastBuildConfig(devEnvConfigurations)) + { + MasterBffGenerator.Generate(builder, solution, devEnvConfigurations, solutionFile, generatedFiles, skipFiles); + } - SlnGenerator.Generate(builder, solution, configurations, solutionFile, generatedFiles, skipFiles); - break; - } - default: - { - throw new Error("Generate called with unknown DevEnv: " + devEnv); - } + SlnGenerator.Generate(builder, solution, devEnvConfigurations, solutionFile, generatedFiles, skipFiles); + break; + } + case DevEnv.ninja: + { + NinjaProjectGenerator.Generate(builder, solution, devEnvConfigurations, solutionFile, generatedFiles, skipFiles); + break; + } + default: + { + throw new Error("Generate called with unknown DevEnv: " + devEnv); + } + } } } } diff --git a/Sharpmake.Generators/Generic/GenericProjectOptionsGenerator.cs b/Sharpmake.Generators/Generic/GenericProjectOptionsGenerator.cs new file mode 100644 index 000000000..be42fab7e --- /dev/null +++ b/Sharpmake.Generators/Generic/GenericProjectOptionsGenerator.cs @@ -0,0 +1,2732 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.IO; + +namespace Sharpmake.Generators.Generic +{ + class GenericProjectOptionsGenerator + { + private class ProjectOptionsGenerationContext + { + private readonly Project.Configuration _projectConfiguration; + + public string OutputDirectoryRelative { get; set; } + public string OutputLibraryDirectoryRelative { get; set; } + public string IntermediateDirectoryRelative { get; set; } + public bool HasClrSupport { get; set; } + public EnvironmentVariableResolver Resolver { get; } + public string PlatformLibraryExtension { get; } + public string PlatformOutputLibraryExtension { get; } + public string PlatformPrefixExtension { get; } + public IPlatformDescriptor PlatformDescriptor { get; } + public VisualStudio.IPlatformVcxproj PlatformVcxproj { get; } + + public ProjectOptionsGenerationContext(Project.Configuration conf, params VariableAssignment[] resolverParams) + { + _projectConfiguration = conf; + Resolver = PlatformRegistry.Get(conf.Platform).GetPlatformEnvironmentResolver(resolverParams); + + PlatformDescriptor = PlatformRegistry.Get(conf.Platform); + PlatformVcxproj = PlatformRegistry.Get(conf.Platform); + + string platformLibraryExtension = ".lib"; + string platformOutputLibraryExtension = ".lib"; + string platformPrefixExtension = string.Empty; + + PlatformLibraryExtension = platformLibraryExtension; + PlatformOutputLibraryExtension = platformOutputLibraryExtension; + PlatformPrefixExtension = platformPrefixExtension; + } + } + + internal class GenericCmdLineOptions : Dictionary + { + } + + private static string GetPlatformStringDefineQuot(Platform platform) + { + return @"""; + } + + private string GetPlatformStringResourceDefineQuote(Platform platform) + { + return @"\""; + } + + internal void GenerateOptions(IGenerationContext context) + { + var optionsContext = new ProjectOptionsGenerationContext(context.Configuration, + new VariableAssignment("project", context.Project), + new VariableAssignment("target", context.Configuration.Target), + new VariableAssignment("conf", context.Configuration)); + + GenerateGeneralOptions(context, optionsContext); + + GenerateAdvancedOptions(context, optionsContext); + + GenerateCompilerOptions(context, optionsContext); + + GenerateLibrarianOptions(context, optionsContext); + + GenerateLinkerOptions(context, optionsContext); + + GenerateManifestToolOptions(context, optionsContext); + + GenerateLLVMOptions(context, optionsContext); + + GeneratePostBuildOptions(context, optionsContext); + } + + private void GenerateGeneralOptions(IGenerationContext context, ProjectOptionsGenerationContext optionsContext) + { + // Default defines, includes, libraries... + context.Options.ExplicitDefines.AddRange(optionsContext.PlatformVcxproj.GetImplicitlyDefinedSymbols(context)); + + // Set whatever VS needs to delete when you run the Clean command. + optionsContext.PlatformVcxproj.SetupDeleteExtensionsOnCleanOptions(context); + + if (context.Configuration.DefaultOption == Options.DefaultTarget.Debug) + { + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.RuntimeLibrary.MultiThreaded, () => { }), + Options.Option(Options.Vc.Compiler.RuntimeLibrary.MultiThreadedDebug, () => context.Options.ExplicitDefines.Add("_DEBUG")), + Options.Option(Options.Vc.Compiler.RuntimeLibrary.MultiThreadedDLL, () => { }), + Options.Option(Options.Vc.Compiler.RuntimeLibrary.MultiThreadedDebugDLL, () => context.Options.ExplicitDefines.Add("_DEBUG")) + ); + } + else // Release + { + context.Options.ExplicitDefines.Add("NDEBUG"); + } + + //Output + // Application Project.ProjectConfiguration.ConfigurationType="1" + // Dll Project.ProjectConfiguration.ConfigurationType="2" /D "_WINDLL" /DLL + // Lib Project.ProjectConfiguration.ConfigurationType="4" + SelectConfigurationTypeOption(context); + + context.Options.ExplicitDefines.AddRange(optionsContext.PlatformVcxproj.GetImplicitlyDefinedSymbols(context)); + + optionsContext.OutputDirectoryRelative = Util.PathGetRelative(context.ProjectDirectory, context.Configuration.TargetPath); + optionsContext.OutputLibraryDirectoryRelative = Util.PathGetRelative(context.ProjectDirectory, context.Configuration.TargetLibraryPath); + if (context.Configuration.Output == Project.Configuration.OutputType.Lib) + context.Options["OutputDirectory"] = optionsContext.OutputLibraryDirectoryRelative; + else if (context.Configuration.Output != Project.Configuration.OutputType.None) + context.Options["OutputDirectory"] = optionsContext.OutputDirectoryRelative; + else + context.Options["OutputDirectory"] = FileGeneratorUtilities.RemoveLineTag; + + //IntermediateDirectory + optionsContext.IntermediateDirectoryRelative = Util.PathGetRelative(context.ProjectDirectory, context.Configuration.IntermediatePath); + context.Options["IntermediateDirectory"] = context.Configuration.Output != Project.Configuration.OutputType.None ? optionsContext.IntermediateDirectoryRelative : FileGeneratorUtilities.RemoveLineTag; + + if (!string.IsNullOrEmpty(context.Configuration.LayoutDir)) + context.Options["LayoutDir"] = Util.PathGetRelative(context.ProjectDirectory, context.Configuration.LayoutDir); + else + context.Options["LayoutDir"] = FileGeneratorUtilities.RemoveLineTag; + context.Options["PullMappingFile"] = !string.IsNullOrEmpty(context.Configuration.PullMappingFile) ? context.Configuration.PullMappingFile : FileGeneratorUtilities.RemoveLineTag; + context.Options["PullTemporaryFolder"] = !string.IsNullOrEmpty(context.Configuration.PullTemporaryFolder) ? context.Configuration.PullTemporaryFolder : FileGeneratorUtilities.RemoveLineTag; + + if (!string.IsNullOrEmpty(context.Configuration.LayoutExtensionFilter)) + context.Options["LayoutExtensionFilter"] = context.Configuration.LayoutExtensionFilter; + else + context.Options["LayoutExtensionFilter"] = FileGeneratorUtilities.RemoveLineTag; + + // This should normally be set with the KitsRootPaths class, but this allows the coder to force a platform version. + var winTargetPlatformVersionOptionActions = new List(); + foreach (Options.Vc.General.WindowsTargetPlatformVersion winVersion in Enum.GetValues(typeof(Options.Vc.General.WindowsTargetPlatformVersion))) + winTargetPlatformVersionOptionActions.Add(Options.Option(winVersion, () => { context.Options["WindowsTargetPlatformVersion"] = winVersion.ToVersionString(); })); + context.SelectOptionWithFallback( + () => { context.Options["WindowsTargetPlatformVersion"] = FileGeneratorUtilities.RemoveLineTag; }, + winTargetPlatformVersionOptionActions.ToArray() + ); + } + + private static void SelectConfigurationTypeOption(IGenerationContext context) + { + context.CommandLineOptions["ConfigurationType"] = FileGeneratorUtilities.RemoveLineTag; + context.Options["ConfigurationType"] = FileGeneratorUtilities.RemoveLineTag; + switch (context.Configuration.Output) + { + case Project.Configuration.OutputType.Exe: + case Project.Configuration.OutputType.DotNetConsoleApp: + case Project.Configuration.OutputType.DotNetWindowsApp: + { + context.Options["ConfigurationType"] = context.Configuration.IsFastBuild ? "Makefile" : "Application"; + } + break; + case Project.Configuration.OutputType.Dll: + case Project.Configuration.OutputType.DotNetClassLibrary: + { + if (!PlatformRegistry.Get(context.Configuration.Platform).HasSharedLibrarySupport) + { + throw new Error($"Current platform {context.Configuration.Platform} doesn't support shared lib output type: Project {context.Project.GetType()} conf {context.Configuration.Target}"); + } + context.Options["ConfigurationType"] = context.Configuration.IsFastBuild ? "Makefile" : "DynamicLibrary"; + } + break; + case Project.Configuration.OutputType.Lib: + context.Options["ConfigurationType"] = context.Configuration.IsFastBuild ? "Makefile" : "StaticLibrary"; + break; + case Project.Configuration.OutputType.Utility: + context.Options["ConfigurationType"] = "Utility"; + break; + case Project.Configuration.OutputType.None: + context.Options["ConfigurationType"] = context.Configuration.IsFastBuild || context.Configuration.CustomBuildSettings != null ? "Makefile" : FileGeneratorUtilities.RemoveLineTag; + break; + } + } + + private void GenerateAdvancedOptions(IGenerationContext context, ProjectOptionsGenerationContext optionsContext) + { + context.SelectOption + ( + Options.Option(Options.Vc.Advanced.CopyLocalDeploymentContent.Enable, () => { context.Options["CopyLocalDeploymentContent"] = "true"; }), + Options.Option(Options.Vc.Advanced.CopyLocalDeploymentContent.Disable, () => { context.Options["CopyLocalDeploymentContent"] = FileGeneratorUtilities.RemoveLineTag; }) + ); + + context.SelectOption + ( + Options.Option(Options.Vc.Advanced.CopyLocalProjectReference.Enable, () => { context.Options["CopyLocalProjectReference"] = "true"; }), + Options.Option(Options.Vc.Advanced.CopyLocalProjectReference.Disable, () => { context.Options["CopyLocalProjectReference"] = FileGeneratorUtilities.RemoveLineTag; }) + ); + + context.SelectOption + ( + Options.Option(Options.Vc.Advanced.CopyLocalDebugSymbols.Enable, () => { context.Options["CopyLocalDebugSymbols"] = "true"; }), + Options.Option(Options.Vc.Advanced.CopyLocalDebugSymbols.Disable, () => { context.Options["CopyLocalDebugSymbols"] = FileGeneratorUtilities.RemoveLineTag; }) + ); + + context.SelectOption + ( + Options.Option(Options.Vc.Advanced.CopyCppRuntimeToOutputDir.Enable, () => { context.Options["CopyCppRuntimeToOutputDir"] = "true"; }), + Options.Option(Options.Vc.Advanced.CopyCppRuntimeToOutputDir.Disable, () => { context.Options["CopyCppRuntimeToOutputDir"] = FileGeneratorUtilities.RemoveLineTag; }) + ); + } + + private void GenerateCompilerOptions(IGenerationContext context, ProjectOptionsGenerationContext optionsContext) + { + Compiler compiler = context.Configuration.Target.GetFragment(); + + switch (compiler) + { + case Compiler.MSVC: + GenerateMSVCCompilerOptions(context, optionsContext); + break; + case Compiler.Clang: + GenerateClangCompilerOptions(context, optionsContext); + break; + case Compiler.GCC: + GenerateGccCompilerOptions(context, optionsContext); + break; + default: + throw new Error("Unknown compiler used for options generation"); + } + } + + private void GenerateMSVCCompilerOptions(IGenerationContext context, ProjectOptionsGenerationContext optionsContext) + { + var forcedIncludes = new Strings(); + + bool useClangCl = Options.GetObject(context.Configuration).IsLLVMToolchain() && + Options.GetObject(context.Configuration) == Options.Vc.LLVM.UseClangCl.Enable; + + if (!context.Configuration.IsFastBuild) + { + // support of PCH requires them to be set as ForceIncludes with ClangCl + if (useClangCl) + { + forcedIncludes.Add(context.Configuration.PrecompHeader); + } + } + + forcedIncludes.AddRange(context.Configuration.ForcedIncludes); + + if (forcedIncludes.Count > 0) + { + context.Options["ForcedIncludeFiles"] = forcedIncludes.JoinStrings(";"); + + // save the vanilla value without the LLVM workaround for reuse later + if (forcedIncludes.Count != context.Configuration.ForcedIncludes.Count) + context.Options["ForcedIncludeFilesVanilla"] = context.Configuration.ForcedIncludes.JoinStrings(";"); + + StringBuilder result = new StringBuilder(); + foreach (var forcedInclude in forcedIncludes) + result.Append(@"/FI""" + forcedInclude + @""" "); + result.Remove(result.Length - 1, 1); + context.CommandLineOptions["ForcedIncludeFiles"] = result.ToString(); + } + else + { + context.Options["ForcedIncludeFiles"] = FileGeneratorUtilities.RemoveLineTag; + context.CommandLineOptions["ForcedIncludeFiles"] = FileGeneratorUtilities.RemoveLineTag; + } + + if (useClangCl) + { + context.Options["CharacterSet"] = FileGeneratorUtilities.RemoveLineTag; + context.CommandLineOptions["CharacterSet"] = FileGeneratorUtilities.RemoveLineTag; + + context.Options["LanguageStandard"] = FileGeneratorUtilities.RemoveLineTag; + context.CommandLineOptions["LanguageStandard"] = FileGeneratorUtilities.RemoveLineTag; + + //https://clang.llvm.org/docs/CommandGuide/clang.html + context.SelectOption + ( + Options.Option(Options.Clang.Compiler.CppLanguageStandard.Default, () => { context.Options["ClangCppLanguageStandard"] = FileGeneratorUtilities.RemoveLineTag; context.Options["CppLanguageStandard"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Clang.Compiler.CppLanguageStandard.Cpp98, () => { context.Options["ClangCppLanguageStandard"] = "-std=c++98"; context.Options["CppLanguageStandard"] = "c++98"; }), + Options.Option(Options.Clang.Compiler.CppLanguageStandard.Cpp11, () => { context.Options["ClangCppLanguageStandard"] = "-std=c++11"; context.Options["CppLanguageStandard"] = "c++11"; }), + Options.Option(Options.Clang.Compiler.CppLanguageStandard.Cpp14, () => { context.Options["ClangCppLanguageStandard"] = "-std=c++14"; context.Options["CppLanguageStandard"] = "c++14"; }), + Options.Option(Options.Clang.Compiler.CppLanguageStandard.Cpp17, () => { context.Options["ClangCppLanguageStandard"] = "-std=c++17"; context.Options["CppLanguageStandard"] = "c++17"; }), + Options.Option(Options.Clang.Compiler.CppLanguageStandard.Cpp2a, () => { context.Options["ClangCppLanguageStandard"] = "-std=c++2a"; context.Options["CppLanguageStandard"] = "c++2a"; }), + Options.Option(Options.Clang.Compiler.CppLanguageStandard.GnuCpp98, () => { context.Options["ClangCppLanguageStandard"] = "-std=gnu++98"; context.Options["CppLanguageStandard"] = "gnu++98"; }), + Options.Option(Options.Clang.Compiler.CppLanguageStandard.GnuCpp11, () => { context.Options["ClangCppLanguageStandard"] = "-std=gnu++11"; context.Options["CppLanguageStandard"] = "gnu++11"; }), + Options.Option(Options.Clang.Compiler.CppLanguageStandard.GnuCpp14, () => { context.Options["ClangCppLanguageStandard"] = "-std=gnu++14"; context.Options["CppLanguageStandard"] = "gnu++14"; }), + Options.Option(Options.Clang.Compiler.CppLanguageStandard.GnuCpp17, () => { context.Options["ClangCppLanguageStandard"] = "-std=gnu++17"; context.Options["CppLanguageStandard"] = "gnu++17"; }), + Options.Option(Options.Clang.Compiler.CppLanguageStandard.GnuCpp2a, () => { context.Options["ClangCppLanguageStandard"] = "-std=gnu++2a"; context.Options["CppLanguageStandard"] = "gnu++2a"; }) + ); + + context.SelectOption + ( + Options.Option(Options.Clang.Compiler.CLanguageStandard.Default, () => { context.Options["ClangCLanguageStandard"] = FileGeneratorUtilities.RemoveLineTag; context.Options["CLanguageStandard"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Clang.Compiler.CLanguageStandard.C89, () => { context.Options["ClangCLanguageStandard"] = "-std=c89"; context.Options["CLanguageStandard"] = "c89"; }), + Options.Option(Options.Clang.Compiler.CLanguageStandard.C90, () => { context.Options["ClangCLanguageStandard"] = "-std=c90"; context.Options["CLanguageStandard"] = "c90"; }), + Options.Option(Options.Clang.Compiler.CLanguageStandard.C99, () => { context.Options["ClangCLanguageStandard"] = "-std=c99"; context.Options["CLanguageStandard"] = "c99"; }), + Options.Option(Options.Clang.Compiler.CLanguageStandard.C11, () => { context.Options["ClangCLanguageStandard"] = "-std=c11"; context.Options["CLanguageStandard"] = "c11"; }), + Options.Option(Options.Clang.Compiler.CLanguageStandard.C17, () => { context.Options["ClangCLanguageStandard"] = "-std=c17"; context.Options["CLanguageStandard"] = "c17"; }), + Options.Option(Options.Clang.Compiler.CLanguageStandard.GnuC89, () => { context.Options["ClangCLanguageStandard"] = "-std=gnu89"; context.Options["CLanguageStandard"] = "gnu89"; }), + Options.Option(Options.Clang.Compiler.CLanguageStandard.GnuC90, () => { context.Options["ClangCLanguageStandard"] = "-std=gnu90"; context.Options["CLanguageStandard"] = "gnu90"; }), + Options.Option(Options.Clang.Compiler.CLanguageStandard.GnuC99, () => { context.Options["ClangCLanguageStandard"] = "-std=gnu99"; context.Options["CLanguageStandard"] = "gnu99"; }), + Options.Option(Options.Clang.Compiler.CLanguageStandard.GnuC11, () => { context.Options["ClangCLanguageStandard"] = "-std=gnu11"; context.Options["CLanguageStandard"] = "gnu11"; }), + Options.Option(Options.Clang.Compiler.CLanguageStandard.GnuC17, () => { context.Options["ClangCLanguageStandard"] = "-std=gnu17"; context.Options["CLanguageStandard"] = "gnu17"; }) + ); + + context.CommandLineOptions["CppLanguageStd"] = context.Options["ClangCppLanguageStandard"]; + context.CommandLineOptions["CLanguageStd"] = context.Options["ClangCLanguageStandard"]; + } + else + { + context.Options["ClangCppLanguageStandard"] = FileGeneratorUtilities.RemoveLineTag; + context.CommandLineOptions["ClangCppLanguageStandard"] = FileGeneratorUtilities.RemoveLineTag; + + //Options.Vc.General.CharacterSet. + // NotSet CharacterSet="0" + // UseUnicodeCharaterSet Project.ProjectConfiguration.CharacterSet="1" /D "_UNICODE" /D "UNICODE" + // UseMultiByteCharaterSet Project.ProjectConfiguration.CharacterSet="2" /D "_MBCS" + context.SelectOption + ( + Options.Option(Options.Vc.General.CharacterSet.Default, () => { context.Options["CharacterSet"] = "NotSet"; context.CommandLineOptions["CharacterSet"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.General.CharacterSet.Unicode, () => { context.Options["CharacterSet"] = "Unicode"; context.CommandLineOptions["CharacterSet"] = @"/D""_UNICODE"" /D""UNICODE"""; }), + Options.Option(Options.Vc.General.CharacterSet.MultiByte, () => { context.Options["CharacterSet"] = "MultiByte"; context.CommandLineOptions["CharacterSet"] = @"/D""_MBCS"""; }) + ); + + //Options.Vc.Compiler.CppLanguageStandard. + // CPP98 LanguageStandard="" + // CPP11 LanguageStandard="" + // CPP14 LanguageStandard="stdcpp14" /std:c++14 + // CPP17 LanguageStandard="stdcpp17" /std:c++17 + // GNU98 LanguageStandard="" + // GNU11 LanguageStandard="" + // GNU14 LanguageStandard="stdcpp14" /std:c++14 + // GNU17 LanguageStandard="stdcpp17" /std:c++17 + // Latest LanguageStandard="stdcpplatest" /std:c++latest + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP98, () => { context.Options["LanguageStandard"] = FileGeneratorUtilities.RemoveLineTag; context.CommandLineOptions["LanguageStandard"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP11, () => { context.Options["LanguageStandard"] = FileGeneratorUtilities.RemoveLineTag; context.CommandLineOptions["LanguageStandard"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP14, () => { context.Options["LanguageStandard"] = "stdcpp14"; context.CommandLineOptions["LanguageStandard"] = "/std:c++14"; }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP17, () => { context.Options["LanguageStandard"] = "stdcpp17"; context.CommandLineOptions["LanguageStandard"] = "/std:c++17"; }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP20, () => { context.Options["LanguageStandard"] = "stdcpp20"; context.CommandLineOptions["LanguageStandard"] = "/std:c++20"; }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.GNU98, () => { context.Options["LanguageStandard"] = FileGeneratorUtilities.RemoveLineTag; context.CommandLineOptions["LanguageStandard"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.GNU11, () => { context.Options["LanguageStandard"] = FileGeneratorUtilities.RemoveLineTag; context.CommandLineOptions["LanguageStandard"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.GNU14, () => { context.Options["LanguageStandard"] = "stdcpp14"; context.CommandLineOptions["LanguageStandard"] = "/std:c++14"; }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.GNU17, () => { context.Options["LanguageStandard"] = "stdcpp17"; context.CommandLineOptions["LanguageStandard"] = "/std:c++17"; }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.Latest, () => { context.Options["LanguageStandard"] = "stdcpplatest"; context.CommandLineOptions["LanguageStandard"] = "/std:c++latest"; }) + ); + + //Options.Vc.Compiler.CLanguageStandard. + // Legacy LanguageStandard_C="" + // C11 LanguageStandard_C="stdc11" /std:c11 + // C17 LanguageStandard_C="stdc17" /std:c17 + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.CLanguageStandard.Legacy, () => { context.Options["LanguageStandard_C"] = FileGeneratorUtilities.RemoveLineTag; context.CommandLineOptions["LanguageStandard_C"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Compiler.CLanguageStandard.C11, () => { context.Options["LanguageStandard_C"] = "stdc11"; context.CommandLineOptions["LanguageStandard_C"] = "/std:c11"; }), + Options.Option(Options.Vc.Compiler.CLanguageStandard.C17, () => { context.Options["LanguageStandard_C"] = "stdc17"; context.CommandLineOptions["LanguageStandard_C"] = "/std:c17"; }) + ); + } + + // MSVC NMake IntelliSence options + + context.Options["AdditionalOptions"] = (context.Configuration.CustomBuildSettings is null) ? FileGeneratorUtilities.RemoveLineTag : context.Configuration.CustomBuildSettings.AdditionalOptions; + + string cppLanguageStd = null; + if (context.Configuration.CustomBuildSettings is null || context.Configuration.CustomBuildSettings.AutoConfigure) + { + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP98, () => { }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP11, () => { }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP14, () => { cppLanguageStd = "/std:c++14"; }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP17, () => { cppLanguageStd = "/std:c++17"; }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP20, () => { cppLanguageStd = "/std:c++20"; }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.GNU98, () => { }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.GNU11, () => { }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.GNU14, () => { cppLanguageStd = "/std:c++14"; }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.GNU17, () => { cppLanguageStd = "/std:c++17"; }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.Latest, () => { cppLanguageStd = "/std:c++latest"; }) + ); + } + + if (!string.IsNullOrEmpty(cppLanguageStd)) + { + if (string.IsNullOrEmpty(context.Options["AdditionalOptions"]) || context.Options["AdditionalOptions"] == FileGeneratorUtilities.RemoveLineTag) + context.Options["AdditionalOptions"] = cppLanguageStd; + else + context.Options["AdditionalOptions"] += $" {cppLanguageStd}"; + } + else if (string.IsNullOrEmpty(context.Options["AdditionalOptions"])) + { + context.Options["AdditionalOptions"] = FileGeneratorUtilities.RemoveLineTag; + } + + // Compiler section + + context.SelectOption + ( + Options.Option(Options.Vc.General.TranslateIncludes.Enable, () => { context.Options["TranslateIncludes"] = "true"; context.CommandLineOptions["TranslateIncludes"] = "/translateInclude"; }), + Options.Option(Options.Vc.General.TranslateIncludes.Disable, () => { context.Options["TranslateIncludes"] = FileGeneratorUtilities.RemoveLineTag; context.CommandLineOptions["TranslateIncludes"] = FileGeneratorUtilities.RemoveLineTag; }) + ); + + //Options.Vc.General.CommonLanguageRuntimeSupport. + context.SelectOption + ( + Options.Option(Options.Vc.General.CommonLanguageRuntimeSupport.NoClrSupport, () => { context.Options["CLRSupport"] = FileGeneratorUtilities.RemoveLineTag; context.CommandLineOptions["CLRSupport"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.General.CommonLanguageRuntimeSupport.ClrSupport, () => { context.Options["CLRSupport"] = "true"; context.CommandLineOptions["CLRSupport"] = "/clr"; }), + Options.Option(Options.Vc.General.CommonLanguageRuntimeSupport.PureMsilClrSupport, () => { context.Options["CLRSupport"] = "Pure"; context.CommandLineOptions["CLRSupport"] = "/clr:pure"; }), + Options.Option(Options.Vc.General.CommonLanguageRuntimeSupport.SafeMsilClrSupport, () => { context.Options["CLRSupport"] = "Safe"; context.CommandLineOptions["CLRSupport"] = "/clr:safe"; }) + ); + + context.SelectOption + ( + Options.Option(Options.Vc.General.MfcSupport.UseMfcStdWin, () => { context.Options["UseOfMfc"] = FileGeneratorUtilities.RemoveLineTag; context.CommandLineOptions["UseOfMfc"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.General.MfcSupport.UseMfcStatic, () => { context.Options["UseOfMfc"] = "Static"; context.CommandLineOptions["UseOfMfc"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.General.MfcSupport.UseMfcDynamic, () => { context.Options["UseOfMfc"] = "Dynamic"; context.CommandLineOptions["UseOfMfc"] = FileGeneratorUtilities.RemoveLineTag; }) + ); + + //Options.Vc.General.WholeProgramOptimization. + // NoWholeProgramOptimization WholeProgramOptimization="0" + // UseLinkTimeCodeGeneration WholeProgramOptimization="1" /GL /LTCG + // ProfileGuidedOptimizationInstrument WholeProgramOptimization="2" /GL /LTCG:PGINSTRUMENT + // ProfileGuidedOptimizationOptimize WholeProgramOptimization="3" /GL /LTCG:PGOPTIMIZE /PGD:"f:\coding\helloworld\helloworld\Debug\hellochange.pgd" + // ProfileGuidedOptimizationUpdate WholeProgramOptimization="3" /GL /LTCG:PGUPDATE /PGD:"f:\coding\helloworld\helloworld\Debug\hellochange.pgd" + context.SelectOption + ( + Options.Option(Options.Vc.General.WholeProgramOptimization.Disable, () => { context.Options["WholeProgramOptimization"] = "false"; context.Options["CompilerWholeProgramOptimization"] = "false"; context.CommandLineOptions["CompilerWholeProgramOptimization"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.General.WholeProgramOptimization.LinkTime, () => { context.Options["WholeProgramOptimization"] = "true"; context.Options["CompilerWholeProgramOptimization"] = "true"; context.CommandLineOptions["CompilerWholeProgramOptimization"] = "/GL"; }), + Options.Option(Options.Vc.General.WholeProgramOptimization.Instrument, () => { context.Options["WholeProgramOptimization"] = "PGInstrument"; context.Options["CompilerWholeProgramOptimization"] = "true"; context.CommandLineOptions["CompilerWholeProgramOptimization"] = "/GL"; }), + Options.Option(Options.Vc.General.WholeProgramOptimization.Optimize, () => { context.Options["WholeProgramOptimization"] = "PGOptimize"; context.Options["CompilerWholeProgramOptimization"] = "true"; context.CommandLineOptions["CompilerWholeProgramOptimization"] = "/GL"; }), + Options.Option(Options.Vc.General.WholeProgramOptimization.Update, () => { context.Options["WholeProgramOptimization"] = "PGUpdate"; context.Options["CompilerWholeProgramOptimization"] = "true"; context.CommandLineOptions["CompilerWholeProgramOptimization"] = "/GL"; }) + ); + + optionsContext.PlatformVcxproj.SelectApplicationFormatOptions(context); + optionsContext.PlatformVcxproj.SelectBuildType(context); + + // Visual C++ Directories + { + // Path to use when searching for executable files while building a VC++ project. Corresponds to environment variable PATH. + context.Options["ExecutablePath"] = FileGeneratorUtilities.RemoveLineTag; + + // Path to use when searching for include files while building a VC++ project. Corresponds to environment variable INCLUDE. + context.Options["IncludePath"] = FileGeneratorUtilities.RemoveLineTag; + + // Vs2019+: Path to treat as external/system during compilation and skip in build up-to-date check. + context.Options["ExternalIncludePath"] = FileGeneratorUtilities.RemoveLineTag; + + // Path to use when searching for metadata files while building a VC++ project. Corresponds to environment variable LIBPATH. + context.Options["ReferencePath"] = FileGeneratorUtilities.RemoveLineTag; + + // Path to use when searching for library files while building a VC++ project. Corresponds to environment variable LIB. + context.Options["LibraryPath"] = FileGeneratorUtilities.RemoveLineTag; + + // Path to use when searching for winmd metadata files while building a VC++ project. Gets concatenated with 'Reference Directories' into LIBPATH. + context.Options["LibraryWPath"] = FileGeneratorUtilities.RemoveLineTag; + + // Path to use when searching for source files to use for Intellisense. + context.Options["SourcePath"] = FileGeneratorUtilities.RemoveLineTag; + + // Path to skip when searching for scan dependencies. + context.Options["ExcludePath"] = FileGeneratorUtilities.RemoveLineTag; + + // One or more directories to automatically add to the include path in the referencing projects. + context.Options["PublicIncludeDirectories"] = FileGeneratorUtilities.RemoveLineTag; + + // Specifies if directories or all project header files should be automatically added to the include path in the referencing projects. + context.Options["AllProjectIncludesArePublic"] = FileGeneratorUtilities.RemoveLineTag; + + // One or more this project directories containing c++ module and/or header unit sources to make automatically available in the referencing projects. + context.Options["PublicModuleDirectories"] = FileGeneratorUtilities.RemoveLineTag; + + // Specifies if all project modules and header units should be automatically available in the referencing projects. + context.Options["AllProjectBMIsArePublic"] = FileGeneratorUtilities.RemoveLineTag; + } + + context.Options["AdditionalUsingDirectories"] = FileGeneratorUtilities.RemoveLineTag; + optionsContext.PlatformVcxproj.SetupSdkOptions(context); + + bool writeResourceCompileTag = optionsContext.PlatformVcxproj.GetResourceIncludePaths(context).Any(); + + //Resource Compiler ShowProgress + // No ShowProgress="false" + // Yes ShowProgress="true" + context.SelectOption + ( + Options.Option(Options.Vc.ResourceCompiler.ShowProgress.No, () => { context.Options["ResourceCompilerShowProgress"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.ResourceCompiler.ShowProgress.Yes, () => { context.Options["ResourceCompilerShowProgress"] = "true"; writeResourceCompileTag = true; }) + ); + + // Options.Vc.ResourceCompiler.PreprocessorDefinitions + Strings resourcedefines = Options.GetStrings(context.Configuration); + if (resourcedefines.Any()) + { + context.Options["ResourcePreprocessorDefinitions"] = resourcedefines.JoinStrings(";").Replace(@"""", GetPlatformStringResourceDefineQuote(context.Configuration.Platform)); + writeResourceCompileTag = true; + } + else + { + context.Options["ResourcePreprocessorDefinitions"] = FileGeneratorUtilities.RemoveLineTag; + } + + context.Options["ResourceCompileTag"] = writeResourceCompileTag ? string.Empty : FileGeneratorUtilities.RemoveLineTag; + + //Options.Vc.General.DebugInformation. + // Disabled Project.ProjectConfiguration.Tool.DebugInformationFormat="0" + // C7Compatible Project.ProjectConfiguration.Tool.DebugInformationFormat="1" /Z7 + // ProgramDatabase Project.ProjectConfiguration.Tool.DebugInformationFormat="3" /Zi + // ProgramDatabaseForEditAndContinue Project.ProjectConfiguration.Tool.DebugInformationFormat="4" /ZI + + SelectDebugInformationOption(context, optionsContext); + + context.SelectOption + ( + Options.Option(Options.Vc.General.UseDebugLibraries.Disabled, () => { context.Options["UseDebugLibraries"] = "false"; }), + Options.Option(Options.Vc.General.UseDebugLibraries.Enabled, () => { context.Options["UseDebugLibraries"] = "true"; }) + ); + + //Options.Vc.General.WarningLevel. + // Level0 Project.ProjectConfiguration.Tool.WarningLevel="0" /W0 + // Level1 Project.ProjectConfiguration.Tool.WarningLevel="1" /W1 + // Level2 Project.ProjectConfiguration.Tool.WarningLevel="2" /W2 + // Level3 Project.ProjectConfiguration.Tool.WarningLevel="3" /W3 + // Level4 Project.ProjectConfiguration.Tool.WarningLevel="4" /W4 + context.SelectOption + ( + Options.Option(Options.Vc.General.WarningLevel.Level0, () => { context.Options["WarningLevel"] = "TurnOffAllWarnings"; context.CommandLineOptions["WarningLevel"] = "/W0"; }), + Options.Option(Options.Vc.General.WarningLevel.Level1, () => { context.Options["WarningLevel"] = "Level1"; context.CommandLineOptions["WarningLevel"] = "/W1"; }), + Options.Option(Options.Vc.General.WarningLevel.Level2, () => { context.Options["WarningLevel"] = "Level2"; context.CommandLineOptions["WarningLevel"] = "/W2"; }), + Options.Option(Options.Vc.General.WarningLevel.Level3, () => { context.Options["WarningLevel"] = "Level3"; context.CommandLineOptions["WarningLevel"] = "/W3"; }), + Options.Option(Options.Vc.General.WarningLevel.Level4, () => { context.Options["WarningLevel"] = "Level4"; context.CommandLineOptions["WarningLevel"] = "/W4"; }), + Options.Option(Options.Vc.General.WarningLevel.EnableAllWarnings, () => { context.Options["WarningLevel"] = "EnableAllWarnings"; context.CommandLineOptions["WarningLevel"] = "/Wall"; }) + ); + + //Options.Vc.General.TreatWarnigAsError. + // Disable WarnAsError="false" + // Enable WarnAsError="true" /WX + context.SelectOption + ( + Options.Option(Options.Vc.General.TreatWarningsAsErrors.Disable, () => { context.Options["TreatWarningAsError"] = "false"; context.CommandLineOptions["TreatWarningAsError"] = "/WX-"; }), + Options.Option(Options.Vc.General.TreatWarningsAsErrors.Enable, () => { context.Options["TreatWarningAsError"] = "true"; context.CommandLineOptions["TreatWarningAsError"] = "/WX"; }) + ); + + context.SelectOption + ( + Options.Option(Options.Vc.General.DiagnosticsFormat.Classic, () => { context.Options["DiagnosticsFormat"] = FileGeneratorUtilities.RemoveLineTag; context.CommandLineOptions["DiagnosticsFormat"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.General.DiagnosticsFormat.Caret, () => { context.Options["DiagnosticsFormat"] = "Caret"; context.CommandLineOptions["DiagnosticsFormat"] = "/diagnostics:caret"; }), + Options.Option(Options.Vc.General.DiagnosticsFormat.ColumnInfo, () => { context.Options["DiagnosticsFormat"] = "Column"; context.CommandLineOptions["DiagnosticsFormat"] = "/diagnostics:column"; }) + ); + + context.SelectOption + ( + Options.Option(Options.Vc.General.TreatAngleIncludeAsExternal.Enable, () => { context.Options["TreatAngleIncludeAsExternal"] = "true"; context.CommandLineOptions["TreatAngleIncludeAsExternal"] = "/external:anglebrackets"; }), + Options.Option(Options.Vc.General.TreatAngleIncludeAsExternal.Disable, () => { context.Options["TreatAngleIncludeAsExternal"] = FileGeneratorUtilities.RemoveLineTag; context.CommandLineOptions["TreatAngleIncludeAsExternal"] = FileGeneratorUtilities.RemoveLineTag; }) + ); + + context.SelectOption + ( + Options.Option(Options.Vc.General.ExternalWarningLevel.Level0, () => { context.Options["ExternalWarningLevel"] = "TurnOffAllWarnings"; context.CommandLineOptions["ExternalWarningLevel"] = "/external:W0"; }), + Options.Option(Options.Vc.General.ExternalWarningLevel.Level1, () => { context.Options["ExternalWarningLevel"] = "Level1"; context.CommandLineOptions["ExternalWarningLevel"] = "/external:W1"; }), + Options.Option(Options.Vc.General.ExternalWarningLevel.Level2, () => { context.Options["ExternalWarningLevel"] = "Level2"; context.CommandLineOptions["ExternalWarningLevel"] = "/external:W2"; }), + Options.Option(Options.Vc.General.ExternalWarningLevel.Level3, () => { context.Options["ExternalWarningLevel"] = "Level3"; context.CommandLineOptions["ExternalWarningLevel"] = "/external:W3"; }), + Options.Option(Options.Vc.General.ExternalWarningLevel.Level4, () => { context.Options["ExternalWarningLevel"] = "Level4"; context.CommandLineOptions["ExternalWarningLevel"] = "/external:W4"; }), + Options.Option(Options.Vc.General.ExternalWarningLevel.InheritWarningLevel, () => { context.Options["ExternalWarningLevel"] = FileGeneratorUtilities.RemoveLineTag; context.CommandLineOptions["ExternalWarningLevel"] = FileGeneratorUtilities.RemoveLineTag; }) + ); + + context.SelectOption + ( + Options.Option(Options.Vc.General.ExternalTemplatesDiagnostics.Enable, () => { context.Options["ExternalTemplatesDiagnostics"] = "true"; context.CommandLineOptions["ExternalTemplatesDiagnostics"] = "/external:templates-"; }), + Options.Option(Options.Vc.General.ExternalTemplatesDiagnostics.Disable, () => { context.Options["ExternalTemplatesDiagnostics"] = FileGeneratorUtilities.RemoveLineTag; context.CommandLineOptions["ExternalTemplatesDiagnostics"] = FileGeneratorUtilities.RemoveLineTag; }) + ); + + context.Options["TrackFileAccess"] = FileGeneratorUtilities.RemoveLineTag; + + if (context.DevelopmentEnvironment.IsVisualStudio()) + { + SelectPreferredToolArchitecture(context); + SelectPlatformToolsetOption(context, optionsContext); + } + + // Compiler.SuppressStartupBanner + context.CommandLineOptions["SuppressStartupBanner"] = "/nologo"; + + //Options.Vc.Compiler.MultiProcessorCompilation. + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.MultiProcessorCompilation.Enable, () => { context.Options["MultiProcessorCompilation"] = "true"; context.CommandLineOptions["MultiProcessorCompilation"] = "/MP"; }), + Options.Option(Options.Vc.Compiler.MultiProcessorCompilation.Disable, () => { context.Options["MultiProcessorCompilation"] = "false"; context.CommandLineOptions["MultiProcessorCompilation"] = FileGeneratorUtilities.RemoveLineTag; }) + ); + + + //Options.Vc.Compiler.Optimization. + // Disable Project.ProjectConfiguration.Tool.Optimization="0" /Od + // MinimizeSize Project.ProjectConfiguration.Tool.Optimization="1" /O1 + // MaximizeSpeed Project.ProjectConfiguration.Tool.Optimization="2" /O2 + // FullOptimization Project.ProjectConfiguration.Tool.Optimization="3" /Ox + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.Optimization.Disable, () => { context.Options["Optimization"] = "Disabled"; context.CommandLineOptions["Optimization"] = "/Od"; }), + Options.Option(Options.Vc.Compiler.Optimization.MinimizeSize, () => { context.Options["Optimization"] = "MinSpace"; context.CommandLineOptions["Optimization"] = "/O1"; }), + Options.Option(Options.Vc.Compiler.Optimization.MaximizeSpeed, () => { context.Options["Optimization"] = "MaxSpeed"; context.CommandLineOptions["Optimization"] = "/O2"; }), + Options.Option(Options.Vc.Compiler.Optimization.FullOptimization, () => { context.Options["Optimization"] = "Full"; context.CommandLineOptions["Optimization"] = "/Ox"; }) + ); + + //Options.Vc.Compiler.Inline. + // Default InlineFunctionExpansion="0" + // OnlyInline InlineFunctionExpansion="1" /Ob1 + // AnySuitable InlineFunctionExpansion="2" /Ob2 + // Disable InlineFunctionExpansion="3" /Ob0 + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.Inline.Default, () => { context.Options["InlineFunctionExpansion"] = "Default"; context.CommandLineOptions["InlineFunctionExpansion"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Compiler.Inline.OnlyInline, () => { context.Options["InlineFunctionExpansion"] = "OnlyExplicitInline"; context.CommandLineOptions["InlineFunctionExpansion"] = "/Ob1"; }), + Options.Option(Options.Vc.Compiler.Inline.AnySuitable, () => { context.Options["InlineFunctionExpansion"] = "AnySuitable"; context.CommandLineOptions["InlineFunctionExpansion"] = "/Ob2"; }), + Options.Option(Options.Vc.Compiler.Inline.Disable, () => { context.Options["InlineFunctionExpansion"] = "Disabled"; context.CommandLineOptions["InlineFunctionExpansion"] = "/Ob0"; }) + ); + + //Options.Vc.Compiler.Intrinsic. + // Disable EnableIntrinsicFunctions="false" + // Enable EnableIntrinsicFunctions="true" /Oi + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.Intrinsic.Disable, () => { context.Options["EnableIntrinsicFunctions"] = "false"; context.CommandLineOptions["EnableIntrinsicFunctions"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Compiler.Intrinsic.Enable, () => { context.Options["EnableIntrinsicFunctions"] = "true"; context.CommandLineOptions["EnableIntrinsicFunctions"] = "/Oi"; }) + ); + + //Compiler.Optimization.FavorSizeOrSpeed + // Neither FavorSizeOrSpeed="0" + // FavorFastCode FavorSizeOrSpeed="1" /Ot + // FavorSmallCode FavorSizeOrSpeed="2" /Os + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.FavorSizeOrSpeed.Neither, () => { context.Options["FavorSizeOrSpeed"] = "Neither"; context.CommandLineOptions["FavorSizeOrSpeed"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Compiler.FavorSizeOrSpeed.FastCode, () => { context.Options["FavorSizeOrSpeed"] = "Speed"; context.CommandLineOptions["FavorSizeOrSpeed"] = "/Ot"; }), + Options.Option(Options.Vc.Compiler.FavorSizeOrSpeed.SmallCode, () => { context.Options["FavorSizeOrSpeed"] = "Size"; context.CommandLineOptions["FavorSizeOrSpeed"] = "/Os"; }) + ); + + //Compiler.Optimization.OmitFramePointers + // Disable OmitFramePointers="false" + // Enable OmitFramePointers="true" /Oy + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.OmitFramePointers.Disable, () => { context.Options["OmitFramePointers"] = "false"; context.CommandLineOptions["OmitFramePointers"] = "/Oy-"; }), + Options.Option(Options.Vc.Compiler.OmitFramePointers.Enable, () => { context.Options["OmitFramePointers"] = "true"; context.CommandLineOptions["OmitFramePointers"] = "/Oy"; }) + ); + + //Compiler.Optimization.FiberSafe + // Disable EnableFiberSafeOptimizations="false" + // Enable EnableFiberSafeOptimizations="true" /GT + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.FiberSafe.Disable, () => { context.Options["EnableFiberSafeOptimizations"] = "false"; context.CommandLineOptions["EnableFiberSafeOptimizations"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Compiler.FiberSafe.Enable, () => { context.Options["EnableFiberSafeOptimizations"] = "true"; context.CommandLineOptions["EnableFiberSafeOptimizations"] = "/GT"; }) + ); + + //Compiler.IgnoreStandardIncludePath. + // Disable IgnoreStandardIncludePath="false" + // Enable IgnoreStandardIncludePath="true" /X + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.IgnoreStandardIncludePath.Disable, () => { context.Options["IgnoreStandardIncludePath"] = "false"; context.CommandLineOptions["IgnoreStandardIncludePath"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Compiler.IgnoreStandardIncludePath.Enable, () => { context.Options["IgnoreStandardIncludePath"] = "true"; context.CommandLineOptions["IgnoreStandardIncludePath"] = "/X"; }) + ); + + //Compiler.Proprocessor.GenerateProcessorFile + // Disable GeneratePreprocessedFile="0" + // WithLineNumbers GeneratePreprocessedFile="1" /P + // WithoutLineNumbers GeneratePreprocessedFile="2" /EP /P + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.GenerateProcessorFile.Disable, () => { context.Options["GeneratePreprocessedFile"] = "false"; context.Options["PreprocessSuppressLineNumbers"] = "false"; context.CommandLineOptions["GeneratePreprocessedFile"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Compiler.GenerateProcessorFile.WithLineNumbers, () => { context.Options["GeneratePreprocessedFile"] = "true"; context.Options["PreprocessSuppressLineNumbers"] = "false"; context.CommandLineOptions["GeneratePreprocessedFile"] = "/P"; }), + Options.Option(Options.Vc.Compiler.GenerateProcessorFile.WithoutLineNumbers, () => { context.Options["GeneratePreprocessedFile"] = "true"; context.Options["PreprocessSuppressLineNumbers"] = "true"; context.CommandLineOptions["GeneratePreprocessedFile"] = "/EP /P"; }) + ); + + //Options.Vc.Compiler.KeepComment. + // Disable KeepComments="false" + // Enable KeepComments="true" /C + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.KeepComment.Disable, () => { context.Options["KeepComments"] = "false"; context.CommandLineOptions["KeepComments"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Compiler.KeepComment.Enable, () => { context.Options["KeepComments"] = "true"; context.CommandLineOptions["KeepComments"] = "/C"; }) + ); + + //Options.Vc.Compiler.StringPooling. + // Disable StringPooling="false" + // Enable StringPooling="true" /GF + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.StringPooling.Disable, () => { context.Options["StringPooling"] = "false"; context.CommandLineOptions["StringPooling"] = "/GF-"; }), + Options.Option(Options.Vc.Compiler.StringPooling.Enable, () => { context.Options["StringPooling"] = "true"; context.CommandLineOptions["StringPooling"] = "/GF"; }) + ); + + //Options.Vc.Compiler.Exceptions. + // Disable ExceptionHandling="false" + // Enable ExceptionHandling="Sync" /EHsc + // EnableWithExternC ExceptionHandling="SyncCThrow" /EHs + // EnableWithSEH ExceptionHandling="Async" /EHa + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.Exceptions.Disable, () => { context.Options["ExceptionHandling"] = "false"; context.CommandLineOptions["ExceptionHandling"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Compiler.Exceptions.Enable, () => { context.Options["ExceptionHandling"] = "Sync"; context.CommandLineOptions["ExceptionHandling"] = "/EHsc"; }), + Options.Option(Options.Vc.Compiler.Exceptions.EnableWithExternC, () => { context.Options["ExceptionHandling"] = "SyncCThrow"; context.CommandLineOptions["ExceptionHandling"] = "/EHs"; }), + Options.Option(Options.Vc.Compiler.Exceptions.EnableWithSEH, () => { context.Options["ExceptionHandling"] = "Async"; context.CommandLineOptions["ExceptionHandling"] = "/EHa"; }) + ); + + context.Options["ForcedUsingFiles"] = FileGeneratorUtilities.RemoveLineTag; + if (context.Configuration.ForceUsingFiles.Any() || context.Configuration.DependenciesForceUsingFiles.Any() || context.Configuration.ForceUsingDependencies.Any()) + { + StringBuilder builder = new StringBuilder(context.Configuration.ForceUsingFiles.JoinStrings(";", true)); + if (context.Configuration.ForceUsingFiles.Any()) + builder.Append(";"); + + builder.Append(context.Configuration.DependenciesForceUsingFiles.JoinStrings(";")); + if (context.Configuration.DependenciesForceUsingFiles.Any()) + builder.Append(";"); + + foreach (var dep in context.Configuration.ForceUsingDependencies) + builder.AppendFormat(@"{0}.dll;", dep.Project is CSharpProject ? dep.TargetFileName : dep.TargetFileFullName); + string ForceUsingFiles = builder.ToString(); + context.Options["ForcedUsingFiles"] = ForceUsingFiles.Remove(ForceUsingFiles.Length - 1, 1); + } + + //Options.Vc.Compiler.CompileAsWinRT. + // Disable CompileAsWinRT="false" + // Enable CompileAsWinRT="true" + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.CompileAsWinRT.Default, () => { context.Options["CompileAsWinRT"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Compiler.CompileAsWinRT.Disable, () => { context.Options["CompileAsWinRT"] = "false"; }), + Options.Option(Options.Vc.Compiler.CompileAsWinRT.Enable, () => { context.Options["CompileAsWinRT"] = "true"; }) + ); + + //Options.Vc.Compiler.TypeChecks. + // Disable SmallerTypeCheck="true" /RTCc + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.TypeChecks.Disable, () => { context.Options["SmallerTypeCheck"] = "false"; context.CommandLineOptions["SmallerTypeCheck"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Compiler.TypeChecks.Enable, () => { context.Options["SmallerTypeCheck"] = "true"; context.CommandLineOptions["SmallerTypeCheck"] = "/RTCc"; }) + ); + + //Options.Vc.Compiler.RuntimeChecks. + // Default BasicRuntimeChecks="0" + // StackFrames BasicRuntimeChecks="1" /RTCs + // UninitializedVariables BasicRuntimeChecks="2" /RTCu + // Both BasicRuntimeChecks="3" /RTC1 + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.RuntimeChecks.Default, () => { context.Options["BasicRuntimeChecks"] = "Default"; context.CommandLineOptions["BasicRuntimeChecks"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Compiler.RuntimeChecks.StackFrames, () => { context.Options["BasicRuntimeChecks"] = "StackFrameRuntimeCheck"; context.CommandLineOptions["BasicRuntimeChecks"] = "/RTCs"; }), + Options.Option(Options.Vc.Compiler.RuntimeChecks.UninitializedVariables, () => { context.Options["BasicRuntimeChecks"] = "UninitializedLocalUsageCheck"; context.CommandLineOptions["BasicRuntimeChecks"] = "/RTCu"; }), + Options.Option(Options.Vc.Compiler.RuntimeChecks.Both, () => { context.Options["BasicRuntimeChecks"] = "EnableFastChecks"; context.CommandLineOptions["BasicRuntimeChecks"] = "/RTC1"; }) + ); + + if (Util.IsCpp(context.Configuration)) + { + //Options.Vc.Compiler.RuntimeLibrary. + // MultiThreaded RuntimeLibrary="0" /MT + // MultiThreadedDebug RuntimeLibrary="1" /MTd + // MultiThreadedDLL RuntimeLibrary="2" /MD + // MultiThreadedDebugDLL RuntimeLibrary="3" /MDd + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.RuntimeLibrary.MultiThreaded, () => { context.Options["RuntimeLibrary"] = "MultiThreaded"; context.CommandLineOptions["RuntimeLibrary"] = "/MT"; }), + Options.Option(Options.Vc.Compiler.RuntimeLibrary.MultiThreadedDebug, () => { context.Options["RuntimeLibrary"] = "MultiThreadedDebug"; context.CommandLineOptions["RuntimeLibrary"] = "/MTd"; }), + Options.Option(Options.Vc.Compiler.RuntimeLibrary.MultiThreadedDLL, () => { context.Options["RuntimeLibrary"] = "MultiThreadedDLL"; context.CommandLineOptions["RuntimeLibrary"] = "/MD"; }), + Options.Option(Options.Vc.Compiler.RuntimeLibrary.MultiThreadedDebugDLL, () => { context.Options["RuntimeLibrary"] = "MultiThreadedDebugDLL"; context.CommandLineOptions["RuntimeLibrary"] = "/MDd"; }) + ); + } + else + { + context.Options["RuntimeLibrary"] = FileGeneratorUtilities.RemoveLineTag; + } + + bool clrSupport = Util.IsDotNet(context.Configuration); + if (!clrSupport && context.DevelopmentEnvironment.IsVisualStudio() && context.DevelopmentEnvironment < DevEnv.vs2019) // Gm is deprecated starting with vs2019 + { + //Options.Vc.Compiler.MinimalRebuild. + // Disable MinimalRebuild="false" + // Enable MinimalRebuild="true" /Gm + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.MinimalRebuild.Disable, () => { context.Options["MinimalRebuild"] = "false"; context.CommandLineOptions["MinimalRebuild"] = "/Gm-"; }), + Options.Option(Options.Vc.Compiler.MinimalRebuild.Enable, () => { context.Options["MinimalRebuild"] = FileGeneratorUtilities.RemoveLineTag; context.CommandLineOptions["MinimalRebuild"] = "/Gm"; }) + ); + } + else + { + context.Options["MinimalRebuild"] = FileGeneratorUtilities.RemoveLineTag; + context.CommandLineOptions["MinimalRebuild"] = FileGeneratorUtilities.RemoveLineTag; + } + + if (!clrSupport) + { + //Options.Vc.Compiler.RTTI. + // Disable RuntimeTypeInfo="false" /GR- + // Enable RuntimeTypeInfo="true" + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.RTTI.Disable, () => { context.Options["RuntimeTypeInfo"] = "false"; context.CommandLineOptions["RuntimeTypeInfo"] = "/GR-"; }), + Options.Option(Options.Vc.Compiler.RTTI.Enable, () => { context.Options["RuntimeTypeInfo"] = "true"; context.CommandLineOptions["RuntimeTypeInfo"] = "/GR"; }) + ); + } + else + { + context.Options["RuntimeTypeInfo"] = FileGeneratorUtilities.RemoveLineTag; + context.CommandLineOptions["RuntimeTypeInfo"] = FileGeneratorUtilities.RemoveLineTag; + } + + //Options.Vc.Compiler.StructAlignment. + // Default StructMemberAlignment="0" + // Alignment1 StructMemberAlignment="1" /Zp1 + // Alignment2 StructMemberAlignment="2" /Zp2 + // Alignment4 StructMemberAlignment="3" /Zp4 + // Alignment8 StructMemberAlignment="4" /Zp8 + // Alignment16 StructMemberAlignment="5" /Zp16 + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.StructAlignment.Default, () => { context.Options["StructMemberAlignment"] = "Default"; context.CommandLineOptions["StructMemberAlignment"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Compiler.StructAlignment.Alignment1, () => { context.Options["StructMemberAlignment"] = "1Byte"; context.CommandLineOptions["StructMemberAlignment"] = "/Zp1"; }), + Options.Option(Options.Vc.Compiler.StructAlignment.Alignment2, () => { context.Options["StructMemberAlignment"] = "2Bytes"; context.CommandLineOptions["StructMemberAlignment"] = "/Zp2"; }), + Options.Option(Options.Vc.Compiler.StructAlignment.Alignment4, () => { context.Options["StructMemberAlignment"] = "4Bytes"; context.CommandLineOptions["StructMemberAlignment"] = "/Zp4"; }), + Options.Option(Options.Vc.Compiler.StructAlignment.Alignment8, () => { context.Options["StructMemberAlignment"] = "8Bytes"; context.CommandLineOptions["StructMemberAlignment"] = "/Zp8"; }), + Options.Option(Options.Vc.Compiler.StructAlignment.Alignment16, () => { context.Options["StructMemberAlignment"] = "16Bytes"; context.CommandLineOptions["StructMemberAlignment"] = "/Zp16"; }) + ); + + //Options.Vc.Compiler.BufferSecurityCheck. + // Enable BufferSecurityCheck="true" + // Disable BufferSecurityCheck="false" /GS- + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.BufferSecurityCheck.Enable, () => { context.Options["BufferSecurityCheck"] = "true"; context.CommandLineOptions["BufferSecurityCheck"] = "/GS"; }), + Options.Option(Options.Vc.Compiler.BufferSecurityCheck.Disable, () => { context.Options["BufferSecurityCheck"] = "false"; context.CommandLineOptions["BufferSecurityCheck"] = "/GS-"; }) + ); + + //Options.Vc.Compiler.OptimizeGlobalData. + // Disable /Gw- in AdditionalOptions + // Enable /Gw in AdditionalOptions + if (context.Configuration.Platform.IsMicrosoft()) + { + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.OptimizeGlobalData.Disable, () => + { /* do nothing */ + }), + Options.Option(Options.Vc.Compiler.OptimizeGlobalData.Enable, () => { context.Configuration.AdditionalCompilerOptions.Add("/Gw"); }) + ); + } + + //Options.Vc.Compiler.FunctionLevelLinking. + // Disable EnableFunctionLevelLinking="false" + // Enable EnableFunctionLevelLinking="true" /Gy + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.FunctionLevelLinking.Disable, () => { context.Options["EnableFunctionLevelLinking"] = "false"; context.CommandLineOptions["EnableFunctionLevelLinking"] = "/Gy-"; }), + Options.Option(Options.Vc.Compiler.FunctionLevelLinking.Enable, () => { context.Options["EnableFunctionLevelLinking"] = "true"; context.CommandLineOptions["EnableFunctionLevelLinking"] = "/Gy"; }) + ); + + //Options.Vc.Compiler.EnhancedInstructionSet. + // Disable EnableEnhancedInstructionSet + // SIMD EnableEnhancedInstructionSet /arch:SSE + // SIMD2 EnableEnhancedInstructionSet /arch:SSE2 + // AdvancedVectorExtensions EnableEnhancedInstructionSet /arch:AVX + // NoEnhancedInstructions EnableEnhancedInstructionSet /arch:IA32 + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.EnhancedInstructionSet.Disable, () => { context.Options["EnableEnhancedInstructionSet"] = "NotSet"; context.CommandLineOptions["EnableEnhancedInstructionSet"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Compiler.EnhancedInstructionSet.SIMD, () => { context.Options["EnableEnhancedInstructionSet"] = "StreamingSIMDExtensions"; context.CommandLineOptions["EnableEnhancedInstructionSet"] = "/arch:SSE"; }), + Options.Option(Options.Vc.Compiler.EnhancedInstructionSet.SIMD2, () => { context.Options["EnableEnhancedInstructionSet"] = "StreamingSIMDExtensions2"; context.CommandLineOptions["EnableEnhancedInstructionSet"] = "/arch:SSE2"; }), + Options.Option(Options.Vc.Compiler.EnhancedInstructionSet.AdvancedVectorExtensions, () => { context.Options["EnableEnhancedInstructionSet"] = "AdvancedVectorExtensions"; context.CommandLineOptions["EnableEnhancedInstructionSet"] = "/arch:AVX"; }), + Options.Option(Options.Vc.Compiler.EnhancedInstructionSet.AdvancedVectorExtensions2, () => { context.Options["EnableEnhancedInstructionSet"] = "AdvancedVectorExtensions2"; context.CommandLineOptions["EnableEnhancedInstructionSet"] = "/arch:AVX2"; }), + Options.Option(Options.Vc.Compiler.EnhancedInstructionSet.AdvancedVectorExtensions512, () => { context.Options["EnableEnhancedInstructionSet"] = "AdvancedVectorExtensions512"; context.CommandLineOptions["EnableEnhancedInstructionSet"] = "/arch:AVX512"; }), + Options.Option(Options.Vc.Compiler.EnhancedInstructionSet.NoEnhancedInstructions, () => { context.Options["EnableEnhancedInstructionSet"] = "NoExtensions"; context.CommandLineOptions["EnableEnhancedInstructionSet"] = "/arch:IA32"; }) + ); + + //Options.Vc.Compiler.FloatingPointModel. + // Precise FloatingPointModel="0" /fp:precise + // Strict FloatingPointModel="1" /fp:strict + // Fast FloatingPointModel="2" /fp:fast + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.FloatingPointModel.Precise, () => { context.Options["FloatingPointModel"] = "Precise"; context.CommandLineOptions["FloatingPointModel"] = "/fp:precise"; }), + Options.Option(Options.Vc.Compiler.FloatingPointModel.Strict, () => { context.Options["FloatingPointModel"] = "Strict"; context.CommandLineOptions["FloatingPointModel"] = "/fp:strict"; }), + Options.Option(Options.Vc.Compiler.FloatingPointModel.Fast, () => { context.Options["FloatingPointModel"] = "Fast"; context.CommandLineOptions["FloatingPointModel"] = "/fp:fast"; }) + ); + + //Options.Vc.Compiler.FloatingPointExceptions. + // Disable FloatingPointExceptions="false" + // Enable FloatingPointExceptions="true" /fp:except + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.FloatingPointExceptions.Disable, () => { context.Options["FloatingPointExceptions"] = "false"; context.CommandLineOptions["FloatingPointExceptions"] = "/fp:except-"; }), + Options.Option(Options.Vc.Compiler.FloatingPointExceptions.Enable, () => { context.Options["FloatingPointExceptions"] = "true"; context.CommandLineOptions["FloatingPointExceptions"] = "/fp:except"; }) + ); + + //Options.Vc.Compiler.CreateHotPatchableCode. + // Disable CreateHotPatchableCode="false" + // Enable CreateHotPatchableCode="true" /hotpatch + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.CreateHotPatchableCode.Default, () => { context.Options["CompilerCreateHotpatchableImage"] = FileGeneratorUtilities.RemoveLineTag; context.CommandLineOptions["CompilerCreateHotpatchableImage"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Compiler.CreateHotPatchableCode.Disable, () => { context.Options["CompilerCreateHotpatchableImage"] = "false"; context.CommandLineOptions["CompilerCreateHotpatchableImage"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Compiler.CreateHotPatchableCode.Enable, () => { context.Options["CompilerCreateHotpatchableImage"] = "true"; context.CommandLineOptions["CompilerCreateHotpatchableImage"] = "/hotpatch"; }) + ); + + //Options.Vc.Compiler.ConformanceMode. + // Disable ConformanceMode="false" + // Enable ConformanceMode="true" /permissive- + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.ConformanceMode.Disable, () => { context.Options["ConformanceMode"] = FileGeneratorUtilities.RemoveLineTag; context.CommandLineOptions["ConformanceMode"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Compiler.ConformanceMode.Enable, () => { context.Options["ConformanceMode"] = "true"; context.CommandLineOptions["ConformanceMode"] = "/permissive-"; }) + ); + + //Options.Vc.Compiler.DisableLanguageExtensions. + // Disable DisableLanguageExtensions="false" + // Enable DisableLanguageExtensions="true" /Za + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.DisableLanguageExtensions.Disable, () => { context.Options["DisableLanguageExtensions"] = "false"; context.CommandLineOptions["DisableLanguageExtensions"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Compiler.DisableLanguageExtensions.Enable, () => { context.Options["DisableLanguageExtensions"] = "true"; context.CommandLineOptions["DisableLanguageExtensions"] = "/Za"; }) + ); + + //Options.Vc.Compiler.BuiltInWChartType. + // Disable TreatWChar_tAsBuiltInType="false" /Zc:wchar_t- + // Enable TreatWChar_tAsBuiltInType="true" /Zc:wchar_t + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.BuiltInWChartType.Disable, () => { context.Options["TreatWChar_tAsBuiltInType"] = "false"; context.CommandLineOptions["TreatWChar_tAsBuiltInType"] = "/Zc:wchar_t-"; }), + Options.Option(Options.Vc.Compiler.BuiltInWChartType.Enable, () => { context.Options["TreatWChar_tAsBuiltInType"] = "true"; context.CommandLineOptions["TreatWChar_tAsBuiltInType"] = "/Zc:wchar_t"; }) + ); + + // Disable RemoveUnreferencedCodeData="false" + // Enable RemoveUnreferencedCodeData="true" /Zc:inline + if (!context.DevelopmentEnvironment.IsVisualStudio()) + { + context.Options["RemoveUnreferencedCodeData"] = FileGeneratorUtilities.RemoveLineTag; + context.CommandLineOptions["RemoveUnreferencedCodeData"] = FileGeneratorUtilities.RemoveLineTag; + } + else + { + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.RemoveUnreferencedCodeData.Disable, () => + { + context.Options["RemoveUnreferencedCodeData"] = "false"; + context.CommandLineOptions["RemoveUnreferencedCodeData"] = FileGeneratorUtilities.RemoveLineTag; + }), + Options.Option(Options.Vc.Compiler.RemoveUnreferencedCodeData.Enable, () => + { + context.Options["RemoveUnreferencedCodeData"] = FileGeneratorUtilities.RemoveLineTag; + context.CommandLineOptions["RemoveUnreferencedCodeData"] = "/Zc:inline"; + }) + ); + } + + //Options.Vc.Compiler.ForceLoopScope. + // Disable ForceConformanceInForLoopScope="false" /Zc:forScope- + // Enable ForceConformanceInForLoopScope="true" /Zc:forScope + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.ForceLoopScope.Disable, () => { context.Options["ForceConformanceInForLoopScope"] = "false"; context.CommandLineOptions["ForceConformanceInForLoopScope"] = "/Zc:forScope-"; }), + Options.Option(Options.Vc.Compiler.ForceLoopScope.Enable, () => { context.Options["ForceConformanceInForLoopScope"] = "true"; context.CommandLineOptions["ForceConformanceInForLoopScope"] = "/Zc:forScope"; }) + ); + + //Options.Vc.Compiler.OpenMP. + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.OpenMP.Default, () => { context.Options["OpenMP"] = FileGeneratorUtilities.RemoveLineTag; context.CommandLineOptions["OpenMP"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Compiler.OpenMP.Disable, () => { context.Options["OpenMP"] = "false"; context.CommandLineOptions["OpenMP"] = "/openmp-"; }), + Options.Option(Options.Vc.Compiler.OpenMP.Enable, () => { context.Options["OpenMP"] = "true"; context.CommandLineOptions["OpenMP"] = "/openmp"; }) + ); + + //Options.Vc.Compiler.GenerateXMLDocumentation. + // Disable GenerateXMLDocumentation="false" + // Enable GenerateXMLDocumentation="true" /openmp + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.GenerateXMLDocumentation.Disable, () => { context.Options["GenerateXMLDocumentation"] = "false"; context.CommandLineOptions["GenerateXMLDocumentation"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Compiler.GenerateXMLDocumentation.Enable, () => { context.Options["GenerateXMLDocumentation"] = "true"; context.CommandLineOptions["GenerateXMLDocumentation"] = @"/doc""[project.RootPath]"""; }) + ); + + //Options.Vc.Compiler.PrecompiledHeader + // NotUsingPrecompiledHeaders UsePrecompiledHeader="0" + // CreatePrecompiledHeader UsePrecompiledHeader="1" /Yc + // UsePrecompiledHeader UsePrecompiledHeader="2" /Yu + SelectPrecompiledHeaderOption(context, optionsContext); + + //Options.Vc.Compiler.CallingConvention. + // cdecl CallingConvention="0" /Gd + // fastcall CallingConvention="1" /Gr + // stdcall CallingConvention="2" /Gz + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.CallingConvention.cdecl, () => { context.Options["CallingConvention"] = "Cdecl"; context.CommandLineOptions["CallingConvention"] = "/Gd"; }), + Options.Option(Options.Vc.Compiler.CallingConvention.fastcall, () => { context.Options["CallingConvention"] = "FastCall"; context.CommandLineOptions["CallingConvention"] = "/Gr"; }), + Options.Option(Options.Vc.Compiler.CallingConvention.stdcall, () => { context.Options["CallingConvention"] = "StdCall"; context.CommandLineOptions["CallingConvention"] = "/Gz"; }), + Options.Option(Options.Vc.Compiler.CallingConvention.vectorcall, () => { context.Options["CallingConvention"] = "VectorCall"; context.CommandLineOptions["CallingConvention"] = "/Gv"; }) + ); + + //Options.Vc.Compiler.ShowIncludes. + // Disable ShowIncludes="false" + // Enable ShowIncludes="true" /showIncludes + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.ShowIncludes.Disable, () => { context.Options["ShowIncludes"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Compiler.ShowIncludes.Enable, () => { context.Options["ShowIncludes"] = "true"; }) + ); + + // '/JMC' and '/clr' command-line options are incompatible + if (!clrSupport) + { + //Options.Vc.Compiler.SupportJustMyCode. + // Yes SupportJustMyCode="true" /JMC + // No + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.SupportJustMyCode.Default, () => { context.Options["SupportJustMyCode"] = FileGeneratorUtilities.RemoveLineTag; context.CommandLineOptions["SupportJustMyCode"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Compiler.SupportJustMyCode.No, () => + { + if (context.DevelopmentEnvironment >= DevEnv.vs2017) + { + context.Options["SupportJustMyCode"] = "false"; + context.CommandLineOptions["SupportJustMyCode"] = "/JMC-"; + } + else + { + context.Options["SupportJustMyCode"] = FileGeneratorUtilities.RemoveLineTag; + context.CommandLineOptions["SupportJustMyCode"] = FileGeneratorUtilities.RemoveLineTag; + } + }), + Options.Option(Options.Vc.Compiler.SupportJustMyCode.Yes, () => { context.Options["SupportJustMyCode"] = "true"; context.CommandLineOptions["SupportJustMyCode"] = "/JMC"; }) + ); + } + else + { + context.Options["SupportJustMyCode"] = FileGeneratorUtilities.RemoveLineTag; + context.CommandLineOptions["SupportJustMyCode"] = FileGeneratorUtilities.RemoveLineTag; + } + + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.SpectreMitigation.Default, () => { context.Options["SpectreMitigation"] = FileGeneratorUtilities.RemoveLineTag; context.CommandLineOptions["SpectreMitigation"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Compiler.SpectreMitigation.Spectre, () => { context.Options["SpectreMitigation"] = "Spectre"; context.CommandLineOptions["SpectreMitigation"] = "/Qspectre"; }), + Options.Option(Options.Vc.Compiler.SpectreMitigation.SpectreLoad, () => { context.Options["SpectreMitigation"] = "SpectreLoad"; context.CommandLineOptions["SpectreMitigation"] = "/Qspectre-load"; }), + Options.Option(Options.Vc.Compiler.SpectreMitigation.SpectreLoadCF, () => { context.Options["SpectreMitigation"] = "SpectreLoadCF"; context.CommandLineOptions["SpectreMitigation"] = "/Qspectre-load-cf"; }), + Options.Option(Options.Vc.Compiler.SpectreMitigation.Disabled, () => { context.Options["SpectreMitigation"] = "false"; context.CommandLineOptions["SpectreMitigation"] = FileGeneratorUtilities.RemoveLineTag; }) + ); + + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.EnableAsan.Disable, () => { context.Options["EnableASAN"] = FileGeneratorUtilities.RemoveLineTag; context.CommandLineOptions["EnableASAN"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Compiler.EnableAsan.Enable, () => { context.Options["EnableASAN"] = "true"; context.CommandLineOptions["EnableASAN"] = "/fsanitize=address"; }) + ); + + if (context.DevelopmentEnvironment.IsVisualStudio() && context.DevelopmentEnvironment >= DevEnv.vs2017) + { + //Options.Vc.Compiler.DefineCPlusPlus. See: https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/ + // Disable /Zc:__cplusplus- + // Enable /Zc:__cplusplus + if (!useClangCl) + { + if (!context.Configuration.Platform.IsUsingClang()) + { + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.DefineCPlusPlus.Default, () => { }), + Options.Option(Options.Vc.Compiler.DefineCPlusPlus.Disable, () => { context.Configuration.AdditionalCompilerOptions.Add("/Zc:__cplusplus-"); }), + Options.Option(Options.Vc.Compiler.DefineCPlusPlus.Enable, () => { context.Configuration.AdditionalCompilerOptions.Add("/Zc:__cplusplus"); }) + ); + } + } + } + + // Options.Vc.Compiler.DisableSpecificWarnings + Strings disableWarnings = Options.GetStrings(context.Configuration); + if (disableWarnings.Count > 0) + { + StringBuilder result = new StringBuilder(); + foreach (string disableWarning in disableWarnings.SortedValues) + result.Append(@"/wd""" + disableWarning + @""" "); + result.Remove(result.Length - 1, 1); + context.Options["DisableSpecificWarnings"] = disableWarnings.JoinStrings(";"); + context.CommandLineOptions["DisableSpecificWarnings"] = result.ToString(); + } + else + { + context.Options["DisableSpecificWarnings"] = FileGeneratorUtilities.RemoveLineTag; + context.CommandLineOptions["DisableSpecificWarnings"] = FileGeneratorUtilities.RemoveLineTag; + } + + // Options.Vc.Compiler.UndefinePreprocessorDefinitions + Strings undefinePreprocessors = Options.GetStrings(context.Configuration); + if (undefinePreprocessors.Count > 0) + { + context.Options["UndefinePreprocessorDefinitions"] = undefinePreprocessors.JoinStrings(";"); + + StringBuilder result = new StringBuilder(); + foreach (string undefine in undefinePreprocessors) + result.Append(@"/U""" + undefine + @""" "); + result.Remove(result.Length - 1, 1); + context.CommandLineOptions["UndefinePreprocessorDefinitions"] = result.ToString(); + } + else + { + context.Options["UndefinePreprocessorDefinitions"] = FileGeneratorUtilities.RemoveLineTag; + context.CommandLineOptions["UndefinePreprocessorDefinitions"] = FileGeneratorUtilities.RemoveLineTag; + } + + // UndefineAllPreprocessorDefinitions + context.CommandLineOptions["UndefineAllPreprocessorDefinitions"] = FileGeneratorUtilities.RemoveLineTag; + + optionsContext.PlatformVcxproj.SelectPrecompiledHeaderOptions(context); + + // Default defines... + optionsContext.PlatformVcxproj.SelectCompilerOptions(context); + + if (useClangCl && context.Configuration.IsFastBuild) + { + // This prevents clang-cl from auto-detecting the locally installed MSVC toolchain. Only paths on the command line will be considered. + // It doesn't apply on MSVC build, where the toolchain is provided through environment variables. + context.Configuration.AdditionalCompilerOptions.Add("-nostdinc"); + } + + // Options.Vc.Compiler.AdditionalOptions + foreach (Tuple optionsTuple in new[] + { + Tuple.Create(context.Configuration.AdditionalCompilerOptions, "AdditionalCompilerOptions"), + Tuple.Create(context.Configuration.AdditionalCompilerOptionsOnPCHCreate, "AdditionalCompilerOptionsOnPCHCreate"), + Tuple.Create(context.Configuration.AdditionalCompilerOptionsOnPCHUse, "AdditionalCompilerOptionsOnPCHUse") + }) + { + OrderableStrings optionsStrings = optionsTuple.Item1; + string optionsKey = optionsTuple.Item2; + if (optionsStrings.Any()) + { + optionsStrings.Sort(); + string additionalCompilerOptions = optionsStrings.JoinStrings(" "); + context.Options[optionsKey] = additionalCompilerOptions; + } + else + { + context.Options[optionsKey] = FileGeneratorUtilities.RemoveLineTag; + } + } + + optionsContext.HasClrSupport = clrSupport; + } + private void GenerateClangCompilerOptions(IGenerationContext context, ProjectOptionsGenerationContext optionsContext) + { + var forcedIncludes = new Strings(); + + if (!context.Configuration.IsFastBuild) + { + forcedIncludes.Add(context.Configuration.PrecompHeader); + } + + forcedIncludes.AddRange(context.Configuration.ForcedIncludes); + + if (forcedIncludes.Count > 0) + { + context.Options["ForcedIncludeFiles"] = forcedIncludes.JoinStrings(";"); + + // save the vanilla value without the LLVM workaround for reuse later + if (forcedIncludes.Count != context.Configuration.ForcedIncludes.Count) + context.Options["ForcedIncludeFilesVanilla"] = context.Configuration.ForcedIncludes.JoinStrings(";"); + + StringBuilder result = new StringBuilder(); + foreach (var forcedInclude in forcedIncludes) + { + if (forcedInclude != null) + { + result.Append(@"-isystem""" + forcedInclude + @""" "); + } + } + if (result.Length > 0) + { + result.Remove(result.Length - 1, 1); + } + context.CommandLineOptions["ForcedIncludeFiles"] = result.ToString(); + } + else + { + context.Options["ForcedIncludeFiles"] = FileGeneratorUtilities.RemoveLineTag; + context.CommandLineOptions["ForcedIncludeFiles"] = FileGeneratorUtilities.RemoveLineTag; + } + + context.Options["CharacterSet"] = FileGeneratorUtilities.RemoveLineTag; + context.CommandLineOptions["CharacterSet"] = FileGeneratorUtilities.RemoveLineTag; + + context.Options["LanguageStandard"] = FileGeneratorUtilities.RemoveLineTag; + context.CommandLineOptions["LanguageStandard"] = FileGeneratorUtilities.RemoveLineTag; + + //https://clang.llvm.org/docs/CommandGuide/clang.html + string cppLanguageStd = null; + context.SelectOption + ( + Options.Option(Options.Clang.Compiler.CppLanguageStandard.Default, () => { context.Options["ClangCppLanguageStandard"] = FileGeneratorUtilities.RemoveLineTag; context.Options["CppLanguageStandard"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Clang.Compiler.CppLanguageStandard.Cpp98, () => { context.Options["ClangCppLanguageStandard"] = "-std=c++98"; context.Options["CppLanguageStandard"] = "c++98"; }), + Options.Option(Options.Clang.Compiler.CppLanguageStandard.Cpp11, () => { context.Options["ClangCppLanguageStandard"] = "-std=c++11"; context.Options["CppLanguageStandard"] = "c++11"; }), + Options.Option(Options.Clang.Compiler.CppLanguageStandard.Cpp14, () => { context.Options["ClangCppLanguageStandard"] = "-std=c++14"; context.Options["CppLanguageStandard"] = "c++14"; }), + Options.Option(Options.Clang.Compiler.CppLanguageStandard.Cpp17, () => { context.Options["ClangCppLanguageStandard"] = "-std=c++17"; context.Options["CppLanguageStandard"] = "c++17"; }), + Options.Option(Options.Clang.Compiler.CppLanguageStandard.Cpp2a, () => { context.Options["ClangCppLanguageStandard"] = "-std=c++2a"; context.Options["CppLanguageStandard"] = "c++2a"; }), + Options.Option(Options.Clang.Compiler.CppLanguageStandard.GnuCpp98, () => { context.Options["ClangCppLanguageStandard"] = "-std=gnu++98"; context.Options["CppLanguageStandard"] = "gnu++98"; }), + Options.Option(Options.Clang.Compiler.CppLanguageStandard.GnuCpp11, () => { context.Options["ClangCppLanguageStandard"] = "-std=gnu++11"; context.Options["CppLanguageStandard"] = "gnu++11"; }), + Options.Option(Options.Clang.Compiler.CppLanguageStandard.GnuCpp14, () => { context.Options["ClangCppLanguageStandard"] = "-std=gnu++14"; context.Options["CppLanguageStandard"] = "gnu++14"; }), + Options.Option(Options.Clang.Compiler.CppLanguageStandard.GnuCpp17, () => { context.Options["ClangCppLanguageStandard"] = "-std=gnu++17"; context.Options["CppLanguageStandard"] = "gnu++17"; }), + Options.Option(Options.Clang.Compiler.CppLanguageStandard.GnuCpp2a, () => { context.Options["ClangCppLanguageStandard"] = "-std=gnu++2a"; context.Options["CppLanguageStandard"] = "gnu++2a"; })); + + if (!context.Options.ContainsKey("ClangCppLanguageStandard") || string.IsNullOrEmpty(context.Options["ClangCppLanguageStandard"]) || context.Options["ClangCppLanguageStandard"] == FileGeneratorUtilities.RemoveLineTag) + { + context.SelectOption( + Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP98, () => { }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP11, () => { }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP14, () => { context.Options["ClangCppLanguageStandard"] = "-std=c++14"; }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP17, () => { context.Options["ClangCppLanguageStandard"] = "-std=c++17"; }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP20, () => { context.Options["ClangCppLanguageStandard"] = "-std=c++2a"; }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.GNU98, () => { }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.GNU11, () => { }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.GNU14, () => { context.Options["ClangCppLanguageStandard"] = "-std=c++14"; }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.GNU17, () => { context.Options["ClangCppLanguageStandard"] = "-std=c++17"; }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.Latest, () => { context.Options["ClangCppLanguageStandard"] = "-std=c++2a"; }) + ); + } + + + context.SelectOption + ( + Options.Option(Options.Clang.Compiler.CLanguageStandard.Default, () => { context.Options["ClangCLanguageStandard"] = FileGeneratorUtilities.RemoveLineTag; context.Options["CLanguageStandard"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Clang.Compiler.CLanguageStandard.C89, () => { context.Options["ClangCLanguageStandard"] = "-std=c89"; context.Options["CLanguageStandard"] = "c89"; }), + Options.Option(Options.Clang.Compiler.CLanguageStandard.C90, () => { context.Options["ClangCLanguageStandard"] = "-std=c90"; context.Options["CLanguageStandard"] = "c90"; }), + Options.Option(Options.Clang.Compiler.CLanguageStandard.C99, () => { context.Options["ClangCLanguageStandard"] = "-std=c99"; context.Options["CLanguageStandard"] = "c99"; }), + Options.Option(Options.Clang.Compiler.CLanguageStandard.C11, () => { context.Options["ClangCLanguageStandard"] = "-std=c11"; context.Options["CLanguageStandard"] = "c11"; }), + Options.Option(Options.Clang.Compiler.CLanguageStandard.C17, () => { context.Options["ClangCLanguageStandard"] = "-std=c17"; context.Options["CLanguageStandard"] = "c17"; }), + Options.Option(Options.Clang.Compiler.CLanguageStandard.GnuC89, () => { context.Options["ClangCLanguageStandard"] = "-std=gnu89"; context.Options["CLanguageStandard"] = "gnu89"; }), + Options.Option(Options.Clang.Compiler.CLanguageStandard.GnuC90, () => { context.Options["ClangCLanguageStandard"] = "-std=gnu90"; context.Options["CLanguageStandard"] = "gnu90"; }), + Options.Option(Options.Clang.Compiler.CLanguageStandard.GnuC99, () => { context.Options["ClangCLanguageStandard"] = "-std=gnu99"; context.Options["CLanguageStandard"] = "gnu99"; }), + Options.Option(Options.Clang.Compiler.CLanguageStandard.GnuC11, () => { context.Options["ClangCLanguageStandard"] = "-std=gnu11"; context.Options["CLanguageStandard"] = "gnu11"; }), + Options.Option(Options.Clang.Compiler.CLanguageStandard.GnuC17, () => { context.Options["ClangCLanguageStandard"] = "-std=gnu17"; context.Options["CLanguageStandard"] = "gnu17"; }) + ); + + context.CommandLineOptions["CppLanguageStd"] = context.Options["ClangCppLanguageStandard"]; + context.CommandLineOptions["CLanguageStd"] = context.Options["ClangCLanguageStandard"]; + + cppLanguageStd = context.CommandLineOptions["CppLanguageStd"]; + + context.Options["AdditionalOptions"] = (context.Configuration.CustomBuildSettings is null) ? FileGeneratorUtilities.RemoveLineTag : context.Configuration.CustomBuildSettings.AdditionalOptions; + if (context.Configuration.CustomBuildSettings is null || context.Configuration.CustomBuildSettings.AutoConfigure) + { + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP98, () => { }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP11, () => { }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP14, () => { cppLanguageStd = "/std:c++14"; }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP17, () => { cppLanguageStd = "/std:c++17"; }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP20, () => { cppLanguageStd = "/std:c++20"; }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.GNU98, () => { }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.GNU11, () => { }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.GNU14, () => { cppLanguageStd = "/std:c++14"; }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.GNU17, () => { cppLanguageStd = "/std:c++17"; }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.Latest, () => { cppLanguageStd = "/std:c++latest"; }) + ); + } + + if (!string.IsNullOrEmpty(cppLanguageStd)) + { + if (string.IsNullOrEmpty(context.Options["AdditionalOptions"]) || context.Options["AdditionalOptions"] == FileGeneratorUtilities.RemoveLineTag) + context.Options["AdditionalOptions"] = cppLanguageStd; + else + context.Options["AdditionalOptions"] += $" {cppLanguageStd}"; + } + else if (string.IsNullOrEmpty(context.Options["AdditionalOptions"])) + { + context.Options["AdditionalOptions"] = FileGeneratorUtilities.RemoveLineTag; + } + + context.SelectOption + ( + Options.Option(Options.Vc.General.TreatWarningsAsErrors.Disable, () => { context.Options["TreatWarningAsError"] = "false"; context.CommandLineOptions["TreatWarningAsError"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.General.TreatWarningsAsErrors.Enable, () => { context.Options["TreatWarningAsError"] = "true"; context.CommandLineOptions["TreatWarningAsError"] = "-Werror"; }) + ); + + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.BufferSecurityCheck.Enable, () => { context.Options["BufferSecurityCheck"] = "true"; context.CommandLineOptions["BufferSecurityCheck"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Compiler.BufferSecurityCheck.Disable, () => { context.Options["BufferSecurityCheck"] = "false"; context.CommandLineOptions["BufferSecurityCheck"] = "-fstack-protector"; }) + ); + + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.FunctionLevelLinking.Disable, () => { context.Options["EnableFunctionLevelLinking"] = "false"; context.CommandLineOptions["EnableFunctionLevelLinking"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Compiler.FunctionLevelLinking.Enable, () => { context.Options["EnableFunctionLevelLinking"] = "true"; context.CommandLineOptions["EnableFunctionLevelLinking"] = "-ffunction-sections"; }) + ); + + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.OmitFramePointers.Disable, () => { context.Options["OmitFramePointers"] = "false"; context.CommandLineOptions["OmitFramePointers"] = "-fno-omit-frame-pointer"; }), + Options.Option(Options.Vc.Compiler.OmitFramePointers.Enable, () => { context.Options["OmitFramePointers"] = "true"; context.CommandLineOptions["OmitFramePointers"] = "-fomit-frame-pointer"; }) + ); + + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.Optimization.Disable, () => { context.Options["Optimization"] = "Disabled"; context.CommandLineOptions["Optimization"] = "-O0"; }), + Options.Option(Options.Vc.Compiler.Optimization.MinimizeSize, () => { context.Options["Optimization"] = "MinSize"; context.CommandLineOptions["Optimization"] = "-Os"; }), + Options.Option(Options.Vc.Compiler.Optimization.MaximizeSpeed, () => { context.Options["Optimization"] = "MaxSpeed"; context.CommandLineOptions["Optimization"] = "-O2"; }), + Options.Option(Options.Vc.Compiler.Optimization.FullOptimization, () => { context.Options["Optimization"] = "Full"; context.CommandLineOptions["Optimization"] = "-O3"; }) + ); + + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.MultiProcessorCompilation.Enable, () => { context.Options["UseMultiToolTask"] = "true"; }), + Options.Option(Options.Vc.Compiler.MultiProcessorCompilation.Disable, () => { context.Options["UseMultiToolTask"] = "false"; }) + ); + + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.RTTI.Disable, () => { context.Options["RuntimeTypeInfo"] = "false"; context.CommandLineOptions["RuntimeTypeInfo"] = "-fno-rtti"; }), + Options.Option(Options.Vc.Compiler.RTTI.Enable, () => { context.Options["RuntimeTypeInfo"] = "true"; context.CommandLineOptions["RuntimeTypeInfo"] = "-frtti"; }) + ); + } + private void GenerateGccCompilerOptions(IGenerationContext context, ProjectOptionsGenerationContext optionsContext) + { + var forcedIncludes = new Strings(); + + if (!context.Configuration.IsFastBuild) + { + forcedIncludes.Add(context.Configuration.PrecompHeader); + } + + forcedIncludes.AddRange(context.Configuration.ForcedIncludes); + + if (forcedIncludes.Count > 0) + { + context.Options["ForcedIncludeFiles"] = forcedIncludes.JoinStrings(";"); + + // save the vanilla value without the LLVM workaround for reuse later + if (forcedIncludes.Count != context.Configuration.ForcedIncludes.Count) + context.Options["ForcedIncludeFilesVanilla"] = context.Configuration.ForcedIncludes.JoinStrings(";"); + + StringBuilder result = new StringBuilder(); + foreach (var forcedInclude in forcedIncludes) + { + if (forcedInclude != null) + { + result.Append(@"-isystem""" + forcedInclude + @""" "); + } + } + if (result.Length > 0) + { + result.Remove(result.Length - 1, 1); + } + context.CommandLineOptions["ForcedIncludeFiles"] = result.ToString(); + } + else + { + context.Options["ForcedIncludeFiles"] = FileGeneratorUtilities.RemoveLineTag; + context.CommandLineOptions["ForcedIncludeFiles"] = FileGeneratorUtilities.RemoveLineTag; + } + + context.Options["CharacterSet"] = FileGeneratorUtilities.RemoveLineTag; + context.CommandLineOptions["CharacterSet"] = FileGeneratorUtilities.RemoveLineTag; + + context.Options["LanguageStandard"] = FileGeneratorUtilities.RemoveLineTag; + context.CommandLineOptions["LanguageStandard"] = FileGeneratorUtilities.RemoveLineTag; + + //https://clang.llvm.org/docs/CommandGuide/clang.html + context.SelectOption + ( + Options.Option(Options.Clang.Compiler.CppLanguageStandard.Default, () => { context.Options["ClangCppLanguageStandard"] = FileGeneratorUtilities.RemoveLineTag; context.Options["CppLanguageStandard"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Clang.Compiler.CppLanguageStandard.Cpp98, () => { context.Options["ClangCppLanguageStandard"] = "-std=c++98"; context.Options["CppLanguageStandard"] = "c++98"; }), + Options.Option(Options.Clang.Compiler.CppLanguageStandard.Cpp11, () => { context.Options["ClangCppLanguageStandard"] = "-std=c++11"; context.Options["CppLanguageStandard"] = "c++11"; }), + Options.Option(Options.Clang.Compiler.CppLanguageStandard.Cpp14, () => { context.Options["ClangCppLanguageStandard"] = "-std=c++14"; context.Options["CppLanguageStandard"] = "c++14"; }), + Options.Option(Options.Clang.Compiler.CppLanguageStandard.Cpp17, () => { context.Options["ClangCppLanguageStandard"] = "-std=c++17"; context.Options["CppLanguageStandard"] = "c++17"; }), + Options.Option(Options.Clang.Compiler.CppLanguageStandard.Cpp2a, () => { context.Options["ClangCppLanguageStandard"] = "-std=c++2a"; context.Options["CppLanguageStandard"] = "c++2a"; }), + Options.Option(Options.Clang.Compiler.CppLanguageStandard.GnuCpp98, () => { context.Options["ClangCppLanguageStandard"] = "-std=gnu++98"; context.Options["CppLanguageStandard"] = "gnu++98"; }), + Options.Option(Options.Clang.Compiler.CppLanguageStandard.GnuCpp11, () => { context.Options["ClangCppLanguageStandard"] = "-std=gnu++11"; context.Options["CppLanguageStandard"] = "gnu++11"; }), + Options.Option(Options.Clang.Compiler.CppLanguageStandard.GnuCpp14, () => { context.Options["ClangCppLanguageStandard"] = "-std=gnu++14"; context.Options["CppLanguageStandard"] = "gnu++14"; }), + Options.Option(Options.Clang.Compiler.CppLanguageStandard.GnuCpp17, () => { context.Options["ClangCppLanguageStandard"] = "-std=gnu++17"; context.Options["CppLanguageStandard"] = "gnu++17"; }), + Options.Option(Options.Clang.Compiler.CppLanguageStandard.GnuCpp2a, () => { context.Options["ClangCppLanguageStandard"] = "-std=gnu++2a"; context.Options["CppLanguageStandard"] = "gnu++2a"; }) + ); + + context.SelectOption + ( + Options.Option(Options.Clang.Compiler.CLanguageStandard.Default, () => { context.Options["ClangCLanguageStandard"] = FileGeneratorUtilities.RemoveLineTag; context.Options["CLanguageStandard"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Clang.Compiler.CLanguageStandard.C89, () => { context.Options["ClangCLanguageStandard"] = "-std=c89"; context.Options["CLanguageStandard"] = "c89"; }), + Options.Option(Options.Clang.Compiler.CLanguageStandard.C90, () => { context.Options["ClangCLanguageStandard"] = "-std=c90"; context.Options["CLanguageStandard"] = "c90"; }), + Options.Option(Options.Clang.Compiler.CLanguageStandard.C99, () => { context.Options["ClangCLanguageStandard"] = "-std=c99"; context.Options["CLanguageStandard"] = "c99"; }), + Options.Option(Options.Clang.Compiler.CLanguageStandard.C11, () => { context.Options["ClangCLanguageStandard"] = "-std=c11"; context.Options["CLanguageStandard"] = "c11"; }), + Options.Option(Options.Clang.Compiler.CLanguageStandard.C17, () => { context.Options["ClangCLanguageStandard"] = "-std=c17"; context.Options["CLanguageStandard"] = "c17"; }), + Options.Option(Options.Clang.Compiler.CLanguageStandard.GnuC89, () => { context.Options["ClangCLanguageStandard"] = "-std=gnu89"; context.Options["CLanguageStandard"] = "gnu89"; }), + Options.Option(Options.Clang.Compiler.CLanguageStandard.GnuC90, () => { context.Options["ClangCLanguageStandard"] = "-std=gnu90"; context.Options["CLanguageStandard"] = "gnu90"; }), + Options.Option(Options.Clang.Compiler.CLanguageStandard.GnuC99, () => { context.Options["ClangCLanguageStandard"] = "-std=gnu99"; context.Options["CLanguageStandard"] = "gnu99"; }), + Options.Option(Options.Clang.Compiler.CLanguageStandard.GnuC11, () => { context.Options["ClangCLanguageStandard"] = "-std=gnu11"; context.Options["CLanguageStandard"] = "gnu11"; }), + Options.Option(Options.Clang.Compiler.CLanguageStandard.GnuC17, () => { context.Options["ClangCLanguageStandard"] = "-std=gnu17"; context.Options["CLanguageStandard"] = "gnu17"; }) + ); + + context.CommandLineOptions["CppLanguageStd"] = context.Options["ClangCppLanguageStandard"]; + context.CommandLineOptions["CLanguageStd"] = context.Options["ClangCLanguageStandard"]; + + context.Options["AdditionalOptions"] = (context.Configuration.CustomBuildSettings is null) ? FileGeneratorUtilities.RemoveLineTag : context.Configuration.CustomBuildSettings.AdditionalOptions; + string cppLanguageStd = null; + if (context.Configuration.CustomBuildSettings is null || context.Configuration.CustomBuildSettings.AutoConfigure) + { + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP98, () => { }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP11, () => { }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP14, () => { cppLanguageStd = "/std:c++14"; }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP17, () => { cppLanguageStd = "/std:c++17"; }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.CPP20, () => { cppLanguageStd = "/std:c++20"; }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.GNU98, () => { }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.GNU11, () => { }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.GNU14, () => { cppLanguageStd = "/std:c++14"; }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.GNU17, () => { cppLanguageStd = "/std:c++17"; }), + Options.Option(Options.Vc.Compiler.CppLanguageStandard.Latest, () => { cppLanguageStd = "/std:c++latest"; }) + ); + } + + if (!string.IsNullOrEmpty(cppLanguageStd)) + { + if (string.IsNullOrEmpty(context.Options["AdditionalOptions"]) || context.Options["AdditionalOptions"] == FileGeneratorUtilities.RemoveLineTag) + context.Options["AdditionalOptions"] = cppLanguageStd; + else + context.Options["AdditionalOptions"] += $" {cppLanguageStd}"; + } + else if (string.IsNullOrEmpty(context.Options["AdditionalOptions"])) + { + context.Options["AdditionalOptions"] = FileGeneratorUtilities.RemoveLineTag; + } + + context.SelectOption + ( + Options.Option(Options.Vc.General.TreatWarningsAsErrors.Disable, () => { context.Options["TreatWarningAsError"] = "false"; context.CommandLineOptions["TreatWarningAsError"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.General.TreatWarningsAsErrors.Enable, () => { context.Options["TreatWarningAsError"] = "true"; context.CommandLineOptions["TreatWarningAsError"] = "-Werror"; }) + ); + + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.BufferSecurityCheck.Enable, () => { context.Options["BufferSecurityCheck"] = "true"; context.CommandLineOptions["BufferSecurityCheck"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Compiler.BufferSecurityCheck.Disable, () => { context.Options["BufferSecurityCheck"] = "false"; context.CommandLineOptions["BufferSecurityCheck"] = "-fstack-protector"; }) + ); + + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.FunctionLevelLinking.Disable, () => { context.Options["EnableFunctionLevelLinking"] = "false"; context.CommandLineOptions["EnableFunctionLevelLinking"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Compiler.FunctionLevelLinking.Enable, () => { context.Options["EnableFunctionLevelLinking"] = "true"; context.CommandLineOptions["EnableFunctionLevelLinking"] = "-ffunction-sections"; }) + ); + + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.OmitFramePointers.Disable, () => { context.Options["OmitFramePointers"] = "false"; context.CommandLineOptions["OmitFramePointers"] = "-fno-omit-frame-pointer"; }), + Options.Option(Options.Vc.Compiler.OmitFramePointers.Enable, () => { context.Options["OmitFramePointers"] = "true"; context.CommandLineOptions["OmitFramePointers"] = "-fomit-frame-pointer"; }) + ); + + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.Optimization.Disable, () => { context.Options["Optimization"] = "Disabled"; context.CommandLineOptions["Optimization"] = "-O0"; }), + Options.Option(Options.Vc.Compiler.Optimization.MinimizeSize, () => { context.Options["Optimization"] = "MinSize"; context.CommandLineOptions["Optimization"] = "-Os"; }), + Options.Option(Options.Vc.Compiler.Optimization.MaximizeSpeed, () => { context.Options["Optimization"] = "MaxSpeed"; context.CommandLineOptions["Optimization"] = "-O2"; }), + Options.Option(Options.Vc.Compiler.Optimization.FullOptimization, () => { context.Options["Optimization"] = "Full"; context.CommandLineOptions["Optimization"] = "-O3"; }) + ); + + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.MultiProcessorCompilation.Enable, () => { context.Options["UseMultiToolTask"] = "true"; }), + Options.Option(Options.Vc.Compiler.MultiProcessorCompilation.Disable, () => { context.Options["UseMultiToolTask"] = "false"; }) + ); + + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.RTTI.Disable, () => { context.Options["RuntimeTypeInfo"] = "false"; context.CommandLineOptions["RuntimeTypeInfo"] = "-fno-rtti"; }), + Options.Option(Options.Vc.Compiler.RTTI.Enable, () => { context.Options["RuntimeTypeInfo"] = "true"; context.CommandLineOptions["RuntimeTypeInfo"] = "-frtti"; }) + ); + } + + public static List> ConvertPostBuildCopiesToRelative(Project.Configuration conf, string relativeTo) + { + var relativePostBuildCopies = new List>(); + if (!conf.ResolvedTargetCopyFiles.Any() && conf.CopyDependenciesBuildStep == null && !conf.EventPostBuildCopies.Any() && !conf.ResolvedTargetCopyFilesToSubDirectory.Any()) + return relativePostBuildCopies; + + relativePostBuildCopies.AddRange(conf.ResolvedTargetCopyFiles.Select(x => new KeyValuePair(x, conf.TargetCopyFilesPath))); + relativePostBuildCopies.AddRange(conf.EventPostBuildCopies); + relativePostBuildCopies.AddRange(conf.ResolvedTargetCopyFilesToSubDirectory.Select(x => new KeyValuePair(x.Key, Path.Combine(conf.TargetPath, x.Value)))); + + for (int i = 0; i < relativePostBuildCopies.Count;) + { + string sourceFileFullPath = relativePostBuildCopies[i].Key; + string dstDir = relativePostBuildCopies[i].Value; + + // discard if the source is already in the destination folder + string sourceFileDirectory = Path.GetDirectoryName(sourceFileFullPath); + if (string.Compare(sourceFileDirectory, dstDir, StringComparison.OrdinalIgnoreCase) == 0) + { + relativePostBuildCopies.RemoveAt(i); + continue; + } + + // keep the full path for the source if outside of the global root + string sourcePath; + if (sourceFileFullPath.StartsWith(conf.Project.RootPath, StringComparison.OrdinalIgnoreCase)) + sourcePath = Util.PathGetRelative(relativeTo, sourceFileFullPath, true); + else + sourcePath = sourceFileFullPath; + + string relativeDstDir = Util.PathGetRelative(relativeTo, dstDir); + relativePostBuildCopies[i] = new KeyValuePair(sourcePath, relativeDstDir); + + ++i; + } + + return relativePostBuildCopies; + } + + private static void SelectDebugInformationOption(IGenerationContext context, ProjectOptionsGenerationContext optionsContext) + { + // win64 don't support /ZI which is the default one, forward it to /Zi + if (optionsContext.PlatformVcxproj.HasEditAndContinueDebuggingSupport) + { + context.SelectOption + ( + Options.Option(Options.Vc.General.DebugInformation.Disable, () => { context.Options["DebugInformationFormat"] = "None"; context.CommandLineOptions["DebugInformationFormat"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.General.DebugInformation.C7Compatible, () => { context.Options["DebugInformationFormat"] = "OldStyle"; context.CommandLineOptions["DebugInformationFormat"] = "/Z7"; }), + Options.Option(Options.Vc.General.DebugInformation.ProgramDatabase, () => { context.Options["DebugInformationFormat"] = "ProgramDatabase"; context.CommandLineOptions["DebugInformationFormat"] = "/Zi"; }), + Options.Option(Options.Vc.General.DebugInformation.ProgramDatabaseEnC, () => { context.Options["DebugInformationFormat"] = "EditAndContinue"; context.CommandLineOptions["DebugInformationFormat"] = "/ZI"; }) + ); + } + else + { + context.SelectOption + ( + Options.Option(Options.Vc.General.DebugInformation.Disable, () => { context.Options["DebugInformationFormat"] = "None"; context.CommandLineOptions["DebugInformationFormat"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.General.DebugInformation.C7Compatible, () => { context.Options["DebugInformationFormat"] = "OldStyle"; context.CommandLineOptions["DebugInformationFormat"] = "/Z7"; }), + Options.Option(Options.Vc.General.DebugInformation.ProgramDatabase, () => { context.Options["DebugInformationFormat"] = "ProgramDatabase"; context.CommandLineOptions["DebugInformationFormat"] = "/Zi"; }), + Options.Option(Options.Vc.General.DebugInformation.ProgramDatabaseEnC, () => { context.Options["DebugInformationFormat"] = "ProgramDatabase"; context.CommandLineOptions["DebugInformationFormat"] = "/Zi"; }) + ); + } + } + + private static void SelectPreferredToolArchitecture(IGenerationContext context) + { + if (context.DevelopmentEnvironment.IsVisualStudio()) + { + context.SelectOption + ( + Options.Option(Options.Vc.General.PreferredToolArchitecture.Default, () => { context.Options["PreferredToolArchitecture"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.General.PreferredToolArchitecture.x86, () => { context.Options["PreferredToolArchitecture"] = "x86"; }), + Options.Option(Options.Vc.General.PreferredToolArchitecture.x64, () => { context.Options["PreferredToolArchitecture"] = "x64"; }) + ); + } + } + + private static void SelectPlatformToolsetOption(IGenerationContext context, ProjectOptionsGenerationContext optionsContext) + { + context.SelectOption + ( + Options.Option(Options.Vc.General.PlatformToolset.Default, () => { context.Options["PlatformToolset"] = context.DevelopmentEnvironment.GetDefaultPlatformToolset(); }), + Options.Option(Options.Vc.General.PlatformToolset.v140, () => { context.Options["PlatformToolset"] = "v140"; }), + Options.Option(Options.Vc.General.PlatformToolset.v140_xp, () => { context.Options["PlatformToolset"] = "v140_xp"; }), + Options.Option(Options.Vc.General.PlatformToolset.v141, () => { context.Options["PlatformToolset"] = "v141"; }), + Options.Option(Options.Vc.General.PlatformToolset.v141_xp, () => { context.Options["PlatformToolset"] = "v141_xp"; }), + Options.Option(Options.Vc.General.PlatformToolset.v142, () => { context.Options["PlatformToolset"] = "v142"; }), + Options.Option(Options.Vc.General.PlatformToolset.LLVM, () => { context.Options["PlatformToolset"] = "llvm"; }), + Options.Option(Options.Vc.General.PlatformToolset.ClangCL, () => { context.Options["PlatformToolset"] = "ClangCL"; }) + ); + optionsContext.PlatformVcxproj.SetupPlatformToolsetOptions(context); + } + + private static void SelectPrecompiledHeaderOption(IGenerationContext context, ProjectOptionsGenerationContext optionsContext) + { + if (!optionsContext.PlatformVcxproj.HasPrecomp(context)) + { + context.Options["UsePrecompiledHeader"] = "NotUsing"; + context.Options["PrecompiledHeaderThrough"] = FileGeneratorUtilities.RemoveLineTag; + context.Options["PrecompiledHeaderFile"] = FileGeneratorUtilities.RemoveLineTag; + context.Options["PrecompiledHeaderOutputFileDirectory"] = FileGeneratorUtilities.RemoveLineTag; + context.CommandLineOptions["PrecompiledHeaderThrough"] = FileGeneratorUtilities.RemoveLineTag; + context.CommandLineOptions["PrecompiledHeaderFile"] = FileGeneratorUtilities.RemoveLineTag; + } + else + { + context.Options["UsePrecompiledHeader"] = "Use"; + context.Options["PrecompiledHeaderThrough"] = context.Configuration.PrecompHeader; + string pchOutputDirectoryRelative = string.IsNullOrEmpty(context.Configuration.PrecompHeaderOutputFolder) ? optionsContext.IntermediateDirectoryRelative : Util.PathGetRelative(context.ProjectDirectory, context.Configuration.PrecompHeaderOutputFolder); + context.Options["PrecompiledHeaderFile"] = Path.Combine(pchOutputDirectoryRelative, $"{context.Configuration.Project.Name}.pch"); + context.Options["PrecompiledHeaderOutputFileDirectory"] = pchOutputDirectoryRelative; + context.CommandLineOptions["PrecompiledHeaderThrough"] = context.Options["PrecompiledHeaderThrough"]; + context.CommandLineOptions["PrecompiledHeaderFile"] = FormatCommandLineOptionPath(context, context.Options["PrecompiledHeaderFile"]); + + if (!optionsContext.PlatformDescriptor.HasPrecompiledHeaderSupport) + throw new Error("Precompiled header not supported for spu configuration: {0}", context.Configuration); + } + } + + private void GenerateLibrarianOptions(IGenerationContext context, ProjectOptionsGenerationContext optionsContext) + { + Compiler compiler = context.Configuration.Target.GetFragment(); + + switch (compiler) + { + case Compiler.MSVC: + GenerateMSVCLibrarianOptions(context, optionsContext); + break; + case Compiler.Clang: + GenerateClangLibrarianOptions(context, optionsContext); + break; + case Compiler.GCC: + GenerateGccLibrarianOptions(context, optionsContext); + break; + default: + throw new Error("Unknown compiler used for options generation"); + } + } + + private void GenerateMSVCLibrarianOptions(IGenerationContext context, ProjectOptionsGenerationContext optionsContext) + { + context.SelectOption + ( + Options.Option(Options.Vc.Librarian.TreatLibWarningAsErrors.Disable, () => { context.Options["TreatLibWarningAsErrors"] = FileGeneratorUtilities.RemoveLineTag; context.CommandLineOptions["TreatLibWarningAsErrors"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Librarian.TreatLibWarningAsErrors.Enable, () => { context.Options["TreatLibWarningAsErrors"] = "true"; context.CommandLineOptions["TreatLibWarningAsErrors"] = "/WX"; }) + ); + } + private void GenerateClangLibrarianOptions(IGenerationContext context, ProjectOptionsGenerationContext optionsContext) + { + context.SelectOption + ( + Options.Option(Options.Vc.Librarian.TreatLibWarningAsErrors.Disable, () => { context.Options["TreatLibWarningAsErrors"] = FileGeneratorUtilities.RemoveLineTag; context.CommandLineOptions["TreatLibWarningAsErrors"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Librarian.TreatLibWarningAsErrors.Enable, () => { context.Options["TreatLibWarningAsErrors"] = "true"; context.CommandLineOptions["TreatLibWarningAsErrors"] = "-Werror"; }) + ); + } + private void GenerateGccLibrarianOptions(IGenerationContext context, ProjectOptionsGenerationContext optionsContext) + { + context.SelectOption + ( + Options.Option(Options.Vc.Librarian.TreatLibWarningAsErrors.Disable, () => { context.Options["TreatLibWarningAsErrors"] = FileGeneratorUtilities.RemoveLineTag; context.CommandLineOptions["TreatLibWarningAsErrors"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Librarian.TreatLibWarningAsErrors.Enable, () => { context.Options["TreatLibWarningAsErrors"] = "true"; context.CommandLineOptions["TreatLibWarningAsErrors"] = "-Werror"; }) + ); + } + + private void GenerateLinkerOptions(IGenerationContext context, ProjectOptionsGenerationContext optionsContext) + { + Compiler compiler = context.Configuration.Target.GetFragment(); + + switch (compiler) + { + case Compiler.MSVC: + GenerateMSVCLinkerOptions(context, optionsContext); + break; + case Compiler.Clang: + GenerateClangLinkerOptions(context, optionsContext); + break; + case Compiler.GCC: + GenerateGccLinkerOptions(context, optionsContext); + break; + default: + throw new Error("Unknown compiler used for options generation"); + } + } + + private void GenerateMSVCLinkerOptions(IGenerationContext context, ProjectOptionsGenerationContext optionsContext) + { + var configurationTasks = PlatformRegistry.Get(context.Configuration.Platform); + + context.Options["ImportLibrary"] = FileGeneratorUtilities.RemoveLineTag; + context.LinkerCommandLineOptions["ImportLibrary"] = FileGeneratorUtilities.RemoveLineTag; + context.Options["OutputFileName"] = context.Configuration.TargetFileFullName; + context.Options["OutputFileExtension"] = context.Configuration.TargetFileFullExtension; + + context.Options["AdditionalDeploymentFolders"] = ""; + + switch (context.Configuration.Output) + { + case Project.Configuration.OutputType.Dll: + case Project.Configuration.OutputType.DotNetClassLibrary: + case Project.Configuration.OutputType.Exe: + case Project.Configuration.OutputType.DotNetConsoleApp: + case Project.Configuration.OutputType.DotNetWindowsApp: + case Project.Configuration.OutputType.IosApp: + case Project.Configuration.OutputType.IosTestBundle: + context.Options["OutputFile"] = optionsContext.OutputDirectoryRelative + Util.WindowsSeparator + context.Configuration.TargetFileFullNameWithExtension; + if (context.Configuration.Output == Project.Configuration.OutputType.Dll) + { + string importLibRelative = optionsContext.OutputLibraryDirectoryRelative + Util.WindowsSeparator + context.Configuration.TargetFileFullName + ".lib"; + context.Options["ImportLibrary"] = importLibRelative; + context.LinkerCommandLineOptions["ImportLibrary"] = "/IMPLIB:" + FormatCommandLineOptionPath(context, importLibRelative); + } + break; + case Project.Configuration.OutputType.Lib: + context.Options["OutputFile"] = optionsContext.OutputLibraryDirectoryRelative + Util.WindowsSeparator + context.Configuration.TargetFileFullNameWithExtension; + break; + case Project.Configuration.OutputType.Utility: + case Project.Configuration.OutputType.None: + context.Options["OutputFile"] = FileGeneratorUtilities.RemoveLineTag; + context.Options["OutputFileExtension"] = FileGeneratorUtilities.RemoveLineTag; + context.Options["OutputFileName"] = FileGeneratorUtilities.RemoveLineTag; + break; + default: + throw new ArgumentOutOfRangeException(); + } + + context.SelectOption + ( + Options.Option(Options.Vc.Linker.ShowProgress.NotSet, () => { context.Options["ShowProgress"] = "NotSet"; context.LinkerCommandLineOptions["ShowProgress"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Linker.ShowProgress.LinkVerbose, () => { context.Options["ShowProgress"] = "LinkVerbose"; context.LinkerCommandLineOptions["ShowProgress"] = "/VERBOSE"; }), + Options.Option(Options.Vc.Linker.ShowProgress.LinkVerboseLib, () => { context.Options["ShowProgress"] = "LinkVerboseLib"; context.LinkerCommandLineOptions["ShowProgress"] = "/VERBOSE:Lib"; }), + Options.Option(Options.Vc.Linker.ShowProgress.LinkVerboseICF, () => { context.Options["ShowProgress"] = "LinkVerboseICF"; context.LinkerCommandLineOptions["ShowProgress"] = "/VERBOSE:ICF"; }), + Options.Option(Options.Vc.Linker.ShowProgress.LinkVerboseREF, () => { context.Options["ShowProgress"] = "LinkVerboseREF"; context.LinkerCommandLineOptions["ShowProgress"] = "/VERBOSE:REF"; }), + Options.Option(Options.Vc.Linker.ShowProgress.LinkVerboseSAFESEH, () => { context.Options["ShowProgress"] = "LinkVerboseSAFESEH"; context.LinkerCommandLineOptions["ShowProgress"] = "/VERBOSE:SAFESEH"; }), + Options.Option(Options.Vc.Linker.ShowProgress.LinkVerboseCLR, () => { context.Options["ShowProgress"] = "LinkVerboseCLR"; context.LinkerCommandLineOptions["ShowProgress"] = "/VERBOSE:CLR"; }) + ); + + //Incremental + // Default LinkIncremental="0" + // Disable LinkIncremental="1" /INCREMENTAL:NO + // Enable LinkIncremental="2" /INCREMENTAL + context.SelectOption + ( + Options.Option(Options.Vc.Linker.Incremental.Default, () => { context.Options["LinkIncremental"] = FileGeneratorUtilities.RemoveLineTag; context.LinkerCommandLineOptions["LinkIncremental"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Linker.Incremental.Disable, () => { context.Options["LinkIncremental"] = "false"; context.LinkerCommandLineOptions["LinkIncremental"] = "/INCREMENTAL:NO"; }), + Options.Option(Options.Vc.Linker.Incremental.Enable, () => { context.Options["LinkIncremental"] = "true"; context.LinkerCommandLineOptions["LinkIncremental"] = "/INCREMENTAL"; }) + ); + + //EmbedManifest + // Yes EmbedManifest="true" + // No EmbedManifest="false" + context.SelectOption + ( + Options.Option(Options.Vc.Linker.EmbedManifest.Default, () => { context.Options["EmbedManifest"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Linker.EmbedManifest.Yes, () => { context.Options["EmbedManifest"] = "true"; }), + Options.Option(Options.Vc.Linker.EmbedManifest.No, () => { context.Options["EmbedManifest"] = "false"; }) + ); + + //SuppressStartupBanner + // Disable SuppressStartupBanner="false" + // Enable SuppressStartupBanner="true" /NOLOGO + context.SelectOption + ( + Options.Option(Options.Vc.Linker.SuppressStartupBanner.Disable, () => { context.Options["SuppressStartupBanner"] = "false"; context.LinkerCommandLineOptions["LinkerSuppressStartupBanner"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Linker.SuppressStartupBanner.Enable, () => { context.Options["SuppressStartupBanner"] = "true"; context.LinkerCommandLineOptions["LinkerSuppressStartupBanner"] = "/NOLOGO"; }) + ); + + //LinkLibraryDependencies + // Enable LinkLibraryDependencies="true" + // Disable LinkLibraryDependencies="false" + context.SelectOption + ( + Options.Option(Options.Vc.Linker.LinkLibraryDependencies.Default, () => { context.Options["LinkLibraryDependencies"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Linker.LinkLibraryDependencies.Enable, () => { context.Options["LinkLibraryDependencies"] = "true"; }), + Options.Option(Options.Vc.Linker.LinkLibraryDependencies.Disable, () => { context.Options["LinkLibraryDependencies"] = "false"; }) + ); + + //ReferenceOutputAssembly + // Enable ReferenceOutputAssembly="true" + // Disable ReferenceOutputAssembly="false" + context.SelectOption + ( + Options.Option(Options.Vc.Linker.ReferenceOutputAssembly.Default, () => { context.Options["ReferenceOutputAssembly"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Linker.ReferenceOutputAssembly.Enable, () => { context.Options["ReferenceOutputAssembly"] = "true"; }), + Options.Option(Options.Vc.Linker.ReferenceOutputAssembly.Disable, () => { context.Options["ReferenceOutputAssembly"] = "false"; }) + ); + + //CopyLocalSatelliteAssemblies + // Enable CopyLocalSatelliteAssemblies="true" + // Disable CopyLocalSatelliteAssemblies="false" + context.SelectOption + ( + Options.Option(Options.Vc.Linker.CopyLocalSatelliteAssemblies.Default, () => { context.Options["CopyLocalSatelliteAssemblies"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Linker.CopyLocalSatelliteAssemblies.Enable, () => { context.Options["CopyLocalSatelliteAssemblies"] = "true"; }), + Options.Option(Options.Vc.Linker.CopyLocalSatelliteAssemblies.Disable, () => { context.Options["CopyLocalSatelliteAssemblies"] = "false"; }) + ); + + //IgnoreImportLibrary + // Enable IgnoreImportLibrary="true" + // Disable IgnoreImportLibrary="false" + context.SelectOption + ( + Options.Option(Options.Vc.Linker.IgnoreImportLibrary.Enable, () => { context.Options["IgnoreImportLibrary"] = "true"; }), + Options.Option(Options.Vc.Linker.IgnoreImportLibrary.Disable, () => { context.Options["IgnoreImportLibrary"] = "false"; }) + ); + + if (Options.GetObject(context.Configuration) == Options.Vc.CodeAnalysis.RunCodeAnalysis.Enable) + { + if (context.Configuration.IsFastBuild) + throw new NotImplementedException("Sharpmake does not support code analysis in fastbuild targets yet!"); + + //RunCodeAnalysis + // Enable RunCodeAnalysis="true" + context.Options["RunCodeAnalysis"] = "true"; + + //MicrosoftCodeAnalysis + // Enable MicrosoftCodeAnalysis="true" + // Disable MicrosoftCodeAnalysis="false" + context.SelectOption + ( + Options.Option(Options.Vc.CodeAnalysis.MicrosoftCodeAnalysis.Enable, () => { context.Options["MicrosoftCodeAnalysis"] = "true"; }), + Options.Option(Options.Vc.CodeAnalysis.MicrosoftCodeAnalysis.Disable, () => { context.Options["MicrosoftCodeAnalysis"] = FileGeneratorUtilities.RemoveLineTag; }) + ); + + //ClangTidyCodeAnalysis + // Enable ClangTidyCodeAnalysis="true" + // Disable ClangTidyCodeAnalysis="false" + context.SelectOption + ( + Options.Option(Options.Vc.CodeAnalysis.ClangTidyCodeAnalysis.Enable, () => { context.Options["ClangTidyCodeAnalysis"] = "true"; }), + Options.Option(Options.Vc.CodeAnalysis.ClangTidyCodeAnalysis.Disable, () => { context.Options["ClangTidyCodeAnalysis"] = FileGeneratorUtilities.RemoveLineTag; }) + ); + + //Code analysis excludes paths + context.Options["CAexcludePaths"] = string.Join(";", Options.GetObjects(context.Configuration).Select(optionPath => optionPath.Path)); + } + else + { + //RunCodeAnalysis + // Disable nothing + context.Options["RunCodeAnalysis"] = FileGeneratorUtilities.RemoveLineTag; + context.Options["MicrosoftCodeAnalysis"] = FileGeneratorUtilities.RemoveLineTag; + context.Options["ClangTidyCodeAnalysis"] = FileGeneratorUtilities.RemoveLineTag; + context.Options["CAexcludePaths"] = FileGeneratorUtilities.RemoveLineTag; + } + + + //UseLibraryDependencyInputs + // Enable UseLibraryDependencyInputs="true" + // Disable UseLibraryDependencyInputs="false" + context.SelectOption + ( + Options.Option(Options.Vc.Linker.UseLibraryDependencyInputs.Default, () => { context.Options["UseLibraryDependencyInputs"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Linker.UseLibraryDependencyInputs.Enable, () => { context.Options["UseLibraryDependencyInputs"] = "true"; }), + Options.Option(Options.Vc.Linker.UseLibraryDependencyInputs.Disable, () => { context.Options["UseLibraryDependencyInputs"] = "false"; }) + ); + + //DisableFastUpToDateCheck + // Enable DisableFastUpToDateCheck="true" + // Disable DisableFastUpToDateCheck="false" + context.SelectOption + ( + Options.Option(Options.Vc.General.DisableFastUpToDateCheck.Enable, () => { context.Options["DisableFastUpToDateCheck"] = "true"; }), + Options.Option(Options.Vc.General.DisableFastUpToDateCheck.Disable, () => { context.Options["DisableFastUpToDateCheck"] = FileGeneratorUtilities.RemoveLineTag; }) + ); + + //EnableManagedIncrementalBuild + context.SelectOption + ( + Options.Option(Options.Vc.General.EnableManagedIncrementalBuild.Enable, () => { context.Options["EnableManagedIncrementalBuild"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.General.EnableManagedIncrementalBuild.Disable, () => { context.Options["EnableManagedIncrementalBuild"] = "false"; }) + ); + + //RandomizedBaseAddress + context.SelectOption + ( + Options.Option(Options.Vc.Linker.RandomizedBaseAddress.Default, () => { context.Options["RandomizedBaseAddress"] = FileGeneratorUtilities.RemoveLineTag; context.LinkerCommandLineOptions["RandomizedBaseAddress"] = "/DYNAMICBASE"; }), + Options.Option(Options.Vc.Linker.RandomizedBaseAddress.Enable, () => { context.Options["RandomizedBaseAddress"] = "true"; context.LinkerCommandLineOptions["RandomizedBaseAddress"] = "/DYNAMICBASE"; }), + Options.Option(Options.Vc.Linker.RandomizedBaseAddress.Disable, () => { context.Options["RandomizedBaseAddress"] = "false"; context.LinkerCommandLineOptions["RandomizedBaseAddress"] = "/DYNAMICBASE:NO"; }) + ); + + // Delay Loaded DLLs + Strings delayedDLLs = Options.GetStrings(context.Configuration); + if (delayedDLLs.Any()) + { + context.Options["DelayLoadedDLLs"] = delayedDLLs.JoinStrings(";"); + + StringBuilder result = new StringBuilder(); + foreach (string delayedDLL in delayedDLLs) + result.Append(@"/DELAYLOAD:""" + delayedDLL + @""" "); + result.Remove(result.Length - 1, 1); + context.LinkerCommandLineOptions["DelayLoadedDLLs"] = result.ToString(); + } + else + { + context.Options["DelayLoadedDLLs"] = FileGeneratorUtilities.RemoveLineTag; + context.LinkerCommandLineOptions["DelayLoadedDLLs"] = FileGeneratorUtilities.RemoveLineTag; + } + + // Set module definition + if (!string.IsNullOrEmpty(context.Configuration.ModuleDefinitionFile)) + { + var filePath = Util.PathGetRelative(context.ProjectDirectory, context.Configuration.ModuleDefinitionFile); + context.Options["ModuleDefinitionFile"] = filePath; + context.LinkerCommandLineOptions["ModuleDefinitionFile"] = "/DEF:" + FormatCommandLineOptionPath(context, filePath); + } + else + { + context.Options["ModuleDefinitionFile"] = FileGeneratorUtilities.RemoveLineTag; + context.LinkerCommandLineOptions["ModuleDefinitionFile"] = FileGeneratorUtilities.RemoveLineTag; + } + + //IgnoreAllDefaultLibraries + // Enable IgnoreAllDefaultLibraries="true" /NODEFAULTLIB + // Disable IgnoreAllDefaultLibraries="false" + context.SelectOption + ( + Options.Option(Options.Vc.Linker.IgnoreAllDefaultLibraries.Enable, () => { context.Options["IgnoreAllDefaultLibraries"] = "true"; context.LinkerCommandLineOptions["IgnoreAllDefaultLibraries"] = "/NODEFAULTLIB"; }), + Options.Option(Options.Vc.Linker.IgnoreAllDefaultLibraries.Disable, () => { context.Options["IgnoreAllDefaultLibraries"] = "false"; context.LinkerCommandLineOptions["IgnoreAllDefaultLibraries"] = FileGeneratorUtilities.RemoveLineTag; }) + ); + + //GenerateManifest + // Enable GenerateManifest="true" /MANIFEST + // Disable GenerateManifest="false" + SelectGenerateManifestOption(context, optionsContext); + + SelectGenerateDebugInformationOption(context, optionsContext); + + // GenerateMapFile + SelectGenerateMapFileOption(context, optionsContext); + + //MapExports + // Enable MapExports="true" /MAPINFO:EXPORTS + // Disable MapExports="false" + context.SelectOption + ( + Options.Option(Options.Vc.Linker.MapExports.Enable, () => { context.Options["MapExports"] = "true"; context.LinkerCommandLineOptions["MapExports"] = "/MAPINFO:EXPORTS"; }), + Options.Option(Options.Vc.Linker.MapExports.Disable, () => { context.Options["MapExports"] = "false"; context.LinkerCommandLineOptions["MapExports"] = FileGeneratorUtilities.RemoveLineTag; }) + ); + + //AssemblyDebug + // NoDebuggableAttributeEmitted AssemblyDebug="0" + // RuntimeTrackingAndDisableOptimizations AssemblyDebug="1" /ASSEMBLYDEBUG + // NoRuntimeTrackingAndEnableOptimizations AssemblyDebug="2" /ASSEMBLYDEBUG:DISABLE + context.SelectOption + ( + Options.Option(Options.Vc.Linker.AssemblyDebug.NoDebuggableAttributeEmitted, () => { context.Options["AssemblyDebug"] = FileGeneratorUtilities.RemoveLineTag; context.LinkerCommandLineOptions["AssemblyDebug"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Linker.AssemblyDebug.RuntimeTrackingAndDisableOptimizations, () => { context.Options["AssemblyDebug"] = "true"; context.LinkerCommandLineOptions["AssemblyDebug"] = "/ASSEMBLYDEBUG"; }), + Options.Option(Options.Vc.Linker.AssemblyDebug.NoRuntimeTrackingAndEnableOptimizations, () => { context.Options["AssemblyDebug"] = "false"; context.LinkerCommandLineOptions["AssemblyDebug"] = "/ASSEMBLYDEBUG:DISABLE"; }) + ); + + context.SelectOption + ( + Options.Option(Options.Vc.Linker.SubSystem.NotSet, () => { context.Options["SubSystem"] = "NotSet"; context.LinkerCommandLineOptions["SubSystem"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Linker.SubSystem.Console, () => { context.Options["SubSystem"] = "Console"; context.LinkerCommandLineOptions["SubSystem"] = "/SUBSYSTEM:CONSOLE"; }), + Options.Option(Options.Vc.Linker.SubSystem.Windows, () => { context.Options["SubSystem"] = "Windows"; context.LinkerCommandLineOptions["SubSystem"] = "/SUBSYSTEM:WINDOWS"; }), + Options.Option(Options.Vc.Linker.SubSystem.Native, () => { context.Options["SubSystem"] = "Native"; context.LinkerCommandLineOptions["SubSystem"] = "/SUBSYSTEM:NATIVE"; }), + Options.Option(Options.Vc.Linker.SubSystem.EFI_Application, () => { context.Options["SubSystem"] = "EFI Application"; context.LinkerCommandLineOptions["SubSystem"] = "/SUBSYSTEM:EFI_APPLICATION"; }), + Options.Option(Options.Vc.Linker.SubSystem.EFI_Boot_Service_Driver, () => { context.Options["SubSystem"] = "EFI Boot Service Driver"; context.LinkerCommandLineOptions["SubSystem"] = "/SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER"; }), + Options.Option(Options.Vc.Linker.SubSystem.EFI_ROM, () => { context.Options["SubSystem"] = "EFI ROM"; context.LinkerCommandLineOptions["SubSystem"] = "/SUBSYSTEM:EFI_ROM"; }), + Options.Option(Options.Vc.Linker.SubSystem.EFI_Runtime, () => { context.Options["SubSystem"] = "EFI Runtime"; context.LinkerCommandLineOptions["SubSystem"] = "/SUBSYSTEM:EFI_RUNTIME_DRIVER"; }), + Options.Option(Options.Vc.Linker.SubSystem.POSIX, () => { context.Options["SubSystem"] = "POSIX"; context.LinkerCommandLineOptions["SubSystem"] = "/SUBSYSTEM:POSIX"; }) + ); + + + //HeapSize + //HeapReserveSize + // HeapReserveSize="0" /HEAP:reserve + //HeapCommitSize + // HeapCommitSize="0" /HEAP:reserve,commit + Options.Vc.Linker.HeapSize heap = Options.GetObject(context.Configuration); + if (heap == null) + { + context.Options["HeapReserveSize"] = FileGeneratorUtilities.RemoveLineTag; + context.Options["HeapCommitSize"] = FileGeneratorUtilities.RemoveLineTag; + context.LinkerCommandLineOptions["HeapReserveSize"] = FileGeneratorUtilities.RemoveLineTag; + context.LinkerCommandLineOptions["HeapCommitSize"] = FileGeneratorUtilities.RemoveLineTag; + } + else + { + context.Options["HeapReserveSize"] = heap.ReserveSize.ToString(); + context.Options["HeapCommitSize"] = heap.CommintSize.ToString(); + context.LinkerCommandLineOptions["HeapReserveSize"] = "/HEAP:reserve"; + context.LinkerCommandLineOptions["HeapCommitSize"] = "/HEAP:reserve,commit"; + } + + //StackSize + //StackReserveSize + // StackReserveSize="0" /STACK:reserve + //StackCommitSize + // StackCommitSize="0" /STACK:reserve,commit + Options.Vc.Linker.StackSize stack = Options.GetObject(context.Configuration); + if (stack == null) + { + context.Options["StackReserveSize"] = FileGeneratorUtilities.RemoveLineTag; + context.Options["StackCommitSize"] = FileGeneratorUtilities.RemoveLineTag; + context.LinkerCommandLineOptions["StackReserveSize"] = FileGeneratorUtilities.RemoveLineTag; + context.LinkerCommandLineOptions["StackCommitSize"] = FileGeneratorUtilities.RemoveLineTag; + } + else + { + context.Options["StackReserveSize"] = stack.ReserveSize.ToString(); + context.Options["StackCommitSize"] = stack.CommintSize.ToString(); + if (stack.CommintSize > 0) + { + context.LinkerCommandLineOptions["StackReserveSize"] = FileGeneratorUtilities.RemoveLineTag; + context.LinkerCommandLineOptions["StackCommitSize"] = "/STACK:" + stack.ReserveSize + "," + stack.CommintSize; + } + else + { + context.LinkerCommandLineOptions["StackReserveSize"] = "/STACK:" + stack.ReserveSize; + context.LinkerCommandLineOptions["StackCommitSize"] = FileGeneratorUtilities.RemoveLineTag; + } + } + + context.SelectOption + ( + Options.Option(Options.Vc.Linker.AllowIsolation.Enabled, () => { context.Options["AllowIsolation"] = FileGeneratorUtilities.RemoveLineTag; context.LinkerCommandLineOptions["AllowIsolation"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Linker.AllowIsolation.Disabled, () => { context.Options["AllowIsolation"] = "false"; context.LinkerCommandLineOptions["AllowIsolation"] = "/ALLOWISOLATION:NO"; }) + ); + + //LargeAddress + // Default LargeAddressAware="0" + // NotSupportLargerThan2Gb LargeAddressAware="1" /LARGEADDRESSAWARE:NO + // SupportLargerThan2Gb LargeAddressAware="2" /LARGEADDRESSAWARE + context.SelectOption + ( + Options.Option(Options.Vc.Linker.LargeAddress.Default, () => { context.Options["LargeAddressAware"] = "true"; context.LinkerCommandLineOptions["LargeAddressAware"] = "/LARGEADDRESSAWARE"; }), + Options.Option(Options.Vc.Linker.LargeAddress.NotSupportLargerThan2Gb, () => { context.Options["LargeAddressAware"] = "false"; context.LinkerCommandLineOptions["LargeAddressAware"] = "/LARGEADDRESSAWARE:NO"; }), + Options.Option(Options.Vc.Linker.LargeAddress.SupportLargerThan2Gb, () => { context.Options["LargeAddressAware"] = "true"; context.LinkerCommandLineOptions["LargeAddressAware"] = "/LARGEADDRESSAWARE"; }) + ); + + Options.Vc.Linker.BaseAddress baseAddress = Options.GetObject(context.Configuration); + if (baseAddress != null && baseAddress.Value.Length > 0) + { + context.Options["BaseAddress"] = baseAddress.Value; + context.LinkerCommandLineOptions["BaseAddress"] = @"/BASE:""" + (baseAddress.Value) + @""""; + } + else + { + context.Options["BaseAddress"] = FileGeneratorUtilities.RemoveLineTag; + context.LinkerCommandLineOptions["BaseAddress"] = FileGeneratorUtilities.RemoveLineTag; + } + + //Reference + // Default OptimizeReferences="0" + // KeepUnreferencedData OptimizeReferences="1" /OPT:NOREF + // EliminateUnreferencedData OptimizeReferences="2" /OPT:REF + context.SelectOption + ( + Options.Option(Options.Vc.Linker.Reference.KeepUnreferencedData, () => { context.Options["OptimizeReferences"] = "false"; context.LinkerCommandLineOptions["OptimizeReference"] = "/OPT:NOREF"; }), + Options.Option(Options.Vc.Linker.Reference.EliminateUnreferencedData, () => { context.Options["OptimizeReferences"] = "true"; context.LinkerCommandLineOptions["OptimizeReference"] = "/OPT:REF"; }) + ); + + //EnableCOMDATFolding + // Default EnableCOMDATFolding="0" + // DoNotRemoveRedundantCOMDATs EnableCOMDATFolding="1" /OPT:NOICF + // RemoveRedundantCOMDATs EnableCOMDATFolding="2" /OPT:ICF + context.SelectOption + ( + Options.Option(Options.Vc.Linker.EnableCOMDATFolding.DoNotRemoveRedundantCOMDATs, () => { context.Options["EnableCOMDATFolding"] = "false"; context.LinkerCommandLineOptions["EnableCOMDATFolding"] = "/OPT:NOICF"; }), + Options.Option(Options.Vc.Linker.EnableCOMDATFolding.RemoveRedundantCOMDATs, () => { context.Options["EnableCOMDATFolding"] = "true"; context.LinkerCommandLineOptions["EnableCOMDATFolding"] = "/OPT:ICF"; }) + ); + + //FixedBaseAddress + // Default FixedBaseAddress="0" + // Enable FixedBaseAddress="1" /FIXED + // Disable FixedBaseAddress="2" /FIXED:NO + context.SelectOption + ( + Options.Option(Options.Vc.Linker.FixedBaseAddress.Default, () => { context.Options["FixedBaseAddress"] = FileGeneratorUtilities.RemoveLineTag; context.LinkerCommandLineOptions["FixedBaseAddress"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Linker.FixedBaseAddress.Enable, () => { context.Options["FixedBaseAddress"] = "true"; context.LinkerCommandLineOptions["FixedBaseAddress"] = "/FIXED"; }), + Options.Option(Options.Vc.Linker.FixedBaseAddress.Disable, () => { context.Options["FixedBaseAddress"] = "false"; context.LinkerCommandLineOptions["FixedBaseAddress"] = "/FIXED:NO"; }) + ); + + //GenerateWindowsMetadata + // Default GenerateWindowsMetadata="0" + // Enable GenerateWindowsMetadata="1" /WINMD + // Disable GenerateWindowsMetadata="2" /WINMD:NO + context.SelectOption + ( + Options.Option(Options.Vc.Linker.GenerateWindowsMetadata.Default, () => + { + context.Options["GenerateWindowsMetadata"] = FileGeneratorUtilities.RemoveLineTag; + context.Options["WindowsMetadataFile"] = FileGeneratorUtilities.RemoveLineTag; + context.LinkerCommandLineOptions["GenerateWindowsMetadata"] = FileGeneratorUtilities.RemoveLineTag; + context.LinkerCommandLineOptions["WindowsMetadataFile"] = FileGeneratorUtilities.RemoveLineTag; + }), + Options.Option(Options.Vc.Linker.GenerateWindowsMetadata.Enable, () => + { + context.Options["GenerateWindowsMetadata"] = "true"; + string windowsMetadataFile = @"$(OutDir)\$(RootNamespace).winmd"; + context.Options["WindowsMetadataFile"] = windowsMetadataFile; + context.LinkerCommandLineOptions["GenerateWindowsMetadata"] = "/WINMD"; + context.LinkerCommandLineOptions["WindowsMetadataFile"] = @"/WINMDFILE:""" + windowsMetadataFile + @""""; + }), + Options.Option(Options.Vc.Linker.GenerateWindowsMetadata.Disable, () => + { + context.Options["GenerateWindowsMetadata"] = "false"; + context.Options["WindowsMetadataFile"] = FileGeneratorUtilities.RemoveLineTag; + context.LinkerCommandLineOptions["GenerateWindowsMetadata"] = "/WINMD:NO"; + context.LinkerCommandLineOptions["WindowsMetadataFile"] = FileGeneratorUtilities.RemoveLineTag; + }) + ); + + //LinkTimeCodeGeneration + // Default LinkTimeCodeGeneration="0" + // UseLinkTimeCodeGeneration LinkTimeCodeGeneration="1" /ltcg + // ProfileGuidedOptimizationInstrument LinkTimeCodeGeneration="2" /ltcg:pginstrument + // ProfileGuidedOptimizationOptimize LinkTimeCodeGeneration="3" /ltcg:pgoptimize + // ProfileGuidedOptimizationUpdate LinkTimeCodeGeneration="4" /ltcg:pgupdate + bool profileGuideOptimization = false; + + if (context.Configuration.Output == Project.Configuration.OutputType.Lib) + { + context.SelectOption + ( + Options.Option(Options.Vc.Linker.LinkTimeCodeGeneration.Default, () => { context.Options["LinkTimeCodeGeneration"] = "false"; context.LinkerCommandLineOptions["LinkTimeCodeGeneration"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Linker.LinkTimeCodeGeneration.UseLinkTimeCodeGeneration, () => { context.Options["LinkTimeCodeGeneration"] = "true"; context.LinkerCommandLineOptions["LinkTimeCodeGeneration"] = "/LTCG"; }), + Options.Option(Options.Vc.Linker.LinkTimeCodeGeneration.UseFastLinkTimeCodeGeneration, () => { context.Options["LinkTimeCodeGeneration"] = "true"; context.LinkerCommandLineOptions["LinkTimeCodeGeneration"] = "/LTCG"; }), + Options.Option(Options.Vc.Linker.LinkTimeCodeGeneration.ProfileGuidedOptimizationInstrument, () => { context.Options["LinkTimeCodeGeneration"] = "true"; context.LinkerCommandLineOptions["LinkTimeCodeGeneration"] = "/LTCG"; }), + Options.Option(Options.Vc.Linker.LinkTimeCodeGeneration.ProfileGuidedOptimizationOptimize, () => { context.Options["LinkTimeCodeGeneration"] = "true"; context.LinkerCommandLineOptions["LinkTimeCodeGeneration"] = "/LTCG"; }), + Options.Option(Options.Vc.Linker.LinkTimeCodeGeneration.ProfileGuidedOptimizationUpdate, () => { context.Options["LinkTimeCodeGeneration"] = "true"; context.LinkerCommandLineOptions["LinkTimeCodeGeneration"] = "/LTCG"; }) + ); + } + else + { + context.SelectOption + ( + Options.Option(Options.Vc.Linker.LinkTimeCodeGeneration.Default, () => { context.Options["LinkTimeCodeGeneration"] = "Default"; context.LinkerCommandLineOptions["LinkTimeCodeGeneration"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Linker.LinkTimeCodeGeneration.UseFastLinkTimeCodeGeneration, () => { context.Options["LinkTimeCodeGeneration"] = "UseFastLinkTimeCodeGeneration"; context.LinkerCommandLineOptions["LinkTimeCodeGeneration"] = "/LTCG:incremental"; }), + Options.Option(Options.Vc.Linker.LinkTimeCodeGeneration.UseLinkTimeCodeGeneration, () => { context.Options["LinkTimeCodeGeneration"] = "UseLinkTimeCodeGeneration"; context.LinkerCommandLineOptions["LinkTimeCodeGeneration"] = "/LTCG"; }), + Options.Option(Options.Vc.Linker.LinkTimeCodeGeneration.ProfileGuidedOptimizationInstrument, () => { context.Options["LinkTimeCodeGeneration"] = "PGInstrument"; profileGuideOptimization = true; context.LinkerCommandLineOptions["LinkTimeCodeGeneration"] = "/LTCG:PGInstrument"; }), + Options.Option(Options.Vc.Linker.LinkTimeCodeGeneration.ProfileGuidedOptimizationOptimize, () => { context.Options["LinkTimeCodeGeneration"] = "PGOptimization"; profileGuideOptimization = true; context.LinkerCommandLineOptions["LinkTimeCodeGeneration"] = "/LTCG:PGOptimize"; }), + Options.Option(Options.Vc.Linker.LinkTimeCodeGeneration.ProfileGuidedOptimizationUpdate, () => { context.Options["LinkTimeCodeGeneration"] = "PGUpdate"; profileGuideOptimization = true; context.LinkerCommandLineOptions["LinkTimeCodeGeneration"] = "/LTCG:PGUpdate"; }) + ); + } + + + if (profileGuideOptimization) + { + string profileGuidedDatabase = optionsContext.OutputDirectoryRelative + Util.WindowsSeparator + context.Configuration.TargetFileFullName + ".pgd"; + context.Options["ProfileGuidedDatabase"] = profileGuidedDatabase; + context.LinkerCommandLineOptions["ProfileGuidedDatabase"] = @"/PGD:""" + profileGuidedDatabase + @""""; + } + else + { + context.Options["ProfileGuidedDatabase"] = ""; + context.LinkerCommandLineOptions["ProfileGuidedDatabase"] = FileGeneratorUtilities.RemoveLineTag; + } + + // FunctionOrder + // FunctionOrder="@..\path_to\order.txt" /ORDER:"@..\path_to\order.txt" + Options.Vc.Linker.FunctionOrder fctOrder = Options.GetObject(context.Configuration); + context.Options["FunctionOrder"] = (fctOrder != null) ? fctOrder.Order : FileGeneratorUtilities.RemoveLineTag; + context.LinkerCommandLineOptions["FunctionOrder"] = (fctOrder != null) ? @"/ORDER:@""" + fctOrder.Order + @"""" : FileGeneratorUtilities.RemoveLineTag; + + context.SelectOption + ( + Options.Option(Options.Vc.Linker.ForceFileOutput.Default, () => { context.Options["ForceFileOutput"] = FileGeneratorUtilities.RemoveLineTag; context.LinkerCommandLineOptions["ForceFileOutput"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Linker.ForceFileOutput.Enable, () => { context.Options["ForceFileOutput"] = "Enabled"; context.LinkerCommandLineOptions["ForceFileOutput"] = "/FORCE"; }), + Options.Option(Options.Vc.Linker.ForceFileOutput.MultiplyDefinedSymbolOnly, () => { context.Options["ForceFileOutput"] = "MultiplyDefinedSymbolOnly"; context.LinkerCommandLineOptions["ForceFileOutput"] = "/FORCE:MULTIPLE"; }), + Options.Option(Options.Vc.Linker.ForceFileOutput.UndefinedSymbolOnly, () => { context.Options["ForceFileOutput"] = "UndefinedSymbolOnly"; context.LinkerCommandLineOptions["ForceFileOutput"] = "/FORCE:UNRESOLVED"; }) + ); + + context.SelectOption + ( + Options.Option(Options.Vc.Linker.CreateHotPatchableImage.Disable, () => { context.Options["LinkerCreateHotPatchableImage"] = FileGeneratorUtilities.RemoveLineTag; context.LinkerCommandLineOptions["LinkerCreateHotPatchableImage"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Linker.CreateHotPatchableImage.Enable, () => { context.Options["LinkerCreateHotPatchableImage"] = "Enabled"; context.LinkerCommandLineOptions["LinkerCreateHotPatchableImage"] = "/FUNCTIONPADMIN"; }), + Options.Option(Options.Vc.Linker.CreateHotPatchableImage.X86Image, () => { context.Options["LinkerCreateHotPatchableImage"] = "X86Image"; context.LinkerCommandLineOptions["LinkerCreateHotPatchableImage"] = "/FUNCTIONPADMIN:5"; }), + Options.Option(Options.Vc.Linker.CreateHotPatchableImage.X64Image, () => { context.Options["LinkerCreateHotPatchableImage"] = "X64Image"; context.LinkerCommandLineOptions["LinkerCreateHotPatchableImage"] = "/FUNCTIONPADMIN:6"; }), + Options.Option(Options.Vc.Linker.CreateHotPatchableImage.ItaniumImage, () => { context.Options["LinkerCreateHotPatchableImage"] = "ItaniumImage"; context.LinkerCommandLineOptions["LinkerCreateHotPatchableImage"] = "/FUNCTIONPADMIN:16"; }) + ); + + context.SelectOption + ( + Options.Option(Options.Vc.Linker.TreatLinkerWarningAsErrors.Disable, () => { context.Options["TreatLinkerWarningAsErrors"] = FileGeneratorUtilities.RemoveLineTag; context.LinkerCommandLineOptions["TreatLinkerWarningAsErrors"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Linker.TreatLinkerWarningAsErrors.Enable, () => { context.Options["TreatLinkerWarningAsErrors"] = "true"; context.LinkerCommandLineOptions["TreatLinkerWarningAsErrors"] = "/WX"; }) + ); + + // Target Machine + optionsContext.PlatformVcxproj.SetupPlatformTargetOptions(context); + optionsContext.PlatformVcxproj.SelectLinkerOptions(context); + + // Options.Vc.Librarian.AdditionalOptions + context.Configuration.AdditionalLibrarianOptions.Sort(); + string additionalLibrarianOptions = context.Configuration.AdditionalLibrarianOptions.JoinStrings(" ").Trim(); + + // Options.Vc.Linker.AdditionalOptions + context.Configuration.AdditionalLinkerOptions.Sort(); + string linkerAdditionalOptions = context.Configuration.AdditionalLinkerOptions.JoinStrings(" ").Trim(); + + Func formatIgnoredWarnings = disabledWarnings => + { + if (disabledWarnings.Count > 0) + return "/ignore:" + disabledWarnings.JoinStrings(","); + return string.Empty; + }; + + // Treat Options.Vc.Librarian/Linker.DisableSpecificWarnings here because + // they do not have a specific line in the vcxproj + string ignoredLibWarnings = formatIgnoredWarnings(Options.GetStrings(context.Configuration)); + if (!string.IsNullOrEmpty(ignoredLibWarnings)) + { + if (additionalLibrarianOptions.Length > 0) + additionalLibrarianOptions += " "; + additionalLibrarianOptions += ignoredLibWarnings; + } + + string ignoredLinkerWarnings = formatIgnoredWarnings(Options.GetStrings(context.Configuration)); + if (!string.IsNullOrEmpty(ignoredLinkerWarnings)) + { + if (linkerAdditionalOptions.Length > 0) + linkerAdditionalOptions += " "; + linkerAdditionalOptions += ignoredLinkerWarnings; + } + + context.Options["AdditionalLibrarianOptions"] = additionalLibrarianOptions.Length > 0 ? additionalLibrarianOptions : FileGeneratorUtilities.RemoveLineTag; + context.Options["AdditionalLinkerOptions"] = linkerAdditionalOptions.Length > 0 ? linkerAdditionalOptions : FileGeneratorUtilities.RemoveLineTag; + } + private void GenerateClangLinkerOptions(IGenerationContext context, ProjectOptionsGenerationContext optionsContext) + { + + } + private void GenerateGccLinkerOptions(IGenerationContext context, ProjectOptionsGenerationContext optionsContext) + { } + + private void GenerateManifestToolOptions(IGenerationContext context, ProjectOptionsGenerationContext optionsContext) + { + if (!context.DevelopmentEnvironment.IsVisualStudio()) // TODO: ideally this option generator should be split between VS / non-VS + return; + + Strings manifestInputs = new Strings(); + + string vsManifestFilesPath = Util.SimplifyPath(Path.Combine(context.DevelopmentEnvironment.GetVisualStudioVCRootPath(), "Include", "Manifest")); + + //EnableDpiAwareness + context.SelectOption + ( + Options.Option(Options.Vc.ManifestTool.EnableDpiAwareness.Default, () => { context.Options["EnableDpiAwareness"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.ManifestTool.EnableDpiAwareness.Yes, () => { context.Options["EnableDpiAwareness"] = "true"; manifestInputs.Add(Path.Combine(vsManifestFilesPath, "dpiaware.manifest")); }), + Options.Option(Options.Vc.ManifestTool.EnableDpiAwareness.PerMonitor, () => { context.Options["EnableDpiAwareness"] = "PerMonitorHighDPIAware"; manifestInputs.Add(Path.Combine(vsManifestFilesPath, "PerMonitorHighDPIAware.manifest")); }), + Options.Option(Options.Vc.ManifestTool.EnableDpiAwareness.No, () => { context.Options["EnableDpiAwareness"] = "false"; }) + ); + + if (context.Configuration.AdditionalManifestFiles.Count > 0) + { + context.Options["AdditionalManifestFiles"] = string.Join(";", Util.PathGetRelative(context.ProjectDirectory, context.Configuration.AdditionalManifestFiles)); + manifestInputs.AddRange(context.Configuration.AdditionalManifestFiles); + } + else + context.Options["AdditionalManifestFiles"] = FileGeneratorUtilities.RemoveLineTag; + + if (manifestInputs.Count > 0) + { + Options.Vc.Linker.EmbedManifest embedManifest = Options.GetObject(context.Configuration); + if (embedManifest == Options.Vc.Linker.EmbedManifest.No) + throw new NotImplementedException("Sharpmake does not support manifestinputs without embedding the manifest!"); + + var cmdManifests = manifestInputs.Select(p => FastBuild.Bff.CmdLineConvertIncludePathsFunc(context, optionsContext.Resolver, p, "/manifestinput:")); + + context.CommandLineOptions["ManifestInputs"] = string.Join($"'{Environment.NewLine} + ' ", cmdManifests); + } + else + { + context.CommandLineOptions["ManifestInputs"] = FileGeneratorUtilities.RemoveLineTag; + } + } + + private void GeneratePostBuildOptions(IGenerationContext context, ProjectOptionsGenerationContext optionsContext) + { + string eventSeparator = VisualStudio.Vcxproj.EventSeparator; + + if (context.Configuration.EventPreBuild.Count == 0) + { + context.Options["PreBuildEvent"] = FileGeneratorUtilities.RemoveLineTag; + context.Options["PreBuildEventDescription"] = FileGeneratorUtilities.RemoveLineTag; + context.Options["PreBuildEventEnable"] = FileGeneratorUtilities.RemoveLineTag; + } + else + { + context.Options["PreBuildEvent"] = (context.Configuration.EventPreBuild.JoinStrings(eventSeparator) + eventSeparator).Replace(@"""", @"""); + context.Options["PreBuildEventDescription"] = context.Configuration.EventPreBuildDescription != string.Empty ? context.Configuration.EventPreBuildDescription : FileGeneratorUtilities.RemoveLineTag; + context.Options["PreBuildEventEnable"] = context.Configuration.EventPreBuildExcludedFromBuild ? "false" : "true"; + } + + if (context.Configuration.EventPreLink.Count == 0) + { + context.Options["PreLinkEvent"] = FileGeneratorUtilities.RemoveLineTag; + context.Options["PreLinkEventDescription"] = FileGeneratorUtilities.RemoveLineTag; + context.Options["PreLinkEventEnable"] = FileGeneratorUtilities.RemoveLineTag; + } + else + { + context.Options["PreLinkEvent"] = (context.Configuration.EventPreLink.JoinStrings(eventSeparator) + eventSeparator).Replace(@"""", @"""); + context.Options["PreLinkEventDescription"] = context.Configuration.EventPreLinkDescription != string.Empty ? context.Configuration.EventPreLinkDescription : FileGeneratorUtilities.RemoveLineTag; + context.Options["PreLinkEventEnable"] = context.Configuration.EventPreLinkExcludedFromBuild ? "false" : "true"; + } + + if (context.Configuration.EventPrePostLink.Count == 0) + { + context.Options["PrePostLinkEvent"] = FileGeneratorUtilities.RemoveLineTag; + context.Options["PrePostLinkEventDescription"] = FileGeneratorUtilities.RemoveLineTag; + context.Options["PrePostLinkEventEnable"] = FileGeneratorUtilities.RemoveLineTag; + } + else + { + context.Options["PrePostLinkEvent"] = (context.Configuration.EventPrePostLink.JoinStrings(eventSeparator) + eventSeparator).Replace(@"""", @"""); + context.Options["PrePostLinkEventDescription"] = context.Configuration.EventPrePostLinkDescription != string.Empty ? context.Configuration.EventPrePostLinkDescription : FileGeneratorUtilities.RemoveLineTag; + context.Options["PrePostLinkEventEnable"] = context.Configuration.EventPrePostLinkExcludedFromBuild ? "false" : "true"; + } + + if (!context.Configuration.IsFastBuild) + { + if (context.Configuration.Output == Project.Configuration.OutputType.Exe || context.Configuration.ExecuteTargetCopy) + { + foreach (var customEvent in context.Configuration.ResolvedEventPreBuildExe) + { + if (customEvent is Project.Configuration.BuildStepExecutable) + { + var execEvent = (Project.Configuration.BuildStepExecutable)customEvent; + + string relativeExecutableFile = Util.PathGetRelative(context.ProjectDirectory, execEvent.ExecutableFile); + string eventString = string.Format( + "{0} {1}", + Util.SimplifyPath(relativeExecutableFile), + execEvent.ExecutableOtherArguments + ); + + context.Configuration.EventPreBuild.Add(eventString); + } + else if (customEvent is Project.Configuration.BuildStepCopy) + { + var copyEvent = (Project.Configuration.BuildStepCopy)customEvent; + context.Configuration.EventPreBuild.Add(copyEvent.GetCopyCommand(context.ProjectDirectory, optionsContext.Resolver)); + } + else + { + throw new Error("Unsupported type of build event found in Prebuild steps: " + customEvent.GetType().Name); + } + } + + foreach (var customEvent in context.Configuration.ResolvedEventPostBuildExe) + { + if (customEvent is Project.Configuration.BuildStepExecutable) + { + var execEvent = (Project.Configuration.BuildStepExecutable)customEvent; + + string relativeExecutableFile = Util.PathGetRelative(context.ProjectDirectory, execEvent.ExecutableFile); + string eventString = string.Format( + "{0} {1}", + Util.SimplifyPath(relativeExecutableFile), + execEvent.ExecutableOtherArguments + ); + + if (!context.Configuration.EventPostBuild.Contains(eventString)) + context.Configuration.EventPostBuild.Add(eventString); + } + else if (customEvent is Project.Configuration.BuildStepCopy) + { + var copyEvent = (Project.Configuration.BuildStepCopy)customEvent; + string eventString = copyEvent.GetCopyCommand(context.ProjectDirectory, optionsContext.Resolver); + + if (!context.Configuration.EventPostBuild.Contains(eventString)) + context.Configuration.EventPostBuild.Add(eventString); + } + else + { + throw new Error("Unsupported type of build event found in PostBuild steps: " + customEvent.GetType().Name); + } + } + } + + if (context.Configuration.Output == Project.Configuration.OutputType.Exe || context.Configuration.Output == Project.Configuration.OutputType.Dll) + { + if (context.Configuration.PostBuildStepTest != null) + { + // First, execute tests + context.Configuration.EventPostBuild.Insert(0, + string.Format( + "{0} {1}", + Util.SimplifyPath(Util.PathGetRelative(context.ProjectDirectory, context.Configuration.PostBuildStepTest.TestExecutable)), + context.Configuration.PostBuildStepTest.TestArguments + ) + ); + } + if (context.Configuration.PostBuildStampExe != null || context.Configuration.PostBuildStampExes.Any()) + { + // NO, first, execute stamp ! + var stampEnumerator = context.Configuration.PostBuildStampExes.Prepend(context.Configuration.PostBuildStampExe).Where(x => x != null); + List stampStrings = stampEnumerator.Select( + stampExe => string.Format( + "{0} {1} {2} {3}", + Util.SimplifyPath(Util.PathGetRelative(context.ProjectDirectory, stampExe.ExecutableFile)), + stampExe.ExecutableInputFileArgumentOption, + stampExe.ExecutableOutputFileArgumentOption, + stampExe.ExecutableOtherArguments + )).ToList(); + + context.Configuration.EventPostBuild.InsertRange(0, stampStrings); + } + } + } + + if (context.Configuration.EventPreBuild.Count == 0) + { + context.Options["PreBuildEvent"] = FileGeneratorUtilities.RemoveLineTag; + context.Options["PreBuildEventDescription"] = FileGeneratorUtilities.RemoveLineTag; + context.Options["PreBuildEventEnable"] = FileGeneratorUtilities.RemoveLineTag; + } + else + { + context.Options["PreBuildEvent"] = context.Configuration.EventPreBuild.JoinStrings(eventSeparator, escapeXml: true) + eventSeparator; + context.Options["PreBuildEventDescription"] = context.Configuration.EventPreBuildDescription != string.Empty ? context.Configuration.EventPreBuildDescription : FileGeneratorUtilities.RemoveLineTag; + context.Options["PreBuildEventEnable"] = context.Configuration.EventPreBuildExcludedFromBuild ? "false" : "true"; + } + + if (context.Configuration.EventPostBuild.Count == 0) + { + context.Options["PostBuildEvent"] = FileGeneratorUtilities.RemoveLineTag; + context.Options["PostBuildEventDescription"] = FileGeneratorUtilities.RemoveLineTag; + context.Options["PostBuildEventEnable"] = FileGeneratorUtilities.RemoveLineTag; + } + else + { + context.Options["PostBuildEvent"] = Util.JoinStrings(context.Configuration.EventPostBuild, eventSeparator, escapeXml: true) + eventSeparator; + context.Options["PostBuildEventDescription"] = context.Configuration.EventPostBuildDescription != string.Empty ? context.Configuration.EventPostBuildDescription : FileGeneratorUtilities.RemoveLineTag; + context.Options["PostBuildEventEnable"] = context.Configuration.EventPostBuildExcludedFromBuild ? "false" : "true"; + } + + if (context.Configuration.EventCustomBuild.Count == 0) + { + context.Options["CustomBuildEvent"] = FileGeneratorUtilities.RemoveLineTag; + context.Options["CustomBuildEventDescription"] = FileGeneratorUtilities.RemoveLineTag; + context.Options["CustomBuildEventOutputs"] = FileGeneratorUtilities.RemoveLineTag; + } + else + { + context.Options["CustomBuildEvent"] = (context.Configuration.EventCustomBuild.JoinStrings(eventSeparator, escapeXml: true) + eventSeparator); + context.Options["CustomBuildEventDescription"] = context.Configuration.EventCustomBuildDescription != string.Empty ? context.Configuration.EventCustomBuildDescription : FileGeneratorUtilities.RemoveLineTag; + context.Options["CustomBuildEventOutputs"] = context.Configuration.EventCustomBuildOutputs != string.Empty ? context.Configuration.EventCustomBuildOutputs : FileGeneratorUtilities.RemoveLineTag; + } + + if (context.Configuration.CustomBuildStep.Count == 0) + { + context.Options["CustomBuildStep"] = FileGeneratorUtilities.RemoveLineTag; + context.Options["CustomBuildStepDescription"] = FileGeneratorUtilities.RemoveLineTag; + context.Options["CustomBuildStepOutputs"] = FileGeneratorUtilities.RemoveLineTag; + context.Options["CustomBuildStepInputs"] = FileGeneratorUtilities.RemoveLineTag; + context.Options["CustomBuildStepBeforeTargets"] = FileGeneratorUtilities.RemoveLineTag; + context.Options["CustomBuildStepAfterTargets"] = FileGeneratorUtilities.RemoveLineTag; + context.Options["CustomBuildStepTreatOutputAsContent"] = FileGeneratorUtilities.RemoveLineTag; + } + else + { + context.Options["CustomBuildStep"] = (Util.JoinStrings(context.Configuration.CustomBuildStep, eventSeparator, escapeXml: true) + eventSeparator); + context.Options["CustomBuildStepDescription"] = context.Configuration.CustomBuildStepDescription != string.Empty ? context.Configuration.CustomBuildStepDescription : FileGeneratorUtilities.RemoveLineTag; + context.Options["CustomBuildStepOutputs"] = context.Configuration.CustomBuildStepOutputs.Count == 0 ? FileGeneratorUtilities.RemoveLineTag : (context.Configuration.CustomBuildStepOutputs.JoinStrings(";", escapeXml: true)); + context.Options["CustomBuildStepInputs"] = context.Configuration.CustomBuildStepInputs.Count == 0 ? FileGeneratorUtilities.RemoveLineTag : (context.Configuration.CustomBuildStepInputs.JoinStrings(";", escapeXml: true)); + context.Options["CustomBuildStepBeforeTargets"] = context.Configuration.CustomBuildStepBeforeTargets != string.Empty ? context.Configuration.CustomBuildStepBeforeTargets : FileGeneratorUtilities.RemoveLineTag; + context.Options["CustomBuildStepAfterTargets"] = context.Configuration.CustomBuildStepAfterTargets != string.Empty ? context.Configuration.CustomBuildStepAfterTargets : FileGeneratorUtilities.RemoveLineTag; + context.Options["CustomBuildStepTreatOutputAsContent"] = context.Configuration.CustomBuildStepTreatOutputAsContent != string.Empty ? context.Configuration.CustomBuildStepTreatOutputAsContent : FileGeneratorUtilities.RemoveLineTag; + } + } + + private void GenerateLLVMOptions(IGenerationContext context, ProjectOptionsGenerationContext optionsContext) + { + context.SelectOption + ( + Options.Option(Options.Vc.LLVM.UseClangCl.Enable, () => { context.Options["UseClangCl"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.LLVM.UseClangCl.Disable, () => { context.Options["UseClangCl"] = "false"; }) + ); + + context.SelectOption + ( + Options.Option(Options.Vc.LLVM.UseLldLink.Default, () => { context.Options["UseLldLink"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.LLVM.UseLldLink.Enable, () => { context.Options["UseLldLink"] = "true"; }), + Options.Option(Options.Vc.LLVM.UseLldLink.Disable, () => { context.Options["UseLldLink"] = "false"; }) + ); + } + + public static string MakeBuildStepName(Project.Configuration conf, Project.Configuration.BuildStepBase eventBuildStep, VisualStudio.Vcxproj.BuildStep buildStep, string projectRootPath, string projectPath) + { + if (!eventBuildStep.IsResolved) + throw new Error("Event hasn't been resolved!"); + + Func extractName = (name) => name.Substring(name.LastIndexOf(@"\", StringComparison.Ordinal) + 1).Replace('.', '_'); + + bool isPostBuildCustomActionWithSpecificName = buildStep == VisualStudio.Vcxproj.BuildStep.PostBuild || buildStep == VisualStudio.Vcxproj.BuildStep.PostBuildCustomAction || eventBuildStep.IsNameSpecific; + + if (eventBuildStep is Project.Configuration.BuildStepExecutable) + { + var cEvent = eventBuildStep as Project.Configuration.BuildStepExecutable; + string normalizedConfTargetPath = FastBuild.UtilityMethods.GetNormalizedPathForBuildStep(projectRootPath, projectPath, conf.TargetPath); + string execName; + + if (isPostBuildCustomActionWithSpecificName) + { + execName = @"Exec_" + + extractName(cEvent.ExecutableFile) + + "_" + + ( + normalizedConfTargetPath + + conf.TargetFileFullName + + cEvent.ExecutableInputFileArgumentOption + + cEvent.ExecutableOtherArguments + ). + GetDeterministicHashCode().ToString("X8"); + } + else + { + execName = @"Exec_" + extractName(cEvent.ExecutableFile); + execName += "_" + (execName).GetDeterministicHashCode().ToString("X8"); + } + + return execName; + } + else if (eventBuildStep is Project.Configuration.BuildStepCopy) + { + var cEvent = eventBuildStep as Project.Configuration.BuildStepCopy; + string sourcePath = FastBuild.UtilityMethods.GetNormalizedPathForBuildStep(projectRootPath, projectPath, cEvent.SourcePath); + string destinationPath = FastBuild.UtilityMethods.GetNormalizedPathForBuildStep(projectRootPath, projectPath, cEvent.DestinationPath); + string copyName; + + if (isPostBuildCustomActionWithSpecificName) + { + copyName = "Copy_" + (conf.TargetFileFullName + sourcePath + destinationPath).GetDeterministicHashCode().ToString("X8"); + } + else + { + copyName = "Copy_" + (sourcePath + destinationPath).GetDeterministicHashCode().ToString("X8"); + } + + return copyName; + } + else if (eventBuildStep is Project.Configuration.BuildStepTest) + { + var tEvent = eventBuildStep as Project.Configuration.BuildStepTest; + string normalizedConfTargetPath = FastBuild.UtilityMethods.GetNormalizedPathForBuildStep(projectRootPath, projectPath, conf.TargetPath); + string testName; + + if (isPostBuildCustomActionWithSpecificName) + { + testName = "Test_" + extractName(tEvent.TestExecutable) + "_" + (tEvent.TestArguments + normalizedConfTargetPath + conf.TargetFileFullName).GetDeterministicHashCode().ToString("X8"); + } + else + { + testName = "Test_" + extractName(tEvent.TestExecutable); + testName += "_" + (testName + tEvent.TestArguments).GetDeterministicHashCode().ToString("X8"); + } + + return testName; + } + else + { + throw new Error("error, BuildStep not supported: {0}", eventBuildStep.GetType().FullName); + } + } + + private static void SelectGenerateManifestOption(IGenerationContext context, ProjectOptionsGenerationContext optionsContext) + { + context.SelectOption + ( + Options.Option(Options.Vc.Linker.GenerateManifest.Enable, () => + { + context.Options["GenerateManifest"] = "true"; + + if (optionsContext.PlatformVcxproj.HasUserAccountControlSupport) + { + context.CommandLineOptions["GenerateManifest"] = string.Format(@"/MANIFEST /MANIFESTUAC:""level=^'{0}^' uiAccess=^'false^'""", context.Configuration.ApplicationPermissions); + + switch (context.Configuration.ApplicationPermissions) + { + case Project.Configuration.UACExecutionLevel.asInvoker: + context.Options["UACExecutionLevel"] = FileGeneratorUtilities.RemoveLineTag; + break; + case Project.Configuration.UACExecutionLevel.highestAvailable: + case Project.Configuration.UACExecutionLevel.requireAdministrator: + context.Options["UACExecutionLevel"] = context.Configuration.ApplicationPermissions.ToString(); + break; + } + } + else + { + context.CommandLineOptions["GenerateManifest"] = @"/MANIFEST /MANIFESTUAC:NO"; + context.Options["UACExecutionLevel"] = FileGeneratorUtilities.RemoveLineTag; + } + + if (context.Options["EmbedManifest"] == "false") + { + string manifestFile = optionsContext.IntermediateDirectoryRelative + Util.WindowsSeparator + context.Configuration.TargetFileFullName + context.Configuration.ManifestFileSuffix; + context.Options["ManifestFile"] = manifestFile; + context.CommandLineOptions["ManifestFile"] = @"/ManifestFile:""" + FormatCommandLineOptionPath(context, manifestFile) + @""""; + } + else + { + context.Options["ManifestFile"] = FileGeneratorUtilities.RemoveLineTag; + context.CommandLineOptions["ManifestFile"] = "/MANIFEST:EMBED"; + } + }), + Options.Option(Options.Vc.Linker.GenerateManifest.Disable, () => + { + context.Options["GenerateManifest"] = "false"; + context.Options["ManifestFile"] = FileGeneratorUtilities.RemoveLineTag; + context.CommandLineOptions["GenerateManifest"] = FileGeneratorUtilities.RemoveLineTag; + context.CommandLineOptions["ManifestFile"] = FileGeneratorUtilities.RemoveLineTag; + context.Options["UACExecutionLevel"] = FileGeneratorUtilities.RemoveLineTag; + }) + ); + } + + private static void SelectGenerateDebugInformationOption(IGenerationContext context, ProjectOptionsGenerationContext optionsContext) + { + //GenerateDebugInformation="false" + // VS2015 + // GenerateDebugInformation.Enable GenerateDebugInformation="true" /DEBUG + // GenerateDebugInformation.EnableFastLink GenerateDebugInformation="DebugFastLink" /DEBUG:FASTLINK + // Disable GenerateDebugInformation="No" + // + // VS2017-VS2022 + // Enable GenerateDebugInformation="true" /DEBUG + // EnableFastLink GenerateDebugInformation="DebugFastLink" /DEBUG:FASTLINK + // Disable GenerateDebugInformation="No" + + Action enableDebugInformation = (isFastLink) => + { + bool forceFullPDB = false; + context.SelectOption + ( + Options.Option(Options.Vc.Linker.GenerateFullProgramDatabaseFile.Enable, () => { context.Options["FullProgramDatabaseFile"] = "true"; forceFullPDB = true; }), + Options.Option(Options.Vc.Linker.GenerateFullProgramDatabaseFile.Disable, () => { context.Options["FullProgramDatabaseFile"] = "false"; }), + Options.Option(Options.Vc.Linker.GenerateFullProgramDatabaseFile.Default, () => { context.Options["FullProgramDatabaseFile"] = FileGeneratorUtilities.RemoveLineTag; }) + ); + + if (isFastLink && forceFullPDB) + throw new Error("Cannot set both EnableFastLink and GenerateFullProgramDatabaseFile.Enable in conf " + context.Configuration); + + bool isMicrosoftPlatform = context.Configuration.Platform.IsMicrosoft(); + if (isFastLink) + { + if (!isMicrosoftPlatform) + throw new Error("Cannot set EnableFastLink on non-microsoft platform " + context.Configuration.Platform); + + context.Options["LinkerGenerateDebugInformation"] = "DebugFastLink"; + context.LinkerCommandLineOptions["LinkerGenerateDebugInformation"] = "/DEBUG:FASTLINK"; + } + else + { + if (isMicrosoftPlatform && forceFullPDB && + (context.DevelopmentEnvironment.IsVisualStudio() && context.DevelopmentEnvironment >= DevEnv.vs2017)) + { + context.Options["LinkerGenerateDebugInformation"] = "DebugFull"; + context.LinkerCommandLineOptions["LinkerGenerateDebugInformation"] = "/DEBUG:FULL"; + } + else + { + context.Options["LinkerGenerateDebugInformation"] = "true"; + context.LinkerCommandLineOptions["LinkerGenerateDebugInformation"] = "/DEBUG"; + } + } + + string optionsCompilerProgramDatabaseFile = context.Configuration.CompilerPdbFilePath; + string optionsLinkerProgramDatabaseFile = context.Configuration.LinkerPdbFilePath; + string cmdLineOptionsCompilerProgramDatabaseFile = context.Configuration.CompilerPdbFilePath; + string cmdLineOptionsLinkerProgramDatabaseFile = context.Configuration.LinkerPdbFilePath; + + if (context.Configuration.UseRelativePdbPath) + { + optionsCompilerProgramDatabaseFile = Util.PathGetRelative(context.ProjectDirectory, optionsCompilerProgramDatabaseFile, true); + optionsLinkerProgramDatabaseFile = Util.PathGetRelative(context.ProjectDirectory, optionsLinkerProgramDatabaseFile, true); + cmdLineOptionsCompilerProgramDatabaseFile = FormatCommandLineOptionPath(context, optionsCompilerProgramDatabaseFile); + cmdLineOptionsLinkerProgramDatabaseFile = FormatCommandLineOptionPath(context, optionsLinkerProgramDatabaseFile); + } + + context.Options["CompilerProgramDatabaseFile"] = string.IsNullOrEmpty(optionsCompilerProgramDatabaseFile) + ? FileGeneratorUtilities.RemoveLineTag + : optionsCompilerProgramDatabaseFile; + context.Options["LinkerProgramDatabaseFile"] = string.IsNullOrEmpty(optionsLinkerProgramDatabaseFile) + ? FileGeneratorUtilities.RemoveLineTag + : optionsLinkerProgramDatabaseFile; + + // %2 is converted by FastBuild + // Output name of object being compiled, as specified by CompilerOutputPath and the name of discovered objects depending on the Compiler input options (extension is also replace with CompilerOutputExtension). + if (FastBuildSettings.EnableFastLinkPDBSupport && isFastLink) + context.CommandLineOptions["CompilerProgramDatabaseFile"] = @"/Fd""%2.pdb"""; + else if (!string.IsNullOrEmpty(cmdLineOptionsCompilerProgramDatabaseFile)) + context.CommandLineOptions["CompilerProgramDatabaseFile"] = $@"/Fd""{cmdLineOptionsCompilerProgramDatabaseFile}"""; + else + context.CommandLineOptions["CompilerProgramDatabaseFile"] = FileGeneratorUtilities.RemoveLineTag; + + if (!string.IsNullOrEmpty(cmdLineOptionsLinkerProgramDatabaseFile)) + context.LinkerCommandLineOptions["LinkerProgramDatabaseFile"] = $@"/PDB:""{cmdLineOptionsLinkerProgramDatabaseFile}"""; + else + context.LinkerCommandLineOptions["LinkerProgramDatabaseFile"] = FileGeneratorUtilities.RemoveLineTag; + }; + + context.SelectOption + ( + Options.Option(Options.Vc.Linker.GenerateDebugInformation.Enable, () => { enableDebugInformation(false); }), + Options.Option(Options.Vc.Linker.GenerateDebugInformation.EnableFastLink, () => + { + if (optionsContext.HasClrSupport) + context.Builder.LogWarningLine("GenerateDebugInformation.EnableFastLink is not supported with CLR/dot net (project: " + context.Project.Name + "), fallback to GenerateDebugInformation.Enable"); + enableDebugInformation(!optionsContext.HasClrSupport); + }), + Options.Option(Options.Vc.Linker.GenerateDebugInformation.Disable, () => + { + context.Options["LinkerGenerateDebugInformation"] = "false"; + context.Options["CompilerProgramDatabaseFile"] = FileGeneratorUtilities.RemoveLineTag; + context.Options["LinkerProgramDatabaseFile"] = FileGeneratorUtilities.RemoveLineTag; + context.Options["FullProgramDatabaseFile"] = FileGeneratorUtilities.RemoveLineTag; + + context.CommandLineOptions["LinkerGenerateDebugInformation"] = FileGeneratorUtilities.RemoveLineTag; + context.CommandLineOptions["CompilerProgramDatabaseFile"] = FileGeneratorUtilities.RemoveLineTag; + context.CommandLineOptions["LinkerProgramDatabaseFile"] = FileGeneratorUtilities.RemoveLineTag; + }) + ); + } + + private static void SelectGenerateMapFileOption(IGenerationContext context, ProjectOptionsGenerationContext optionsContext) + { + Action enableMapOption = () => + { + context.Options["GenerateMapFile"] = "true"; + string mapFile = Path.Combine(optionsContext.OutputDirectoryRelative, context.Configuration.TargetFileFullName + ".map"); + context.Options["MapFileName"] = mapFile; + + string mapFileBffRelative = FormatCommandLineOptionPath(context, mapFile); + if (context.Configuration.Target.GetFragment() == Compiler.Clang) + { + context.LinkerCommandLineOptions["GenerateMapFile"] = $@"{context.Configuration.Platform.GetLinkerOptionPrefix(context.Configuration.Target.GetFragment())}-Map=""" + mapFileBffRelative + @""""; + } + else + { + context.LinkerCommandLineOptions["GenerateMapFile"] = @"/MAP"":" + mapFileBffRelative + @""""; + } + }; + + context.SelectOption + ( + Options.Option(Options.Vc.Linker.GenerateMapFile.Disable, () => + { + context.Options["GenerateMapFile"] = "false"; + context.Options["MapFileName"] = ""; + context.CommandLineOptions["GenerateMapFile"] = FileGeneratorUtilities.RemoveLineTag; + }), + Options.Option(Options.Vc.Linker.GenerateMapFile.Normal, enableMapOption), + Options.Option(Options.Vc.Linker.GenerateMapFile.Full, enableMapOption) + ); + } + + private static string FormatCommandLineOptionPath(IGenerationContext context, string path) + { + return !context.PlainOutput ? FastBuild.Bff.CurrentBffPathKeyCombine(path) : path; + } + } +} diff --git a/Sharpmake.Generators/Generic/JsonCompilationDatabase.cs b/Sharpmake.Generators/Generic/JsonCompilationDatabase.cs index cc8ccf989..9d503a744 100644 --- a/Sharpmake.Generators/Generic/JsonCompilationDatabase.cs +++ b/Sharpmake.Generators/Generic/JsonCompilationDatabase.cs @@ -433,6 +433,8 @@ internal class CompileCommandGenerationContext : IGenerationContext public IDictionary CommandLineOptions { get; set; } + public IDictionary LinkerCommandLineOptions { get; set; } = new ProjectOptionsGenerator.VcxprojCmdLineOptions(); + public DevEnv DevelopmentEnvironment { get { return Configuration.Compiler; } } public string ProjectDirectoryCapitalized { get; private set; } diff --git a/Sharpmake.Generators/Generic/NinjaProject.Template.cs b/Sharpmake.Generators/Generic/NinjaProject.Template.cs new file mode 100644 index 000000000..3b494b534 --- /dev/null +++ b/Sharpmake.Generators/Generic/NinjaProject.Template.cs @@ -0,0 +1,151 @@ +namespace Sharpmake.Generators.Generic +{ + public partial class NinjaProject + { + private static class Template + { + // Ninja syntax + public static string RuleBegin = "rule "; + public static string BuildBegin = "build "; + public static string CommandBegin = " command = "; + public static string DescriptionBegin = " description = "; + public static string Input = "$in"; + public static string Output = "$out"; + + public static string PerConfigFormat(GenerationContext context) + { + return $"{context.Project.Name}_{context.Configuration.Name}_{context.Compiler}".ToLower(); + } + public static string PerConfigFolderFormat(GenerationContext context) + { + return System.IO.Path.Combine(context.Compiler.ToString(), context.Configuration.Name); + } + + public static string CleanBuildStatement(GenerationContext context) + { + return $"clean_{PerConfigFormat(context)}"; + } + public static string CompDBBuildStatement(GenerationContext context) + { + return $"compdb_{PerConfigFormat(context)}"; + } + + public static class RuleStatement + { + private static readonly string RulePrefix = "rule_"; + + public static string CompileCppFile(GenerationContext context) + { + return $"{RulePrefix}compile_cpp_file_{PerConfigFormat(context)}"; + } + + public static string LinkExe(GenerationContext context) + { + return $"{RulePrefix}link_exe_{PerConfigFormat(context)}"; + } + + public static string LinkLib(GenerationContext context) + { + return $"{RulePrefix}link_static_lib_{PerConfigFormat(context)}"; + } + + public static string LinkDll(GenerationContext context) + { + return $"{RulePrefix}link_dynamic_lib_{PerConfigFormat(context)}"; + } + + public static string LinkToUse(GenerationContext context) + { + switch (context.Configuration.Output) + { + case Project.Configuration.OutputType.Exe: + return LinkExe(context); + case Project.Configuration.OutputType.Lib: + return LinkLib(context); + case Project.Configuration.OutputType.Dll: + return LinkDll(context); + default: + throw new Error("Invalid output type for rule"); + } + } + + public static string Clean(GenerationContext context) + { + return $"{RulePrefix}clean_{PerConfigFormat(context)}"; + } + public static string CompilerDB(GenerationContext context) + { + return $"{RulePrefix}compdb_{PerConfigFormat(context)}"; + } + } + + public static class BuildStatement + { + public static string Defines(GenerationContext context) + { + return $"{PerConfigFormat(context)}_DEFINES"; + } + public static string Includes(GenerationContext context) + { + return $"{PerConfigFormat(context)}_INCLUDES"; + } + public static string SystemIncludes(GenerationContext context) + { + return $"{PerConfigFormat(context)}_SYSTEM_INCLUDES"; + } + public static string DepFile(GenerationContext context) + { + return $"{PerConfigFormat(context)}_DEP_FILE"; + } + public static string CompilerImplicitFlags(GenerationContext context) + { + return $"{PerConfigFormat(context)}_COMPILER_IMPLICIT_FLAGS"; + } + public static string CompilerFlags(GenerationContext context) + { + return $"{PerConfigFormat(context)}_COMPILER_FLAGS"; + } + public static string LinkerImplicitFlags(GenerationContext context) + { + return $"{PerConfigFormat(context)}_LINKER_IMPLICIT_FLAGS"; + } + public static string LinkerFlags(GenerationContext context) + { + return $"{PerConfigFormat(context)}_LINKER_FLAGS"; + } + public static string TargetPdb(GenerationContext context) + { + return $"{PerConfigFormat(context)}_TARGET_PDB"; + } + public static string ImplicitLinkerPaths(GenerationContext context) + { + return $"{PerConfigFormat(context)}_LINKER_IMPLICIT_PATHS"; + } + public static string ImplicitLinkerLibraries(GenerationContext context) + { + return $"{PerConfigFormat(context)}_LINKER_IMPLICIT_LIBRARIES"; + } + public static string LinkerPaths(GenerationContext context) + { + return $"{PerConfigFormat(context)}_LINKER_PATHS"; + } + public static string LinkerLibraries(GenerationContext context) + { + return $"{PerConfigFormat(context)}_LINKER_LIBRARIES"; + } + public static string PreBuild(GenerationContext context) + { + return $"{PerConfigFormat(context)}_PRE_BUILD"; + } + public static string PostBuild(GenerationContext context) + { + return $"{PerConfigFormat(context)}_POST_BUILD"; + } + public static string TargetFile(GenerationContext context) + { + return $"{PerConfigFormat(context)}_TARGET_FILE"; + } + } + } + } +} diff --git a/Sharpmake.Generators/Generic/NinjaProject.cs b/Sharpmake.Generators/Generic/NinjaProject.cs new file mode 100644 index 000000000..edf7b04a0 --- /dev/null +++ b/Sharpmake.Generators/Generic/NinjaProject.cs @@ -0,0 +1,1077 @@ +using System; +using System.IO; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Diagnostics; + +namespace Sharpmake.Generators.Generic +{ + public partial class NinjaProject : IProjectGenerator + { + private class GenerationContext : IGenerationContext + { + private Dictionary _projectConfigurationOptions; + private IDictionary _cmdLineOptions; + private IDictionary _linkerCmdLineOptions; + private Resolver _envVarResolver; + + public Builder Builder { get; } + public string ProjectPath { get; } + public string ProjectDirectory { get; } + public string ProjectFileName { get; } + public string ProjectDirectoryCapitalized { get; } + public string ProjectSourceCapitalized { get; } + public bool PlainOutput { get { return true; } } + public Project Project { get; } + + public Compiler Compiler { get; } + + public Project.Configuration Configuration { get; set; } + + public IReadOnlyDictionary ProjectConfigurationOptions => _projectConfigurationOptions; + + public void SetProjectConfigurationOptions(Dictionary projectConfigurationOptions) + { + _projectConfigurationOptions = projectConfigurationOptions; + } + + public DevEnv DevelopmentEnvironment => Configuration.Target.GetFragment(); + public DevEnvRange DevelopmentEnvironmentsRange { get; } + public Options.ExplicitOptions Options + { + get + { + Debug.Assert(_projectConfigurationOptions.ContainsKey(Configuration)); + return _projectConfigurationOptions[Configuration]; + } + } + public IDictionary CommandLineOptions + { + get + { + Debug.Assert(_cmdLineOptions != null); + return _cmdLineOptions; + } + set + { + _cmdLineOptions = value; + } + } + public IDictionary LinkerCommandLineOptions + { + get + { + Debug.Assert(_linkerCmdLineOptions != null); + return _linkerCmdLineOptions; + } + set + { + _linkerCmdLineOptions = value; + } + } + public Resolver EnvironmentVariableResolver + { + get + { + Debug.Assert(_envVarResolver != null); + return _envVarResolver; + } + set + { + _envVarResolver = value; + } + } + + public FastBuildMakeCommandGenerator FastBuildMakeCommandGenerator { get; } + + public GenerationContext(Builder builder, string projectPath, Project project, Project.Configuration configuration) + { + Builder = builder; + + FileInfo fileInfo = new FileInfo(projectPath); + ProjectPath = fileInfo.FullName; + ProjectDirectory = Path.GetDirectoryName(ProjectPath); + ProjectFileName = Path.GetFileName(ProjectPath); + Project = project; + + ProjectDirectoryCapitalized = Util.GetCapitalizedPath(ProjectDirectory); + ProjectSourceCapitalized = Util.GetCapitalizedPath(Project.SourceRootPath); + + Configuration = configuration; + Compiler = configuration.Target.GetFragment(); + } + + public void Reset() + { + CommandLineOptions = null; + Configuration = null; + EnvironmentVariableResolver = null; + } + + public void SelectOption(params Options.OptionAction[] options) + { + Sharpmake.Options.SelectOption(Configuration, options); + } + + public void SelectOptionWithFallback(Action fallbackAction, params Options.OptionAction[] options) + { + Sharpmake.Options.SelectOptionWithFallback(Configuration, fallbackAction, options); + } + } + + private class CompileStatement + { + private string Name; + private string Input; + private GenerationContext Context; + + public Strings Defines { get; set; } + public string DepPath { get; set; } + public Strings ImplicitCompilerFlags { get; set; } + public Strings CompilerFlags { get; set; } + public OrderableStrings Includes { get; set; } + public OrderableStrings SystemIncludes { get; set; } + public string TargetFilePath { get; set; } + + public CompileStatement(string name, string input, GenerationContext context) + { + Name = name; + Input = input; + Context = context; + } + + public override string ToString() + { + var fileGenerator = new FileGenerator(); + + string defines = MergeMultipleFlagsToString(Defines, CompilerFlagLookupTable.Get(Context.Compiler, CompilerFlag.Define)); + string implicitCompilerFlags = MergeMultipleFlagsToString(ImplicitCompilerFlags); + string compilerFlags = MergeMultipleFlagsToString(CompilerFlags); + string includes = MergeMultipleFlagsToString(Includes, CompilerFlagLookupTable.Get(Context.Compiler, CompilerFlag.Include)); + string systemIncludes = MergeMultipleFlagsToString(SystemIncludes, CompilerFlagLookupTable.Get(Context.Compiler, CompilerFlag.SystemInclude)); + + fileGenerator.WriteLine($"{Template.BuildBegin}{Name}: {Template.RuleStatement.CompileCppFile(Context)} {Input}"); + + WriteIfNotEmpty(fileGenerator, $" {Template.BuildStatement.Defines(Context)}", defines); + WriteIfNotEmpty(fileGenerator, $" {Template.BuildStatement.DepFile(Context)}", $"{DepPath}.d"); + WriteIfNotEmpty(fileGenerator, $" {Template.BuildStatement.CompilerImplicitFlags(Context)}", implicitCompilerFlags); + WriteIfNotEmpty(fileGenerator, $" {Template.BuildStatement.SystemIncludes(Context)}", systemIncludes); + WriteIfNotEmpty(fileGenerator, $" {Template.BuildStatement.CompilerFlags(Context)}", compilerFlags); + WriteIfNotEmpty(fileGenerator, $" {Template.BuildStatement.Includes(Context)}", includes); + WriteIfNotEmpty(fileGenerator, $" {Template.BuildStatement.TargetPdb(Context)}", TargetFilePath); + + return fileGenerator.ToString(); + } + } + + private class LinkStatement + { + public Strings ObjFilePaths { get; set; } + public Strings ImplicitLinkerFlags { get; set; } + public Strings Flags { get; set; } + public Strings ImplicitLinkerPaths { get; set; } + public Strings ImplicitLinkerLibs { get; set; } + public Strings LinkerPaths { get; set; } + public Strings LinkerLibs { get; set; } + public string PreBuild { get; set; } + public string PostBuild { get; set; } + public string TargetPdb { get; set; } + + private GenerationContext Context; + private string OutputPath; + + public LinkStatement(GenerationContext context, string outputPath) + { + Context = context; + OutputPath = outputPath; + + PreBuild = "cd ."; + PostBuild = "cd ."; + } + + public override string ToString() + { + var fileGenerator = new FileGenerator(); + + string objPaths = MergeMultipleFlagsToString(ObjFilePaths); + string implicitLinkerFlags = MergeMultipleFlagsToString(ImplicitLinkerFlags); + string implicitLinkerPaths = MergeMultipleFlagsToString(ImplicitLinkerPaths, LinkerFlagLookupTable.Get(Context.Compiler, LinkerFlag.IncludePath)); + string implicitLinkerLibs = MergeMultipleFlagsToString(ImplicitLinkerLibs, LinkerFlagLookupTable.Get(Context.Compiler, LinkerFlag.IncludeFile)); + string linkerFlags = MergeMultipleFlagsToString(Flags); + string libraryPaths = MergeMultipleFlagsToString(LinkerPaths, LinkerFlagLookupTable.Get(Context.Compiler, LinkerFlag.IncludePath)); + string libraryFiles = MergeMultipleFlagsToString(LinkerLibs, LinkerFlagLookupTable.Get(Context.Compiler, LinkerFlag.IncludeFile)); + + fileGenerator.WriteLine($"{Template.BuildBegin}{CreateNinjaFilePath(FullOutputPath(Context))}: {Template.RuleStatement.LinkToUse(Context)} {objPaths}"); + + WriteIfNotEmpty(fileGenerator, $" {Template.BuildStatement.LinkerImplicitFlags(Context)}", implicitLinkerFlags); + WriteIfNotEmpty(fileGenerator, $" {Template.BuildStatement.ImplicitLinkerPaths(Context)}", implicitLinkerPaths); + WriteIfNotEmpty(fileGenerator, $" {Template.BuildStatement.ImplicitLinkerLibraries(Context)}", implicitLinkerLibs); + WriteIfNotEmpty(fileGenerator, $" {Template.BuildStatement.LinkerFlags(Context)}", linkerFlags); + WriteIfNotEmpty(fileGenerator, $" {Template.BuildStatement.LinkerPaths(Context)}", libraryPaths); + WriteIfNotEmpty(fileGenerator, $" {Template.BuildStatement.LinkerLibraries(Context)}", libraryFiles); + WriteIfNotEmpty(fileGenerator, $" {Template.BuildStatement.TargetFile(Context)}", OutputPath); + WriteIfNotEmpty(fileGenerator, $" {Template.BuildStatement.TargetPdb(Context)}", TargetPdb); + WriteIfNotEmptyOr(fileGenerator, $" {Template.BuildStatement.PreBuild(Context)}", PreBuild, "cd ."); + WriteIfNotEmptyOr(fileGenerator, $" {Template.BuildStatement.PostBuild(Context)}", PostBuild, "cd ."); + ; + + return fileGenerator.ToString(); + } + } + + private static readonly string ProjectExtension = ".ninja"; + + private static string MergeMultipleFlagsToString(Strings options, string perOptionPrefix = "") + { + string result = ""; + foreach (var option in options) + { + if (option == "REMOVE_LINE_TAG") + { + continue; + } + + result += $"{perOptionPrefix}{option} "; + } + return result; + } + private static string MergeMultipleFlagsToString(OrderableStrings options, string perOptionPrefix = "") + { + string result = ""; + foreach (var option in options) + { + if (option == "REMOVE_LINE_TAG") + { + continue; + } + + result += $"{perOptionPrefix}\"{option}\" "; + } + return result; + } + public void Generate( + Builder builder, + Project project, + List configurations, + string projectFilePath, + List generatedFiles, + List skipFiles) + { + // The first pass writes ninja files per configuration + Strings filesToCompile = GetFilesToCompile(project); + + foreach (var config in configurations) + { + GenerationContext context = new GenerationContext(builder, projectFilePath, project, config); + + if (config.Output == Project.Configuration.OutputType.Dll && context.Compiler == Compiler.GCC) + { + throw new Error("Shared library for GCC is currently not supported"); + } + + WritePerConfigFile(context, filesToCompile, generatedFiles, skipFiles); + WriteCompilerDatabaseFile(context); + } + + // the second pass uses these files to create a project file where the files can be build + WriteProjectFile(builder, projectFilePath, project, configurations, generatedFiles, skipFiles); + } + + public void Generate( + Builder builder, + Solution solution, + List configurations, + string solutionFile, + List generatedFiles, + List skipFiles) + { + FileGenerator fileGenerator = new FileGenerator(); + + GenerateHeader(fileGenerator); + + fileGenerator.WriteLine($"# Solution for {solution.Name}"); + + List projectsToInclude = new List(); + foreach (var config in configurations) + { + foreach (var projectInfo in config.IncludedProjectInfos) + { + if (projectsToInclude.FindIndex(x => x == projectInfo.Project) == -1) + { + projectsToInclude.Add(projectInfo.Project); + } + } + } + + foreach (var project in projectsToInclude) + { + string fullProjectPath = FullProjectPath(project); + fileGenerator.WriteLine($"include {CreateNinjaFilePath(fullProjectPath)}"); + } + + fileGenerator.RemoveTaggedLines(); + MemoryStream memoryStream = fileGenerator.ToMemoryStream(); + FileInfo solutionFileInfo = new FileInfo($"{solutionFile}{Util.GetSolutionExtension(DevEnv.ninja)}"); + + if (builder.Context.WriteGeneratedFile(solution.GetType(), solutionFileInfo, memoryStream)) + { + generatedFiles.Add(solutionFileInfo.FullName); + } + else + { + skipFiles.Add(solutionFileInfo.FullName); + } + } + + private void WriteProjectFile(Builder builder, string projectFilePath, Project project, List configurations, List generatedFiles, List skipFiles) + { + List filePaths = new List(); + List dependencyFilePaths = new List(); + + foreach (var config in configurations) + { + GenerationContext context = new GenerationContext(builder, projectFilePath, project, config); + + foreach (var dependency in config.ResolvedDependencies) + { + string dependencyFilePath = FullProjectPath(dependency.Project); + + if (!dependencyFilePaths.Contains(dependencyFilePath)) + { + dependencyFilePaths.Add(dependencyFilePath); + } + } + + filePaths.Add(GetPerConfigFilePath(context.Configuration, context.Compiler)); + } + + var fileGenerator = new FileGenerator(); + + GenerateHeader(fileGenerator); + + foreach (var path in filePaths) + { + fileGenerator.WriteLine($"include {CreateNinjaFilePath(path)}"); + } + fileGenerator.WriteLine($""); + + string fullProjectPath = FullProjectPath(project); + + if (SaveFileGeneratorToDisk(fileGenerator, builder, project, $"{fullProjectPath}")) + { + generatedFiles.Add(fullProjectPath); + } + else + { + skipFiles.Add(fullProjectPath); + } + } + + private string FullProjectPath(Project project) + { + foreach (var config in project.Configurations) + { + if (config.Target.GetFragment() == DevEnv.ninja) + { + string projectPath = Path.Combine(config.ProjectPath, project.Name); + return $"{projectPath}{ProjectExtension}"; + } + } + + throw new Error("Failed to find project path"); + } + + private void WritePerConfigFile(GenerationContext context, Strings filesToCompile, List generatedFiles, List skipFiles) + { + Strings objFilePaths = GetObjPaths(context); + + ResolvePdbPaths(context); + GenerateConfOptions(context); + + List compileStatements = GenerateCompileStatements(context, filesToCompile, objFilePaths); + List linkStatements = GenerateLinking(context, objFilePaths); + + var fileGenerator = new FileGenerator(); + + GenerateHeader(fileGenerator); + + fileGenerator.WriteLine("# Dependencies"); + foreach (var dependency in context.Configuration.ResolvedDependencies) + { + var compiler = dependency.Target.GetFragment(); + var path = GetPerConfigFilePath(dependency, compiler); + fileGenerator.WriteLine($"include {CreateNinjaFilePath(path)}"); + } + fileGenerator.WriteLine(""); + + GenerateRules(fileGenerator, context); + + fileGenerator.RemoveTaggedLines(); + + foreach (var compileStatement in compileStatements) + { + fileGenerator.WriteLine(compileStatement.ToString()); + } + + foreach (var linkStatement in linkStatements) + { + fileGenerator.WriteLine(linkStatement.ToString()); + } + + GenerateProjectBuilds(fileGenerator, context); + + string filePath = GetPerConfigFilePath(context.Configuration, context.Compiler); + + if (SaveFileGeneratorToDisk(fileGenerator, context, filePath)) + { + generatedFiles.Add(filePath); + } + else + { + skipFiles.Add(filePath); + } + } + + private void WriteCompilerDatabaseFile(GenerationContext context) + { + string outputFolder = Directory.GetParent(GetCompilerDBPath(context)).FullName; + string outputPath = GetCompilerDBPath(context); + if (!Directory.Exists(outputFolder)) + { + Directory.CreateDirectory(outputFolder); + } + else if (File.Exists(outputPath)) + { + File.Delete(outputPath); + } + + string ninjaFilePath = KitsRootPaths.GetNinjaPath(); + string command = $"-f {GetPerConfigFilePath(context.Configuration, context.Compiler)} {Template.CompDBBuildStatement(context)} --quiet >> {outputPath}"; + + Process process = new Process(); + ProcessStartInfo startInfo = new ProcessStartInfo(); + startInfo.WindowStyle = ProcessWindowStyle.Hidden; + startInfo.FileName = "cmd.exe"; + startInfo.Arguments = $"/C {ninjaFilePath} {command}"; + process.StartInfo = startInfo; + process.Start(); + } + + private string GetPerConfigFileName(Project.Configuration config, Compiler compiler) + { + return $"{config.Project.Name}.{config.Name}.{compiler}{ProjectExtension}"; + } + + private string GetCompilerDBPath(GenerationContext context) + { + return $"{Path.Combine(context.Configuration.ProjectPath, "clang_tools", $"{Template.PerConfigFolderFormat(context)}", "compile_commands.json")}"; + } + + private string GetPerConfigFilePath(Project.Configuration config, Compiler compiler) + { + return Path.Combine(config.ProjectPath, "ninja", GetPerConfigFileName(config, compiler)); + } + + private static void WriteIfNotEmpty(FileGenerator fileGenerator, string key, string value) + { + if (!string.IsNullOrEmpty(value)) + { + fileGenerator.WriteLine($"{key} = {value}"); + } + } + private static void WriteIfNotEmptyOr(FileGenerator fileGenerator, string key, string value, string orValue) + { + if (!string.IsNullOrEmpty(value)) + { + fileGenerator.WriteLine($"{key} = {value}"); + } + else + { + fileGenerator.WriteLine($"{key} = {orValue}"); + } + } + + private static string FullOutputPath(GenerationContext context) + { + string fullFileName = $"{context.Configuration.TargetFileFullName}_{context.Configuration.Name}_{context.Compiler}{context.Configuration.TargetFileFullExtension}"; + return CreateNinjaFilePath($"{Path.Combine(context.Configuration.TargetPath, fullFileName)}"); + } + + private void ResolvePdbPaths(GenerationContext context) + { + // Relative pdb filepaths is not supported for ninja generation + if (context.Configuration.UseRelativePdbPath == true) + { + Util.LogWrite("Warning: Configuration.UseRelativePdbPath is not supported for ninja generation"); + context.Configuration.UseRelativePdbPath = false; + } + + // Resolve pdb filepath so it's sorted per compiler + context.Configuration.CompilerPdbSuffix = $"{context.Compiler}{context.Configuration.CompilerPdbSuffix}"; + context.Configuration.LinkerPdbSuffix = $"{context.Compiler}{context.Configuration.LinkerPdbSuffix}"; + + // Not all compilers generate the directories to pdb files + CreatePdbPath(context); + } + + private bool SaveFileGeneratorToDisk(FileGenerator fileGenerator, GenerationContext context, string filePath) + { + return SaveFileGeneratorToDisk(fileGenerator, context.Builder, context.Project, filePath); + } + + private bool SaveFileGeneratorToDisk(FileGenerator fileGenerator, Builder builder, Project project, string filePath) + { + MemoryStream memoryStream = fileGenerator.ToMemoryStream(); + FileInfo projectFileInfo = new FileInfo(filePath); + return builder.Context.WriteGeneratedFile(project.GetType(), projectFileInfo, memoryStream); + } + + private Strings GetFilesToCompile(Project project) + { + Strings filesToCompile = new Strings(); + + foreach (var sourceFile in project.SourceFiles) + { + string extension = Path.GetExtension(sourceFile); + if (project.SourceFilesCompileExtensions.Contains(extension)) + { + filesToCompile.Add(sourceFile); + } + } + + return filesToCompile; + } + Strings GetObjPaths(GenerationContext context) + { + Strings objFilePaths = new Strings(); + + foreach (var sourceFile in context.Project.SourceFiles) + { + string extension = Path.GetExtension(sourceFile); + if (context.Project.SourceFilesCompileExtensions.Contains(extension)) + { + string fileStem = Path.GetFileNameWithoutExtension(sourceFile); + + string outputExtension = context.Configuration.Target.GetFragment() == Compiler.MSVC ? ".obj" : ".o"; + + string objPath = $"{Path.Combine(context.Configuration.IntermediatePath, fileStem)}{outputExtension}"; + objFilePaths.Add(CreateNinjaFilePath(objPath)); + } + } + + return objFilePaths; + } + + private void CreatePdbPath(GenerationContext context) + { + if (!Directory.Exists(Path.GetDirectoryName(context.Configuration.LinkerPdbFilePath))) + { + Directory.CreateDirectory(Path.GetDirectoryName(context.Configuration.LinkerPdbFilePath)); + } + } + + private string GetCompilerPath(GenerationContext context) + { + return KitsRootPaths.GetCompilerSettings(context.Compiler).BinPath; + } + + private string GetLinkerPath(GenerationContext context) + { + return context.Configuration.Output == Project.Configuration.OutputType.Lib + ? KitsRootPaths.GetCompilerSettings(context.Compiler).ArchiverPath + : KitsRootPaths.GetCompilerSettings(context.Compiler).LinkerPath; + } + + private void GenerateHeader(FileGenerator fileGenerator) + { + fileGenerator.WriteLine($"# !! Sharpmake generated file !!"); + fileGenerator.WriteLine($"# All edits will be overwritten on the next sharpmake run"); + fileGenerator.WriteLine($"#"); + fileGenerator.WriteLine($"# Make sure we have the right version of Ninja"); + fileGenerator.WriteLine($"ninja_required_version = 1.1"); + fileGenerator.WriteLine($"builddir = .ninja"); + fileGenerator.WriteLine($""); + } + + private void GenerateRules(FileGenerator fileGenerator, GenerationContext context) + { + // Compilation + fileGenerator.WriteLine($"# Rules to specify how to do things"); + fileGenerator.WriteLine($""); + fileGenerator.WriteLine($"# Rule for compiling C++ files using {context.Compiler}"); + fileGenerator.WriteLine($"{Template.RuleBegin} {Template.RuleStatement.CompileCppFile(context)}"); + fileGenerator.WriteLine($" depfile = ${Template.BuildStatement.DepFile(context)}"); + fileGenerator.WriteLine($" deps = gcc"); + fileGenerator.WriteLine($"{Template.CommandBegin}{GetCompilerPath(context)} ${Template.BuildStatement.Defines(context)} ${Template.BuildStatement.SystemIncludes(context)} ${Template.BuildStatement.Includes(context)} ${Template.BuildStatement.CompilerFlags(context)} ${Template.BuildStatement.CompilerImplicitFlags(context)} {Template.Input}"); + fileGenerator.WriteLine($"{Template.DescriptionBegin} Building C++ object $out"); + fileGenerator.WriteLine($""); + + // Linking + + string outputType = context.Configuration.Output == Project.Configuration.OutputType.Exe + ? "executable" + : "archive"; + + fileGenerator.WriteLine($"# Rule for linking C++ objects"); + fileGenerator.WriteLine($"{Template.RuleBegin}{Template.RuleStatement.LinkToUse(context)}"); + fileGenerator.WriteLine($"{Template.CommandBegin}cmd.exe /C \"${Template.BuildStatement.PreBuild(context)} && {GetLinkerPath(context)} ${Template.BuildStatement.LinkerImplicitFlags(context)} ${Template.BuildStatement.LinkerFlags(context)} ${Template.BuildStatement.ImplicitLinkerPaths(context)} ${Template.BuildStatement.ImplicitLinkerLibraries(context)} ${Template.BuildStatement.LinkerLibraries(context)} $in && ${Template.BuildStatement.PostBuild(context)}\""); + fileGenerator.WriteLine($"{Template.DescriptionBegin}Linking C++ {outputType} ${Template.BuildStatement.TargetFile(context)}"); + fileGenerator.WriteLine($" restat = $RESTAT"); + fileGenerator.WriteLine($""); + + // Cleaning + fileGenerator.WriteLine($"# Rule to clean all built files"); + fileGenerator.WriteLine($"{Template.RuleBegin}{Template.RuleStatement.Clean(context)}"); + fileGenerator.WriteLine($"{Template.CommandBegin}{KitsRootPaths.GetNinjaPath()} -f {GetPerConfigFilePath(context.Configuration, context.Compiler)} -t clean"); + fileGenerator.WriteLine($"{Template.DescriptionBegin}Cleaning all build files"); + fileGenerator.WriteLine($""); + + // Compiler DB + fileGenerator.WriteLine($"# Rule to generate compiler db"); + fileGenerator.WriteLine($"{Template.RuleBegin}{Template.RuleStatement.CompilerDB(context)}"); + fileGenerator.WriteLine($"{Template.CommandBegin}{KitsRootPaths.GetNinjaPath()} -f {GetPerConfigFilePath(context.Configuration, context.Compiler)} -t compdb {Template.RuleStatement.CompileCppFile(context)}"); + fileGenerator.WriteLine($""); + } + + private List GenerateCompileStatements(GenerationContext context, Strings filesToCompile, Strings objPaths) + { + List statements = new List(); + + for (int i = 0; i < filesToCompile.Count; ++i) + { + string fileToCompile = filesToCompile.ElementAt(i); + string objPath = objPaths.ElementAt(i); + string ninjaFilePath = CreateNinjaFilePath(fileToCompile); + + var compileStatement = new CompileStatement(objPath, ninjaFilePath, context); + compileStatement.Defines = context.Configuration.Defines; + compileStatement.DepPath = objPath; + compileStatement.ImplicitCompilerFlags = GetImplicitCompilerFlags(context, objPath); + compileStatement.CompilerFlags = GetCompilerFlags(context); + OrderableStrings includePaths = context.Configuration.IncludePaths; + includePaths.AddRange(context.Configuration.DependenciesIncludePaths); + compileStatement.Includes = includePaths; + OrderableStrings systemIncludePaths = context.Configuration.IncludeSystemPaths; + systemIncludePaths.AddRange(context.Configuration.DependenciesIncludeSystemPaths); + compileStatement.SystemIncludes = systemIncludePaths; + compileStatement.TargetFilePath = context.Configuration.LinkerPdbFilePath; + + statements.Add(compileStatement); + } + + return statements; + } + + private List GenerateLinking(GenerationContext context, Strings objFilePaths) + { + List statements = new List(); + + string outputPath = FullOutputPath(context); + + var linkStatement = new LinkStatement(context, outputPath); + + linkStatement.ObjFilePaths = objFilePaths; + linkStatement.ImplicitLinkerFlags = GetImplicitLinkerFlags(context, outputPath); + linkStatement.Flags = GetLinkerFlags(context); + linkStatement.ImplicitLinkerPaths = GetImplicitLinkPaths(context); + linkStatement.LinkerPaths = GetLinkerPaths(context); + linkStatement.ImplicitLinkerLibs = GetImplicitLinkLibraries(context); + linkStatement.LinkerLibs = GetLinkLibraries(context); + linkStatement.PreBuild = GetPreBuildCommands(context); + linkStatement.PostBuild = GetPostBuildCommands(context); + linkStatement.TargetPdb = context.Configuration.LinkerPdbFilePath; + + statements.Add(linkStatement); + + return statements; + } + + private void GenerateProjectBuilds(FileGenerator fileGenerator, GenerationContext context) + { + //build app.exe: phony d$:\testing\ninjasharpmake\.rex\build\ninja\app\debug\bin\app.exe + string phony_name = $"{ context.Configuration.Name }_{ context.Compiler}_{ context.Configuration.TargetFileFullName}".ToLower(); + fileGenerator.WriteLine($"{Template.BuildBegin}{phony_name}: phony {FullOutputPath(context)}"); + fileGenerator.WriteLine($"{Template.BuildBegin}{Template.CleanBuildStatement(context)}: {Template.RuleStatement.Clean(context)}"); + fileGenerator.WriteLine($"{Template.BuildBegin}{Template.CompDBBuildStatement(context)}: {Template.RuleStatement.CompilerDB(context)}"); + fileGenerator.WriteLine($""); + + fileGenerator.WriteLine($"default {phony_name}"); + } + + private static string CreateNinjaFilePath(string path) + { + if (!Path.IsPathRooted(path)) + { + return path; + } + + // filepaths are absolute and Ninja doesn't support a ':' in a path + // We need to prepend '$' to the ':' to make sure Ninja parses it correctly + string driveLetter = path.Substring(0, 1); + string filePathWithoutDriveLetter = path.Substring(1); + return $"{driveLetter}${filePathWithoutDriveLetter}"; + + } + + // subtract all compiler options from the config and translate them to compiler specific flags + private Strings GetImplicitCompilerFlags(GenerationContext context, string ninjaObjPath) + { + Strings flags = new Strings(); + switch (context.Configuration.Target.GetFragment()) + { + case Compiler.MSVC: + flags.Add("/nologo"); // supress copyright banner in compiler + flags.Add("/TP"); // treat all files on command line as C++ files + flags.Add(" /c"); // don't auto link + flags.Add($" /Fo\"{ninjaObjPath}\""); // obj output path + flags.Add($" /FS"); // force async pdb generation + break; + case Compiler.Clang: + flags.Add(" -c"); // don't auto link + flags.Add($" -o\"{ninjaObjPath}\""); // obj output path + break; + case Compiler.GCC: + flags.Add(" -D_M_X64"); // used in corecrt_stdio_config.h + flags.Add($" -o\"{ninjaObjPath}\""); // obj output path + flags.Add(" -c"); // don't auto link + break; + default: + throw new Error("Unknown Compiler used for implicit compiler flags"); + } + + if (context.Configuration.Output == Project.Configuration.OutputType.Dll) + { + if (PlatformRegistry.Get(context.Configuration.Platform).HasSharedLibrarySupport) + { + flags.Add($" {CompilerFlagLookupTable.Get(context.Compiler, CompilerFlag.Define)}_WINDLL"); + } + } + + int index = context.Configuration.Options.FindIndex(x => x.GetType() == typeof(Options.Vc.Compiler.CppLanguageStandard)); + if (index != -1) + { + object option = context.Configuration.Options[index]; + Options.Vc.Compiler.CppLanguageStandard cppStandard = (Options.Vc.Compiler.CppLanguageStandard)option; + + //switch (cppStandard) + //{ + // case Options.Vc.Compiler.CppLanguageStandard.CPP14: + // flags.Add($" {CompilerFlagLookupTable.Get(context.Compiler, CompilerFlag.Define)}_MSVC_LANG=201402L"); + // break; + // case Options.Vc.Compiler.CppLanguageStandard.CPP17: + // flags.Add($" {CompilerFlagLookupTable.Get(context.Compiler, CompilerFlag.Define)}_MSVC_LANG=201703L"); + // break; + // case Options.Vc.Compiler.CppLanguageStandard.CPP20: + // flags.Add($" {CompilerFlagLookupTable.Get(context.Compiler, CompilerFlag.Define)}_MSVC_LANG=202002L"); + // break; + // case Options.Vc.Compiler.CppLanguageStandard.Latest: + // flags.Add($" {CompilerFlagLookupTable.Get(context.Compiler, CompilerFlag.Define)}_MSVC_LANG=202004L"); + // break; + // default: + // flags.Add($" {CompilerFlagLookupTable.Get(context.Compiler, CompilerFlag.Define)}_MSVC_LANG=201402L"); + // break; + //} + } + + return flags; + } + private Strings GetImplicitLinkerFlags(GenerationContext context, string outputPath) + { + Strings flags = new Strings(); + switch (context.Configuration.Target.GetFragment()) + { + case Compiler.MSVC: + flags.Add("/nologo"); // supress copyright banner in compiler + flags.Add($" /OUT:{outputPath}"); // Output file + if (context.Configuration.Output == Project.Configuration.OutputType.Dll) + { + flags.Add(" /dll"); + } + break; + case Compiler.Clang: + if (context.Configuration.Output != Project.Configuration.OutputType.Lib) + { + flags.Add(" -fuse-ld=lld-link"); // use the llvm lld linker + flags.Add(" -nostartfiles"); // Do not use the standard system startup files when linking + flags.Add(" -nostdlib"); // Do not use the standard system startup files or libraries when linking + flags.Add($" -o {outputPath}"); // Output file + if (context.Configuration.Output == Project.Configuration.OutputType.Dll) + { + flags.Add(" -shared"); + } + } + else + { + flags.Add(" qc"); + flags.Add($" {outputPath}"); // Output file + } + break; + case Compiler.GCC: + //flags += " -fuse-ld=lld"; // use the llvm lld linker + //flags.Add(" -nostdlib"); // Do not use the standard system startup files or libraries when linking + if (context.Configuration.Output != Project.Configuration.OutputType.Exe) + { + flags.Add($"qc {outputPath}"); // Output file + } + else + { + flags.Add($"-o {outputPath}"); // Output file + } + if (context.Configuration.Output == Project.Configuration.OutputType.Dll) + { + flags.Add(" -shared"); + } + break; + default: + throw new Error("Unknown Compiler used for implicit linker flags"); + } + + return flags; + } + + private Strings GetImplicitLinkPaths(GenerationContext context) + { + Strings linkPath = new Strings(); + + if (context.Configuration.Output != Project.Configuration.OutputType.Lib) + { + + switch (context.Configuration.Target.GetFragment()) + { + case Compiler.MSVC: + linkPath.Add("\"D:/Tools/MSVC/install/14.29.30133/lib/x64\""); + linkPath.Add("\"D:/Tools/MSVC/install/14.29.30133/atlmfc/lib/x64\""); + linkPath.Add("\"D:/Tools/Windows SDK/10.0.19041.0/lib/ucrt/x64\""); + linkPath.Add("\"D:/Tools/Windows SDK/10.0.19041.0/lib/um/x64\""); + break; + case Compiler.Clang: + linkPath.Add("\"D:/Tools/MSVC/install/14.29.30133/lib/x64\""); + linkPath.Add("\"D:/Tools/MSVC/install/14.29.30133/atlmfc/lib/x64\""); + linkPath.Add("\"D:/Tools/Windows SDK/10.0.19041.0/lib/ucrt/x64\""); + linkPath.Add("\"D:/Tools/Windows SDK/10.0.19041.0/lib/um/x64\""); + break; + case Compiler.GCC: + //linkPath.Add("\"D:/Tools/MSVC/install/14.29.30133/lib/x64\""); + //linkPath.Add("\"D:/Tools/MSVC/install/14.29.30133/atlmfc/lib/x64\""); + //linkPath.Add("\"D:/Tools/Windows SDK/10.0.19041.0/lib/ucrt/x64\""); + //linkPath.Add("\"D:/Tools/Windows SDK/10.0.19041.0/lib/um/x64\""); + break; + } + } + return linkPath; + } + + private Strings GetImplicitLinkLibraries(GenerationContext context) + { + Strings linkLibraries = new Strings(); + + if (context.Configuration.Output == Project.Configuration.OutputType.Lib) + return linkLibraries; + + switch (context.Configuration.Target.GetFragment()) + { + case Compiler.MSVC: + linkLibraries.Add("kernel32.lib"); + linkLibraries.Add("user32.lib"); + linkLibraries.Add("gdi32.lib"); + linkLibraries.Add("winspool.lib"); + linkLibraries.Add("shell32.lib"); + linkLibraries.Add("ole32.lib"); + linkLibraries.Add("oleaut32.lib"); + linkLibraries.Add("uuid.lib"); + linkLibraries.Add("comdlg32.lib"); + linkLibraries.Add("advapi32.lib"); + linkLibraries.Add("oldnames.lib"); + break; + case Compiler.Clang: + linkLibraries.Add("kernel32"); + linkLibraries.Add("user32"); + linkLibraries.Add("gdi32"); + linkLibraries.Add("winspool"); + linkLibraries.Add("shell32"); + linkLibraries.Add("ole32"); + linkLibraries.Add("oleaut32"); + linkLibraries.Add("uuid"); + linkLibraries.Add("comdlg32"); + linkLibraries.Add("advapi32"); + linkLibraries.Add("oldnames"); + linkLibraries.Add("libcmt.lib"); + break; + case Compiler.GCC: + //linkLibraries.Add("kernel32"); + //linkLibraries.Add("user32"); + //linkLibraries.Add("gdi32"); + //linkLibraries.Add("winspool"); + //linkLibraries.Add("shell32"); + //linkLibraries.Add("ole32"); + //linkLibraries.Add("oleaut32"); + //linkLibraries.Add("uuid"); + //linkLibraries.Add("comdlg32"); + //linkLibraries.Add("advapi32"); + //linkLibraries.Add("oldnames"); + break; + } + + return linkLibraries; + } + + private Strings GetCompilerFlags(GenerationContext context) + { + return new Strings(context.CommandLineOptions.Values); + } + + private Strings GetLinkerPaths(GenerationContext context) + { + return new Strings(context.Configuration.LibraryPaths); + } + private Strings GetLinkLibraries(GenerationContext context) + { + return new Strings(context.Configuration.LibraryFiles); + } + + private string GetPreBuildCommands(GenerationContext context) + { + string preBuildCommand = ""; + string suffix = " && "; + + foreach (var command in context.Configuration.EventPreBuild) + { + preBuildCommand += command; + preBuildCommand += suffix; + } + + // remove trailing && if possible + if (preBuildCommand.EndsWith(suffix)) + { + preBuildCommand = preBuildCommand.Substring(0, preBuildCommand.Length - suffix.Length); + } + + return preBuildCommand; + } + + private string GetPostBuildCommands(GenerationContext context) + { + string postBuildCommand = ""; + string suffix = " && "; + + foreach (var command in context.Configuration.EventPostBuild) + { + postBuildCommand += command; + postBuildCommand += suffix; + } + + // remove trailing && if possible + if (postBuildCommand.EndsWith(suffix)) + { + postBuildCommand = postBuildCommand.Substring(0, postBuildCommand.Length - suffix.Length); + } + + return postBuildCommand; + } + + private Strings GetLinkerFlags(GenerationContext context) + { + Strings flags = new Strings(context.LinkerCommandLineOptions.Values); + + // If we're making an archive, not all linker flags are supported + switch (context.Compiler) + { + case Compiler.MSVC: + return FilterMsvcLinkerFlags(flags, context); + case Compiler.Clang: + return FilterClangLinkerFlags(flags, context); + case Compiler.GCC: + return FilterGccLinkerFlags(flags, context); + default: + throw new Error($"Not linker flag filtering implemented for compiler {context.Compiler}"); + } + } + + private Strings FilterMsvcLinkerFlags(Strings flags, GenerationContext context) + { + switch (context.Configuration.Output) + { + case Project.Configuration.OutputType.Exe: + break; + case Project.Configuration.OutputType.Lib: + RemoveIfContains(flags, "/INCREMENTAL"); + RemoveIfContains(flags, "/DYNAMICBASE"); + RemoveIfContains(flags, "/DEBUG"); + RemoveIfContains(flags, "/PDB"); + RemoveIfContains(flags, "/LARGEADDRESSAWARE"); + RemoveIfContains(flags, "/OPT:REF"); + RemoveIfContains(flags, "/OPT:ICF"); + RemoveIfContains(flags, "/OPT:NOREF"); + RemoveIfContains(flags, "/OPT:NOICF"); + RemoveIfContains(flags, "/FUNCTIONPADMIN"); + break; + case Project.Configuration.OutputType.Dll: + default: + break; + } + + return flags; + } + private Strings FilterClangLinkerFlags(Strings flags, GenerationContext context) + { + switch (context.Configuration.Output) + { + case Project.Configuration.OutputType.Exe: + break; + case Project.Configuration.OutputType.Lib: + break; + case Project.Configuration.OutputType.Dll: + break; + default: + break; + } + + return flags; + } + private Strings FilterGccLinkerFlags(Strings flags, GenerationContext context) + { + switch (context.Configuration.Output) + { + case Project.Configuration.OutputType.Exe: + break; + case Project.Configuration.OutputType.Lib: + break; + case Project.Configuration.OutputType.Dll: + break; + default: + break; + } + + return flags; + } + + private void RemoveIfContains(Strings flags, string value) + { + flags.RemoveAll(x => x.StartsWith(value)); + } + + private void GenerateConfOptions(GenerationContext context) + { + // generate all configuration options once... + var projectOptionsGen = new GenericProjectOptionsGenerator(); + var projectConfigurationOptions = new Dictionary(); + context.SetProjectConfigurationOptions(projectConfigurationOptions); + + // set generator information + var configurationTasks = PlatformRegistry.Get(context.Configuration.Platform); + context.Configuration.GeneratorSetOutputFullExtensions( + configurationTasks.GetDefaultOutputFullExtension(Project.Configuration.OutputType.Exe), + configurationTasks.GetDefaultOutputFullExtension(Project.Configuration.OutputType.Exe), + configurationTasks.GetDefaultOutputFullExtension(Project.Configuration.OutputType.Dll), + ".pdb"); + + projectConfigurationOptions.Add(context.Configuration, new Options.ExplicitOptions()); + context.CommandLineOptions = new GenericProjectOptionsGenerator.GenericCmdLineOptions(); + context.LinkerCommandLineOptions = new GenericProjectOptionsGenerator.GenericCmdLineOptions(); + + projectOptionsGen.GenerateOptions(context); + } + } +} diff --git a/Sharpmake.Generators/IGenerationContext.cs b/Sharpmake.Generators/IGenerationContext.cs index 95b0cd61a..5f44390b5 100644 --- a/Sharpmake.Generators/IGenerationContext.cs +++ b/Sharpmake.Generators/IGenerationContext.cs @@ -25,7 +25,9 @@ public interface IGenerationContext DevEnv DevelopmentEnvironment { get; } Options.ExplicitOptions Options { get; } - IDictionary CommandLineOptions { get; } + IDictionary CommandLineOptions { get; } // for the compiler + IDictionary LinkerCommandLineOptions { get; } // for the linker + string ProjectDirectoryCapitalized { get; } string ProjectSourceCapitalized { get; } diff --git a/Sharpmake.Generators/Sharpmake.Generators.csproj b/Sharpmake.Generators/Sharpmake.Generators.csproj index fa86fe3e4..a2d35612f 100644 --- a/Sharpmake.Generators/Sharpmake.Generators.csproj +++ b/Sharpmake.Generators/Sharpmake.Generators.csproj @@ -69,6 +69,7 @@ + @@ -76,6 +77,9 @@ + + + diff --git a/Sharpmake.Generators/VisualStudio/Androidproj.cs b/Sharpmake.Generators/VisualStudio/Androidproj.cs index b088b9c20..3586646fc 100644 --- a/Sharpmake.Generators/VisualStudio/Androidproj.cs +++ b/Sharpmake.Generators/VisualStudio/Androidproj.cs @@ -39,6 +39,7 @@ public Options.ExplicitOptions Options } } public IDictionary CommandLineOptions { get; set; } + public IDictionary LinkerCommandLineOptions { get; set; } = new ProjectOptionsGenerator.VcxprojCmdLineOptions(); public string ProjectDirectoryCapitalized { get; } public string ProjectSourceCapitalized { get; } public bool PlainOutput { get; } diff --git a/Sharpmake.Generators/VisualStudio/ProjectOptionsGenerator.cs b/Sharpmake.Generators/VisualStudio/ProjectOptionsGenerator.cs index 2980e12a8..6d5b9e11d 100644 --- a/Sharpmake.Generators/VisualStudio/ProjectOptionsGenerator.cs +++ b/Sharpmake.Generators/VisualStudio/ProjectOptionsGenerator.cs @@ -1059,6 +1059,16 @@ private void GenerateCompilerOptions(IGenerationContext context, ProjectOptionsG Options.Option(Options.Vc.Compiler.EnableAsan.Enable, () => { context.Options["EnableASAN"] = "true"; context.CommandLineOptions["EnableASAN"] = "/fsanitize=address"; }) ); + context.SelectOption + ( + Options.Option(Options.Vc.Compiler.JumboBuild.Disable, () => { context.Options["JumboBuild"] = FileGeneratorUtilities.RemoveLineTag; context.Options["MaxFilesPerUnityFile"] = FileGeneratorUtilities.RemoveLineTag; }), + Options.Option(Options.Vc.Compiler.JumboBuild.Enable, () => + { + context.Options["JumboBuild"] = "true"; + context.Options["MaxFilesPerUnityFile"] = context.Configuration.MaxFilesPerUnityFile.ToString(); + }) + ); + if (context.DevelopmentEnvironment.IsVisualStudio() && context.DevelopmentEnvironment >= DevEnv.vs2017) { //Options.Vc.Compiler.DefineCPlusPlus. See: https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/ diff --git a/Sharpmake.Generators/VisualStudio/Sln.cs b/Sharpmake.Generators/VisualStudio/Sln.cs index 596e6d450..c5180acd9 100644 --- a/Sharpmake.Generators/VisualStudio/Sln.cs +++ b/Sharpmake.Generators/VisualStudio/Sln.cs @@ -81,7 +81,7 @@ public static string ToOption(Guid[] projectTypes) public partial class Sln : ISolutionGenerator { - public const string SolutionExtension = ".sln"; + public readonly string SolutionExtension = Util.GetSolutionExtension(DevEnv.VisualStudio); private readonly List _rootSolutionFolders = new List(); private readonly List _solutionFolders = new List(); diff --git a/Sharpmake.Generators/VisualStudio/Vcxproj.cs b/Sharpmake.Generators/VisualStudio/Vcxproj.cs index a88a4f8bc..b953bc4bc 100644 --- a/Sharpmake.Generators/VisualStudio/Vcxproj.cs +++ b/Sharpmake.Generators/VisualStudio/Vcxproj.cs @@ -93,6 +93,7 @@ public IDictionary CommandLineOptions _cmdLineOptions = value; } } + public IDictionary LinkerCommandLineOptions { get; set; } = new ProjectOptionsGenerator.VcxprojCmdLineOptions(); public Resolver EnvironmentVariableResolver { get diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/BasePlatform.Vcxproj.Template.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/BasePlatform.Vcxproj.Template.cs index 45894e91c..d3838f67b 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/BasePlatform.Vcxproj.Template.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/BasePlatform.Vcxproj.Template.cs @@ -190,7 +190,14 @@ public abstract partial class BasePlatform [options.WindowsTargetPlatformVersion] [options.SpectreMitigation] [options.EnableASAN] - + [options.JumboBuild] + True + [options.MaxFilesPerUnityFile] + 2> + 1 + 100 + . + "; private const string _projectConfigurationsGeneral2 = diff --git a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Windows/Win64Platform.cs b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Windows/Win64Platform.cs index 8ce9aba9b..afe322f23 100644 --- a/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Windows/Win64Platform.cs +++ b/Sharpmake.Platforms/Sharpmake.CommonPlatforms/Windows/Win64Platform.cs @@ -356,7 +356,7 @@ public override IEnumerable GetImplicitlyDefinedSymbols(IGenerationConte public override void SetupPlatformTargetOptions(IGenerationContext context) { context.Options["TargetMachine"] = "MachineX64"; - context.CommandLineOptions["TargetMachine"] = "/MACHINE:X64"; + context.LinkerCommandLineOptions["TargetMachine"] = "/MACHINE:X64"; } public override void SelectPlatformAdditionalDependenciesOptions(IGenerationContext context) diff --git a/Sharpmake/Builder.cs b/Sharpmake/Builder.cs index c0deaf989..fe1c95e2f 100644 --- a/Sharpmake/Builder.cs +++ b/Sharpmake/Builder.cs @@ -1222,15 +1222,25 @@ private void GenerateSolutionFile(object arg) try { - DevEnv devEnv = configurations[0].Target.GetFragment(); for (int i = 0; i < configurations.Count; ++i) { - Solution.Configuration conf = pair.Value[i]; - if (devEnv != conf.Target.GetFragment()) - throw new Error("Multiple generator cannot output to the same file:" + Environment.NewLine + "\t'{0}' and '{1}' try to generate '{2}'", - devEnv, - conf.Target.GetFragment(), - solutionFile); + for (int j = 0; j < configurations.Count; ++j) + { + Solution.Configuration confI = pair.Value[i]; + Solution.Configuration confJ = pair.Value[j]; + + DevEnv envI = confI.Target.GetFragment(); + DevEnv envJ = confJ.Target.GetFragment(); + + if (envI != envJ) + { + if (Util.GetSolutionExtension(envI) == Util.GetSolutionExtension(envJ)) + { + throw new Error("Multiple generator cannot output to the same file:" + Environment.NewLine + "\t'{0}' and '{1}' try to generate '{2}'", + envI, envJ, solutionFile); + } + } + } } _getGeneratorsManagerCallBack().Generate(this, solution, configurations, solutionFile, output.Generated, output.Skipped); diff --git a/Sharpmake/CompilerFlagLookupTable.cs b/Sharpmake/CompilerFlagLookupTable.cs new file mode 100644 index 000000000..d70405f8c --- /dev/null +++ b/Sharpmake/CompilerFlagLookupTable.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sharpmake +{ + enum CompilerFlag + { + Define, + Include, + SystemInclude + } + + class CompilerFlagLookupTable + { + private static Dictionary MsvcCompilerFlags = new Dictionary(); + private static Dictionary ClangCompilerFlags = new Dictionary(); + private static Dictionary GccCompilerFlags = new Dictionary(); + + public static void Init() + { + CreateMsvcLookupTable(); + CreateClangLookupTable(); + CreateGccLookupTable(); + } + + public static string Get(Compiler compiler, CompilerFlag flag) + { + switch (compiler) + { + case Compiler.MSVC: return MsvcCompilerFlags.GetValueOrAdd(flag, ""); + case Compiler.Clang: return ClangCompilerFlags.GetValueOrAdd(flag, ""); + case Compiler.GCC: return GccCompilerFlags.GetValueOrAdd(flag, ""); + default: throw new Error("Unknown compiler used for compiler flag lookup"); + } + } + + private static void CreateMsvcLookupTable() + { + MsvcCompilerFlags.Add(CompilerFlag.Define, "/D"); + MsvcCompilerFlags.Add(CompilerFlag.Include, "/I"); + MsvcCompilerFlags.Add(CompilerFlag.SystemInclude, "/I"); + } + private static void CreateClangLookupTable() + { + ClangCompilerFlags.Add(CompilerFlag.Define, "-D"); + ClangCompilerFlags.Add(CompilerFlag.Include, "-I"); + ClangCompilerFlags.Add(CompilerFlag.SystemInclude, "-isystem"); + } + private static void CreateGccLookupTable() + { + GccCompilerFlags.Add(CompilerFlag.Define, "-D"); + GccCompilerFlags.Add(CompilerFlag.Include, "-I"); + GccCompilerFlags.Add(CompilerFlag.SystemInclude, "-isystem"); + } + } +} diff --git a/Sharpmake/CompilerInfo.cs b/Sharpmake/CompilerInfo.cs new file mode 100644 index 000000000..912805413 --- /dev/null +++ b/Sharpmake/CompilerInfo.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sharpmake +{ + [Fragment, Flags] + public enum Compiler + { + Auto = (1 << 0), // Determine Compiler from DevEnv (eg. Visual Studio -> MSVC) + MSVC = (1 << 1), // Microsoft and compatible compilers + Clang = (1 << 2), // Clang and compatible compilers + GCC = (1 << 3), // GCC and compatible compilers + } + + public class CompilerInfo + { + public CompilerInfo(Compiler compiler, string binPath, string linkerPath, string archivePath, string ranLibPath) + { + Compiler = compiler; + BinPath = binPath; + LinkerPath = linkerPath; + ArchiverPath = archivePath; + RanLibPath = ranLibPath; + } + + public Compiler Compiler { get; set; } + public string BinPath { get; set; } + public string LinkerPath { get; set; } + public string ArchiverPath { get; set; } + public string RanLibPath { get; set; } + } +} diff --git a/Sharpmake/ExtensionMethods.cs b/Sharpmake/ExtensionMethods.cs index 3748df4fb..2663c2edb 100644 --- a/Sharpmake/ExtensionMethods.cs +++ b/Sharpmake/ExtensionMethods.cs @@ -41,9 +41,9 @@ public static bool IsLinkerInvokedViaCompiler(this Platform platform) return PlatformRegistry.Get(platform).IsLinkerInvokedViaCompiler; } - public static string GetLinkerOptionPrefix(this Platform platform) + public static string GetLinkerOptionPrefix(this Platform platform, Compiler compiler = Compiler.Auto) { - if (IsUsingClang(platform) && IsLinkerInvokedViaCompiler(platform)) + if ((IsUsingClang(platform) || compiler == Compiler.Clang) && IsLinkerInvokedViaCompiler(platform)) return "-Wl,"; return ""; diff --git a/Sharpmake/KitsRootPaths.cs b/Sharpmake/KitsRootPaths.cs index 3e707ef4c..ab2314728 100644 --- a/Sharpmake/KitsRootPaths.cs +++ b/Sharpmake/KitsRootPaths.cs @@ -27,6 +27,10 @@ public class KitsRootPaths private static Dictionary> s_useKitsRootForDevEnv = new Dictionary>(); private static Dictionary s_kitsRoots = new Dictionary(); + private static Dictionary s_compilerInfo = new Dictionary(); + + private static string s_ninjaPath = ""; + private static readonly ConcurrentDictionary s_netFxKitsDir = new ConcurrentDictionary(); private static readonly ConcurrentDictionary s_netFxToolsDir = new ConcurrentDictionary(); @@ -145,6 +149,125 @@ public static Options.Vc.General.WindowsTargetPlatformVersion GetWindowsTargetPl throw new NotImplementedException("No WindowsTargetPlatformVersion associated with " + devEnv); } + public static void InitializeForNinja() + { + const string MsvcCompilerName = "cl.exe"; + const string ClangCompilerName = "clang.exe"; + const string GccCompilerName = "g++.exe"; + const string MsvcLinkerName = "link.exe"; + const string ClangLinkerName = "clang.exe"; + const string GccLinkerName = "g++.exe"; + + const string MsvcArchiverName = "lib.exe"; + const string ClangArchiverName = "llvm-ar.exe"; + const string ClangRanLibName = "llvm-ranlib.exe"; + const string GccArchiverName = "ar.exe"; + + const string NinjaName = "ninja.exe"; + + string MsvcCompilerPath = ""; + string ClangCompilerPath = ""; + string GccCompilerPath = ""; + string MsvcLinkerPath = ""; + string ClangLinkerPath = ""; + string GccLinkerPath = ""; + + string MsvcArchiver = ""; + string ClangArchiver = ""; + string ClangRanLib = ""; + string GccArchiver = ""; + + string NinjaPath = ""; + + var envPath = Environment.GetEnvironmentVariable("PATH"); + string[] paths = envPath.Split(';'); + + foreach (var path in paths) + { + if (!Directory.Exists(path)) + { + continue; + } + + List files = Directory.EnumerateFiles(path).ToList(); + + foreach (string file in files) + { + string filename = Path.GetFileName(file); + + if (filename == MsvcCompilerName) + { + MsvcCompilerPath = file; + } + if (filename == ClangCompilerName) + { + ClangCompilerPath = file; + } + if (filename == GccCompilerName) + { + GccCompilerPath = file; + } + if (filename == MsvcLinkerName) + { + MsvcLinkerPath = file; + } + if (filename == ClangLinkerName) + { + ClangLinkerPath = file; + } + if (filename == GccLinkerName) + { + GccLinkerPath = file; + } + if (filename == MsvcArchiverName) + { + MsvcArchiver = file; + } + if (filename == ClangArchiverName) + { + ClangArchiver = file; + } + if (filename == ClangRanLibName) + { + ClangRanLib = file; + } + if (filename == GccArchiverName) + { + GccArchiver = file; + } + if (filename == NinjaName) + { + NinjaPath = file; + } + } + } + + SetCompilerPaths(Compiler.MSVC, MsvcCompilerPath, MsvcLinkerPath, MsvcArchiver, ""); + SetCompilerPaths(Compiler.Clang, ClangCompilerPath, ClangLinkerPath, ClangArchiver, ClangRanLib); + SetCompilerPaths(Compiler.GCC, GccCompilerPath, GccLinkerPath, GccArchiver, ""); + SetNinjaPath(NinjaPath); + } + + private static void SetCompilerPaths(Compiler compiler, string compilerPath, string linkerPath, string archiverPath, string ranLibPath) + { + s_compilerInfo.GetValueOrAdd(compiler, new CompilerInfo(compiler, compilerPath, linkerPath, archiverPath, ranLibPath)); + } + + public static CompilerInfo GetCompilerSettings(Compiler compiler) + { + return s_compilerInfo[compiler]; + } + + private static void SetNinjaPath(string path) + { + s_ninjaPath = path; + } + + public static string GetNinjaPath() + { + return s_ninjaPath; + } + public static string GetNETFXKitsDir(DotNetFramework dotNetFramework) { string netFxKitsDir; diff --git a/Sharpmake/LinkerFlagLookupTable.cs b/Sharpmake/LinkerFlagLookupTable.cs new file mode 100644 index 000000000..5a85aa459 --- /dev/null +++ b/Sharpmake/LinkerFlagLookupTable.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sharpmake +{ + enum LinkerFlag + { + IncludePath, + IncludeFile + } + class LinkerFlagLookupTable + { + private static Dictionary MsvcCompilerFlags = new Dictionary(); + private static Dictionary ClangCompilerFlags = new Dictionary(); + private static Dictionary GccCompilerFlags = new Dictionary(); + + public static void Init() + { + CreateMsvcLookupTable(); + CreateClangLookupTable(); + CreateGccLookupTable(); + } + + public static string Get(Compiler compiler, LinkerFlag flag) + { + switch (compiler) + { + case Compiler.MSVC: + return MsvcCompilerFlags.GetValueOrAdd(flag, ""); + case Compiler.Clang: + return ClangCompilerFlags.GetValueOrAdd(flag, ""); + case Compiler.GCC: + return GccCompilerFlags.GetValueOrAdd(flag, ""); + default: + throw new Error("Unknown compiler used for linker flag lookup"); + } + } + + private static void CreateMsvcLookupTable() + { + MsvcCompilerFlags.Add(LinkerFlag.IncludePath, "/LIBPATH:"); + MsvcCompilerFlags.Add(LinkerFlag.IncludeFile, ""); + } + private static void CreateClangLookupTable() + { + ClangCompilerFlags.Add(LinkerFlag.IncludePath, "-L"); + ClangCompilerFlags.Add(LinkerFlag.IncludeFile, "-l"); + } + private static void CreateGccLookupTable() + { + GccCompilerFlags.Add(LinkerFlag.IncludePath, "-L"); + GccCompilerFlags.Add(LinkerFlag.IncludeFile, "-l"); + } + } +} diff --git a/Sharpmake/Options.Vc.cs b/Sharpmake/Options.Vc.cs index 1f14cdc59..22fdd3162 100644 --- a/Sharpmake/Options.Vc.cs +++ b/Sharpmake/Options.Vc.cs @@ -1358,6 +1358,20 @@ public enum EnableAsan [DevEnvVersion(minimum = DevEnv.vs2019)] Enable } + + /// + /// Enable Jumbo/Unity builds + /// + /// + /// Merges multiple translation units together + /// + public enum JumboBuild + { + [Default] + Disable, + [DevEnvVersion(minimum = DevEnv.vs2019)] + Enable + } } public static class CodeAnalysis diff --git a/Sharpmake/Project.Configuration.cs b/Sharpmake/Project.Configuration.cs index f567d1e98..3e63f6061 100644 --- a/Sharpmake/Project.Configuration.cs +++ b/Sharpmake/Project.Configuration.cs @@ -1379,6 +1379,9 @@ public string FastBuildUnityPath /// public bool DoNotGenerateFastBuild = false; + // Unity builds support + public int MaxFilesPerUnityFile = 0; + // container for executable /// /// Represents a build step that invokes an executable on the file system. diff --git a/Sharpmake/Sharpmake.csproj b/Sharpmake/Sharpmake.csproj index 0ee61d84d..b2d9772f9 100644 --- a/Sharpmake/Sharpmake.csproj +++ b/Sharpmake/Sharpmake.csproj @@ -67,6 +67,7 @@ + @@ -94,7 +95,9 @@ + + diff --git a/Sharpmake/Target.cs b/Sharpmake/Target.cs index 62d5d2c59..fcb72cda7 100644 --- a/Sharpmake/Target.cs +++ b/Sharpmake/Target.cs @@ -64,6 +64,11 @@ public enum DevEnv /// make = 1 << 9, + /// + /// Using Ninja with the MSVC compiler + /// + ninja = 1 << 10, + /// /// All supported Visual Studio versions. /// @@ -127,6 +132,7 @@ public enum BuildSystem { MSBuild = 0x01, FastBuild = 0x02, + None = 0x04 } [Fragment, Flags] diff --git a/Sharpmake/Util.cs b/Sharpmake/Util.cs index 4ba0611c4..11bee272f 100644 --- a/Sharpmake/Util.cs +++ b/Sharpmake/Util.cs @@ -1443,6 +1443,9 @@ public static string GetProjectFileExtension(Project.Configuration conf) case DevEnv.make: return ".make"; + case DevEnv.ninja: + return ".ninja"; + default: throw new NotImplementedException("GetProjectFileExtension called with unknown DevEnv: " + devEnv); } @@ -1769,6 +1772,27 @@ private int Parse(string version) } } + public static string GetSolutionExtension(DevEnv env) + { + switch (env) + { + case DevEnv.vs2015: + case DevEnv.vs2017: + case DevEnv.vs2019: + case DevEnv.vs2022: + case DevEnv.VisualStudio: + return ".sln"; + case DevEnv.xcode4ios: + case DevEnv.eclipse: + case DevEnv.make: + return ""; + case DevEnv.ninja: + return ".ninja"; + default: + throw new Error("Unknown DevEnv for solution extension"); + } + } + // http://www.mono-project.com/docs/faq/technical/#how-can-i-detect-if-am-running-in-mono private static readonly bool s_monoRuntimeExists = (Type.GetType("Mono.Runtime") != null); public static bool IsRunningInMono() => s_monoRuntimeExists; diff --git a/UpgradeLog.htm b/UpgradeLog.htm new file mode 100644 index 000000000..82181709e Binary files /dev/null and b/UpgradeLog.htm differ