From 847ba93202902b05c06e31a410129bf8ea9ca4e2 Mon Sep 17 00:00:00 2001 From: Nick De Breuck Date: Sat, 5 Nov 2022 12:20:16 +0000 Subject: [PATCH 1/7] added support for ninja generator (executables only) --- Sharpmake.Application/Program.cs | 5 +- Sharpmake.Generators/Apple/XCodeProj.cs | 1 + Sharpmake.Generators/FastBuild/Bff.cs | 1 + Sharpmake.Generators/GeneratorManager.cs | 77 +- .../Generic/GenericProjectOptionsGenerator.cs | 2715 +++++++++++++++++ .../Generic/JsonCompilationDatabase.cs | 2 + .../Generic/NinjaProject.Template.cs | 46 + Sharpmake.Generators/Generic/NinjaProject.cs | 816 +++++ Sharpmake.Generators/IGenerationContext.cs | 4 +- .../Sharpmake.Generators.csproj | 3 + .../VisualStudio/Androidproj.cs | 1 + Sharpmake.Generators/VisualStudio/Sln.cs | 2 +- Sharpmake.Generators/VisualStudio/Vcxproj.cs | 1 + .../Windows/Win64Platform.cs | 2 +- Sharpmake/Builder.cs | 24 +- Sharpmake/CompilerFlagLookupTable.cs | 59 + Sharpmake/CompilerInfo.cs | 31 + Sharpmake/ExtensionMethods.cs | 4 +- Sharpmake/KitsRootPaths.cs | 96 + Sharpmake/LinkerFlagLookupTable.cs | 58 + Sharpmake/Sharpmake.csproj | 3 + Sharpmake/Target.cs | 6 + Sharpmake/Util.cs | 24 + 23 files changed, 3944 insertions(+), 37 deletions(-) create mode 100644 Sharpmake.Generators/Generic/GenericProjectOptionsGenerator.cs create mode 100644 Sharpmake.Generators/Generic/NinjaProject.Template.cs create mode 100644 Sharpmake.Generators/Generic/NinjaProject.cs create mode 100644 Sharpmake/CompilerFlagLookupTable.cs create mode 100644 Sharpmake/CompilerInfo.cs create mode 100644 Sharpmake/LinkerFlagLookupTable.cs diff --git a/Sharpmake.Application/Program.cs b/Sharpmake.Application/Program.cs index b8cc7aa2b..3b9dff448 100644 --- a/Sharpmake.Application/Program.cs +++ b/Sharpmake.Application/Program.cs @@ -252,6 +252,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 @@ -402,7 +405,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 4aa5f4ff0..e9fb16d43 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..18ca30f1c --- /dev/null +++ b/Sharpmake.Generators/Generic/GenericProjectOptionsGenerator.cs @@ -0,0 +1,2715 @@ +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"; + context.CommandLineOptions["ConfigurationType"] = @"/D""_WINDLL"""; + } + 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 + 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"; }) + ); + } + 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..b727b71d6 --- /dev/null +++ b/Sharpmake.Generators/Generic/NinjaProject.Template.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sharpmake.Generators.Generic +{ + public partial class NinjaProject + { + public static class Template + { + public static class Project + { + public static string ConfigurationBegin = "CONFIGURATION"; + + public static string RuleBegin = "rule "; + + public static string BuildBegin = "build "; + public static string BuildCPPFileName = "COMPILE_CPP_FILE_[project_name]_[config_name]_[config_compiler]"; + public static string BuildLinkExeName = "LINK_CPP_FILE_EXE_[project_name]_[config_name]_[config_compiler]"; + public static string Clean = "Clean_[config_name]_[config_compiler]"; + + public static string CommandBegin = " command = "; + public static string DescriptionBegin = " description = "; + + public static readonly string Defines = "[project_name]_[config_name]_[config_compiler]_DEFINES"; + public static readonly string Includes = "[project_name]_[config_name]_[config_compiler]_INCLUDES"; + public static readonly string SystemIncludes = "[project_name]_[config_name]_[config_compiler]_SYSTEM_INCLUDES"; + public static readonly string DepFile = "[project_name]_[config_name]_[config_compiler]_DEP_FILE"; + public static readonly string CompilerImplicitFlags = "[project_name]_[config_name]_[config_compiler]_COMPILER_IMPLICIT_FLAGS"; + public static readonly string LinkerImplicitFlags = "[project_name]_[config_name]_[config_compiler]_LINKER_IMPLICIT_FLAGS"; + public static readonly string CompilerFlags = "[project_name]_[config_name]_[config_compiler]_COMPILER_FLAGS"; + public static readonly string LinkerFlags = "[project_name]_[config_name]_[config_compiler]_LINKER_FLAGS"; + public static readonly string TargetPdb = "[project_name]_[config_name]_[config_compiler]_TARGET_PDB"; + public static readonly string ImplicitLinkPaths = "[project_name]_[config_name]_[config_compiler]_IMPLICIT_LINK_PATHS"; + public static readonly string ImplicitLinkLibraries = "[project_name]_[config_name]_[config_compiler]_IMPLICIT_LINK_LIBRARIES"; + public static readonly string LinkPaths = "[project_name]_[config_name]_[config_compiler]_LINK_PATHS"; + public static readonly string LinkLibraries = "[project_name]_[config_name]_[config_compiler]_LINK_LIBRARIES"; + public static readonly string PostBuild = "[project_name]_[config_name]_[config_compiler]_POST_BUILD"; + public static readonly string PreBuild = "[project_name]_[config_name]_[config_compiler]_PRE_BUILD"; + public static readonly string TargetFile = "[project_name]_[config_name]_[config_compiler]_TARGET_FILE"; + } + } + } +} diff --git a/Sharpmake.Generators/Generic/NinjaProject.cs b/Sharpmake.Generators/Generic/NinjaProject.cs new file mode 100644 index 000000000..b1f7c4f15 --- /dev/null +++ b/Sharpmake.Generators/Generic/NinjaProject.cs @@ -0,0 +1,816 @@ +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(); + + fileGenerator.Declare("project_name", Context.Project.Name); + fileGenerator.Declare("config_name", Context.Configuration.Name); + fileGenerator.Declare("config_compiler", Context.Compiler.ToString()); + + 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.Project.BuildBegin}{Name}: {Template.Project.BuildCPPFileName} {Input}"); + + WriteIfNotEmpty(fileGenerator, $" {Template.Project.Defines}", defines); + WriteIfNotEmpty(fileGenerator, $" {Template.Project.DepFile}", $"{DepPath}.d"); + WriteIfNotEmpty(fileGenerator, $" {Template.Project.CompilerImplicitFlags}", implicitCompilerFlags); + WriteIfNotEmpty(fileGenerator, $" {Template.Project.SystemIncludes}", systemIncludes); + WriteIfNotEmpty(fileGenerator, $" {Template.Project.CompilerFlags}", compilerFlags); + WriteIfNotEmpty(fileGenerator, $" {Template.Project.Includes}", includes); + WriteIfNotEmpty(fileGenerator, $" {Template.Project.TargetPdb}", 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(); + + fileGenerator.Declare("project_name", Context.Project.Name); + fileGenerator.Declare("config_name", Context.Configuration.Name); + fileGenerator.Declare("config_compiler", Context.Compiler.ToString()); + + 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.Project.BuildBegin}{CreateNinjaFilePath(FullOutputPath(Context))}: {Template.Project.BuildLinkExeName} {objPaths}"); + + WriteIfNotEmpty(fileGenerator, $" {Template.Project.LinkerImplicitFlags}", implicitLinkerFlags); + WriteIfNotEmpty(fileGenerator, $" {Template.Project.ImplicitLinkPaths}", implicitLinkerPaths); + WriteIfNotEmpty(fileGenerator, $" {Template.Project.ImplicitLinkLibraries}", implicitLinkerLibs); + WriteIfNotEmpty(fileGenerator, $" {Template.Project.LinkerFlags}", linkerFlags); + WriteIfNotEmpty(fileGenerator, $" {Template.Project.LinkPaths}", libraryPaths); + WriteIfNotEmpty(fileGenerator, $" {Template.Project.LinkLibraries}", libraryFiles); + WriteIfNotEmpty(fileGenerator, $" {Template.Project.TargetFile}", OutputPath); + WriteIfNotEmpty(fileGenerator, $" {Template.Project.TargetPdb}", TargetPdb); + WriteIfNotEmptyOr(fileGenerator, $" {Template.Project.PreBuild}", PreBuild, "cd ."); + WriteIfNotEmptyOr(fileGenerator, $" {Template.Project.PostBuild}", 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); + + WritePerConfigFile(context, filesToCompile, generatedFiles, skipFiles); + } + + // 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(); + foreach (var config in configurations) + { + GenerationContext context = new GenerationContext(builder, projectFilePath, project, config); + + filePaths.Add(GetPerConfigFilePath(context)); + } + + var fileGenerator = new FileGenerator(); + + GenerateHeader(fileGenerator); + + foreach (var path in filePaths) + { + fileGenerator.WriteLine($"include {CreateNinjaFilePath(path)}"); + } + + 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(); + + fileGenerator.Declare("project_name", context.Project.Name); + fileGenerator.Declare("config_name", context.Configuration.Name); + fileGenerator.Declare("config_compiler", context.Compiler.ToString()); + + GenerateHeader(fileGenerator); + 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); + + if (SaveFileGeneratorToDisk(fileGenerator, context, filePath)) + { + generatedFiles.Add(filePath); + } + else + { + skipFiles.Add(filePath); + } + } + + private string GetPerConfigFilePath(GenerationContext context) + { + return Path.Combine(context.Configuration.ProjectPath, "ninja", $"{context.Project.Name}.{context.Configuration.Name}.{context.Compiler}{ProjectExtension}"); + } + + 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 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"); + } + + 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.Project.RuleBegin} {Template.Project.BuildCPPFileName}"); + fileGenerator.WriteLine($" depfile = ${Template.Project.DepFile}"); + fileGenerator.WriteLine($" deps = gcc"); + fileGenerator.WriteLine($"{Template.Project.CommandBegin}{GetCompilerPath(context)} ${Template.Project.Defines} ${Template.Project.SystemIncludes} ${Template.Project.Includes} ${Template.Project.CompilerFlags} ${Template.Project.CompilerImplicitFlags} $in"); + fileGenerator.WriteLine($"{Template.Project.DescriptionBegin} Building C++ object $out"); + fileGenerator.WriteLine($""); + + // Linking + fileGenerator.WriteLine($"# Rule for linking C++ objects"); + fileGenerator.WriteLine($"{Template.Project.RuleBegin}{Template.Project.BuildLinkExeName}"); + fileGenerator.WriteLine($"{Template.Project.CommandBegin}cmd.exe /C \"${Template.Project.PreBuild} && {GetLinkerPath(context)} ${Template.Project.LinkerImplicitFlags} ${Template.Project.LinkerFlags} ${Template.Project.ImplicitLinkPaths} ${Template.Project.ImplicitLinkLibraries} ${Template.Project.LinkLibraries} $in && ${Template.Project.PostBuild}\""); + fileGenerator.WriteLine($"{Template.Project.DescriptionBegin}Linking C++ executable $TARGET_FILE"); + fileGenerator.WriteLine($" restat = $RESTAT"); + fileGenerator.WriteLine($""); + + // Cleaning + fileGenerator.WriteLine($"# Rule to clean all built files"); + fileGenerator.WriteLine($"{Template.Project.RuleBegin}{Template.Project.Clean}"); + fileGenerator.WriteLine($"{Template.Project.CommandBegin}{KitsRootPaths.GetNinjaPath()} $FILE_ARG -t clean $TARGETS"); + fileGenerator.WriteLine($"{Template.Project.DescriptionBegin}Cleaning all built files"); + 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); + compileStatement.Includes = context.Configuration.IncludePaths; + compileStatement.SystemIncludes = context.Configuration.IncludeSystemPaths; + 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 = ""; + linkStatement.PostBuild = ""; + 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.Project.BuildBegin}{phony_name}: phony {FullOutputPath(context)}"); + + 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(" /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(" -c"); // don't auto link + break; + default: + throw new Error("Unknown Compiler used for implicit compiler flags"); + } + + return flags; + } + private Strings GetImplicitLinkerFlags(GenerationContext context, string outputPath) + { + Strings flags = new Strings(); + switch (context.Configuration.Target.GetFragment()) + { + case Compiler.MSVC: + flags.Add($" /OUT:{outputPath}"); // Output file + break; + case Compiler.Clang: + 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 + break; + case Compiler.GCC: + //flags += " -fuse-ld=lld"; // 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 + break; + default: + throw new Error("Unknown Compiler used for implicit linker flags"); + } + + return flags; + } + + private Strings GetImplicitLinkPaths(GenerationContext context) + { + Strings linkPath = new Strings(); + + 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(); + + 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 Strings GetLinkerFlags(GenerationContext context) + { + return new Strings(context.LinkerCommandLineOptions.Values); + } + + 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 82d8b4667..b1732927e 100644 --- a/Sharpmake.Generators/Sharpmake.Generators.csproj +++ b/Sharpmake.Generators/Sharpmake.Generators.csproj @@ -112,6 +112,7 @@ + @@ -119,6 +120,8 @@ + + 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/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 c1b2191a7..cef50eda8 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/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 833cf45b2..b313b0263 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..b8cb8c672 --- /dev/null +++ b/Sharpmake/CompilerInfo.cs @@ -0,0 +1,31 @@ +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) + { + Compiler = compiler; + BinPath = binPath; + LinkerPath = linkerPath; + } + + public Compiler Compiler { get; set; } + public string BinPath { get; set; } + public string LinkerPath { get; set; } + } +} diff --git a/Sharpmake/ExtensionMethods.cs b/Sharpmake/ExtensionMethods.cs index eefa9a7dd..47297118c 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..4f75aa0f8 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,98 @@ 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 NinjaName = "ninja.exe"; + + string MsvcCompilerPath = ""; + string ClangCompilerPath = ""; + string GccCompilerPath = ""; + string MsvcLinkerPath = ""; + string ClangLinkerPath = ""; + string GccLinkerPath = ""; + 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 == NinjaName) + { + NinjaPath = file; + } + } + } + + SetCompilerPaths(Compiler.MSVC, MsvcCompilerPath, MsvcLinkerPath); + SetCompilerPaths(Compiler.Clang, ClangCompilerPath, ClangLinkerPath); + SetCompilerPaths(Compiler.GCC, GccCompilerPath, GccLinkerPath); + SetNinjaPath(NinjaPath); + } + + private static void SetCompilerPaths(Compiler compiler, string compilerPath, string linkerPath) + { + s_compilerInfo.GetValueOrAdd(compiler, new CompilerInfo(compiler, compilerPath, linkerPath)); + } + + 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/Sharpmake.csproj b/Sharpmake/Sharpmake.csproj index 974d4b285..5ffa5e1a2 100644 --- a/Sharpmake/Sharpmake.csproj +++ b/Sharpmake/Sharpmake.csproj @@ -106,6 +106,7 @@ + @@ -132,7 +133,9 @@ + + diff --git a/Sharpmake/Target.cs b/Sharpmake/Target.cs index 2b04d7088..40d63a48e 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 5abf5c33e..1bba7f7ba 100644 --- a/Sharpmake/Util.cs +++ b/Sharpmake/Util.cs @@ -1448,6 +1448,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); } @@ -1782,6 +1785,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; From b84c6488c35e78d60c03474b896aad328b74fa09 Mon Sep 17 00:00:00 2001 From: Nick De Breuck Date: Sat, 5 Nov 2022 19:21:41 +0000 Subject: [PATCH 2/7] added support for static libraries and dynamic libraries --- .../Generic/GenericProjectOptionsGenerator.cs | 1 - Sharpmake.Generators/Generic/NinjaProject.cs | 152 ++++++++++++++---- Sharpmake/CompilerInfo.cs | 6 +- Sharpmake/KitsRootPaths.cs | 31 +++- 4 files changed, 155 insertions(+), 35 deletions(-) diff --git a/Sharpmake.Generators/Generic/GenericProjectOptionsGenerator.cs b/Sharpmake.Generators/Generic/GenericProjectOptionsGenerator.cs index 18ca30f1c..a12d25e0e 100644 --- a/Sharpmake.Generators/Generic/GenericProjectOptionsGenerator.cs +++ b/Sharpmake.Generators/Generic/GenericProjectOptionsGenerator.cs @@ -167,7 +167,6 @@ private static void SelectConfigurationTypeOption(IGenerationContext context) 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"; - context.CommandLineOptions["ConfigurationType"] = @"/D""_WINDLL"""; } break; case Project.Configuration.OutputType.Lib: diff --git a/Sharpmake.Generators/Generic/NinjaProject.cs b/Sharpmake.Generators/Generic/NinjaProject.cs index b1f7c4f15..6c873ab7f 100644 --- a/Sharpmake.Generators/Generic/NinjaProject.cs +++ b/Sharpmake.Generators/Generic/NinjaProject.cs @@ -224,7 +224,7 @@ public override string ToString() WriteIfNotEmptyOr(fileGenerator, $" {Template.Project.PreBuild}", PreBuild, "cd ."); WriteIfNotEmptyOr(fileGenerator, $" {Template.Project.PostBuild}", PostBuild, "cd ."); ; - + return fileGenerator.ToString(); } } @@ -397,7 +397,7 @@ private void WritePerConfigFile(GenerationContext context, Strings filesToCompil { fileGenerator.WriteLine(compileStatement.ToString()); } - + foreach (var linkStatement in linkStatements) { fileGenerator.WriteLine(linkStatement.ToString()); @@ -527,7 +527,9 @@ private string GetCompilerPath(GenerationContext context) private string GetLinkerPath(GenerationContext context) { - return KitsRootPaths.GetCompilerSettings(context.Compiler).LinkerPath; + return context.Configuration.Output == Project.Configuration.OutputType.Lib + ? KitsRootPaths.GetCompilerSettings(context.Compiler).ArchiverPath + : KitsRootPaths.GetCompilerSettings(context.Compiler).LinkerPath; } private void GenerateHeader(FileGenerator fileGenerator) @@ -554,10 +556,15 @@ private void GenerateRules(FileGenerator fileGenerator, GenerationContext contex fileGenerator.WriteLine($""); // Linking + + string outputType = context.Configuration.Output == Project.Configuration.OutputType.Exe + ? "executable" + : "archive"; + fileGenerator.WriteLine($"# Rule for linking C++ objects"); fileGenerator.WriteLine($"{Template.Project.RuleBegin}{Template.Project.BuildLinkExeName}"); fileGenerator.WriteLine($"{Template.Project.CommandBegin}cmd.exe /C \"${Template.Project.PreBuild} && {GetLinkerPath(context)} ${Template.Project.LinkerImplicitFlags} ${Template.Project.LinkerFlags} ${Template.Project.ImplicitLinkPaths} ${Template.Project.ImplicitLinkLibraries} ${Template.Project.LinkLibraries} $in && ${Template.Project.PostBuild}\""); - fileGenerator.WriteLine($"{Template.Project.DescriptionBegin}Linking C++ executable $TARGET_FILE"); + fileGenerator.WriteLine($"{Template.Project.DescriptionBegin}Linking C++ {outputType} ${Template.Project.TargetFile}"); fileGenerator.WriteLine($" restat = $RESTAT"); fileGenerator.WriteLine($""); @@ -664,6 +671,14 @@ private Strings GetImplicitCompilerFlags(GenerationContext context, string ninja 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"); + } + } + return flags; } private Strings GetImplicitLinkerFlags(GenerationContext context, string outputPath) @@ -673,12 +688,28 @@ private Strings GetImplicitLinkerFlags(GenerationContext context, string outputP { case Compiler.MSVC: flags.Add($" /OUT:{outputPath}"); // Output file + if (context.Configuration.Output == Project.Configuration.OutputType.Dll) + { + flags.Add(" /dll"); + } break; case Compiler.Clang: - 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.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 @@ -697,26 +728,30 @@ private Strings GetImplicitLinkPaths(GenerationContext context) { Strings linkPath = new Strings(); - switch (context.Configuration.Target.GetFragment()) + if (context.Configuration.Output != Project.Configuration.OutputType.Lib) { - 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; + + 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; @@ -726,6 +761,9 @@ 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: @@ -788,7 +826,65 @@ private Strings GetLinkLibraries(GenerationContext context) } private Strings GetLinkerFlags(GenerationContext context) { - return new Strings(context.LinkerCommandLineOptions.Values); + 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); + 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 void RemoveIfContains(Strings flags, string value) + { + flags.RemoveAll(x => x.StartsWith(value)); } private void GenerateConfOptions(GenerationContext context) diff --git a/Sharpmake/CompilerInfo.cs b/Sharpmake/CompilerInfo.cs index b8cb8c672..912805413 100644 --- a/Sharpmake/CompilerInfo.cs +++ b/Sharpmake/CompilerInfo.cs @@ -17,15 +17,19 @@ public enum Compiler public class CompilerInfo { - public CompilerInfo(Compiler compiler, string binPath, string linkerPath) + 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/KitsRootPaths.cs b/Sharpmake/KitsRootPaths.cs index 4f75aa0f8..d309404bc 100644 --- a/Sharpmake/KitsRootPaths.cs +++ b/Sharpmake/KitsRootPaths.cs @@ -158,6 +158,10 @@ public static void InitializeForNinja() 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 NinjaName = "ninja.exe"; string MsvcCompilerPath = ""; @@ -166,6 +170,11 @@ public static void InitializeForNinja() string MsvcLinkerPath = ""; string ClangLinkerPath = ""; string GccLinkerPath = ""; + + string MsvcArchiver = ""; + string ClangArchiver = ""; + string ClangRanLib = ""; + string NinjaPath = ""; var envPath = Environment.GetEnvironmentVariable("PATH"); @@ -208,6 +217,18 @@ public static void InitializeForNinja() { GccLinkerPath = file; } + if (filename == MsvcArchiverName) + { + MsvcArchiver = file; + } + if (filename == ClangArchiverName) + { + ClangArchiver = file; + } + if (filename == ClangRanLibName) + { + ClangRanLib = file; + } if (filename == NinjaName) { NinjaPath = file; @@ -215,15 +236,15 @@ public static void InitializeForNinja() } } - SetCompilerPaths(Compiler.MSVC, MsvcCompilerPath, MsvcLinkerPath); - SetCompilerPaths(Compiler.Clang, ClangCompilerPath, ClangLinkerPath); - SetCompilerPaths(Compiler.GCC, GccCompilerPath, GccLinkerPath); + SetCompilerPaths(Compiler.MSVC, MsvcCompilerPath, MsvcLinkerPath, MsvcArchiver, ""); + SetCompilerPaths(Compiler.Clang, ClangCompilerPath, ClangLinkerPath, ClangArchiver, ClangRanLib); + SetCompilerPaths(Compiler.GCC, GccCompilerPath, GccLinkerPath, GccLinkerPath, ""); SetNinjaPath(NinjaPath); } - private static void SetCompilerPaths(Compiler compiler, string compilerPath, string linkerPath) + private static void SetCompilerPaths(Compiler compiler, string compilerPath, string linkerPath, string archiverPath, string ranLibPath) { - s_compilerInfo.GetValueOrAdd(compiler, new CompilerInfo(compiler, compilerPath, linkerPath)); + s_compilerInfo.GetValueOrAdd(compiler, new CompilerInfo(compiler, compilerPath, linkerPath, archiverPath, ranLibPath)); } public static CompilerInfo GetCompilerSettings(Compiler compiler) From a15f32242c883e6c04f7f1b30ed393f3c7ba1b35 Mon Sep 17 00:00:00 2001 From: Nick De Breuck Date: Mon, 7 Nov 2022 23:31:27 +0000 Subject: [PATCH 3/7] updated sharpmake to support post build commands better and clang-tidy tooling --- .../Generic/NinjaProject.Template.cs | 181 ++++++++++++++---- Sharpmake.Generators/Generic/NinjaProject.cs | 167 +++++++++++----- UpgradeLog.htm | Bin 0 -> 81518 bytes 3 files changed, 264 insertions(+), 84 deletions(-) create mode 100644 UpgradeLog.htm diff --git a/Sharpmake.Generators/Generic/NinjaProject.Template.cs b/Sharpmake.Generators/Generic/NinjaProject.Template.cs index b727b71d6..3b494b534 100644 --- a/Sharpmake.Generators/Generic/NinjaProject.Template.cs +++ b/Sharpmake.Generators/Generic/NinjaProject.Template.cs @@ -1,46 +1,151 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Sharpmake.Generators.Generic +namespace Sharpmake.Generators.Generic { public partial class NinjaProject { - public static class Template + private static class Template { - public static class Project + // 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 ConfigurationBegin = "CONFIGURATION"; - - public static string RuleBegin = "rule "; - - public static string BuildBegin = "build "; - public static string BuildCPPFileName = "COMPILE_CPP_FILE_[project_name]_[config_name]_[config_compiler]"; - public static string BuildLinkExeName = "LINK_CPP_FILE_EXE_[project_name]_[config_name]_[config_compiler]"; - public static string Clean = "Clean_[config_name]_[config_compiler]"; - - public static string CommandBegin = " command = "; - public static string DescriptionBegin = " description = "; - - public static readonly string Defines = "[project_name]_[config_name]_[config_compiler]_DEFINES"; - public static readonly string Includes = "[project_name]_[config_name]_[config_compiler]_INCLUDES"; - public static readonly string SystemIncludes = "[project_name]_[config_name]_[config_compiler]_SYSTEM_INCLUDES"; - public static readonly string DepFile = "[project_name]_[config_name]_[config_compiler]_DEP_FILE"; - public static readonly string CompilerImplicitFlags = "[project_name]_[config_name]_[config_compiler]_COMPILER_IMPLICIT_FLAGS"; - public static readonly string LinkerImplicitFlags = "[project_name]_[config_name]_[config_compiler]_LINKER_IMPLICIT_FLAGS"; - public static readonly string CompilerFlags = "[project_name]_[config_name]_[config_compiler]_COMPILER_FLAGS"; - public static readonly string LinkerFlags = "[project_name]_[config_name]_[config_compiler]_LINKER_FLAGS"; - public static readonly string TargetPdb = "[project_name]_[config_name]_[config_compiler]_TARGET_PDB"; - public static readonly string ImplicitLinkPaths = "[project_name]_[config_name]_[config_compiler]_IMPLICIT_LINK_PATHS"; - public static readonly string ImplicitLinkLibraries = "[project_name]_[config_name]_[config_compiler]_IMPLICIT_LINK_LIBRARIES"; - public static readonly string LinkPaths = "[project_name]_[config_name]_[config_compiler]_LINK_PATHS"; - public static readonly string LinkLibraries = "[project_name]_[config_name]_[config_compiler]_LINK_LIBRARIES"; - public static readonly string PostBuild = "[project_name]_[config_name]_[config_compiler]_POST_BUILD"; - public static readonly string PreBuild = "[project_name]_[config_name]_[config_compiler]_PRE_BUILD"; - public static readonly string TargetFile = "[project_name]_[config_name]_[config_compiler]_TARGET_FILE"; - } + 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 index 6c873ab7f..6a66be48e 100644 --- a/Sharpmake.Generators/Generic/NinjaProject.cs +++ b/Sharpmake.Generators/Generic/NinjaProject.cs @@ -146,25 +146,21 @@ public override string ToString() { var fileGenerator = new FileGenerator(); - fileGenerator.Declare("project_name", Context.Project.Name); - fileGenerator.Declare("config_name", Context.Configuration.Name); - fileGenerator.Declare("config_compiler", Context.Compiler.ToString()); - 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.Project.BuildBegin}{Name}: {Template.Project.BuildCPPFileName} {Input}"); + fileGenerator.WriteLine($"{Template.BuildBegin}{Name}: {Template.RuleStatement.CompileCppFile(Context)} {Input}"); - WriteIfNotEmpty(fileGenerator, $" {Template.Project.Defines}", defines); - WriteIfNotEmpty(fileGenerator, $" {Template.Project.DepFile}", $"{DepPath}.d"); - WriteIfNotEmpty(fileGenerator, $" {Template.Project.CompilerImplicitFlags}", implicitCompilerFlags); - WriteIfNotEmpty(fileGenerator, $" {Template.Project.SystemIncludes}", systemIncludes); - WriteIfNotEmpty(fileGenerator, $" {Template.Project.CompilerFlags}", compilerFlags); - WriteIfNotEmpty(fileGenerator, $" {Template.Project.Includes}", includes); - WriteIfNotEmpty(fileGenerator, $" {Template.Project.TargetPdb}", TargetFilePath); + 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(); } @@ -199,10 +195,6 @@ public override string ToString() { var fileGenerator = new FileGenerator(); - fileGenerator.Declare("project_name", Context.Project.Name); - fileGenerator.Declare("config_name", Context.Configuration.Name); - fileGenerator.Declare("config_compiler", Context.Compiler.ToString()); - string objPaths = MergeMultipleFlagsToString(ObjFilePaths); string implicitLinkerFlags = MergeMultipleFlagsToString(ImplicitLinkerFlags); string implicitLinkerPaths = MergeMultipleFlagsToString(ImplicitLinkerPaths, LinkerFlagLookupTable.Get(Context.Compiler, LinkerFlag.IncludePath)); @@ -211,18 +203,18 @@ public override string ToString() string libraryPaths = MergeMultipleFlagsToString(LinkerPaths, LinkerFlagLookupTable.Get(Context.Compiler, LinkerFlag.IncludePath)); string libraryFiles = MergeMultipleFlagsToString(LinkerLibs, LinkerFlagLookupTable.Get(Context.Compiler, LinkerFlag.IncludeFile)); - fileGenerator.WriteLine($"{Template.Project.BuildBegin}{CreateNinjaFilePath(FullOutputPath(Context))}: {Template.Project.BuildLinkExeName} {objPaths}"); - - WriteIfNotEmpty(fileGenerator, $" {Template.Project.LinkerImplicitFlags}", implicitLinkerFlags); - WriteIfNotEmpty(fileGenerator, $" {Template.Project.ImplicitLinkPaths}", implicitLinkerPaths); - WriteIfNotEmpty(fileGenerator, $" {Template.Project.ImplicitLinkLibraries}", implicitLinkerLibs); - WriteIfNotEmpty(fileGenerator, $" {Template.Project.LinkerFlags}", linkerFlags); - WriteIfNotEmpty(fileGenerator, $" {Template.Project.LinkPaths}", libraryPaths); - WriteIfNotEmpty(fileGenerator, $" {Template.Project.LinkLibraries}", libraryFiles); - WriteIfNotEmpty(fileGenerator, $" {Template.Project.TargetFile}", OutputPath); - WriteIfNotEmpty(fileGenerator, $" {Template.Project.TargetPdb}", TargetPdb); - WriteIfNotEmptyOr(fileGenerator, $" {Template.Project.PreBuild}", PreBuild, "cd ."); - WriteIfNotEmptyOr(fileGenerator, $" {Template.Project.PostBuild}", PostBuild, "cd ."); + 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(); @@ -275,6 +267,7 @@ public void Generate( GenerationContext context = new GenerationContext(builder, projectFilePath, project, config); WritePerConfigFile(context, filesToCompile, generatedFiles, skipFiles); + WriteCompilerDatabaseFile(context); } // the second pass uses these files to create a project file where the files can be build @@ -384,10 +377,6 @@ private void WritePerConfigFile(GenerationContext context, Strings filesToCompil var fileGenerator = new FileGenerator(); - fileGenerator.Declare("project_name", context.Project.Name); - fileGenerator.Declare("config_name", context.Configuration.Name); - fileGenerator.Declare("config_compiler", context.Compiler.ToString()); - GenerateHeader(fileGenerator); GenerateRules(fileGenerator, context); @@ -417,9 +406,45 @@ private void WritePerConfigFile(GenerationContext context, Strings filesToCompil } } + 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)} {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(GenerationContext context) + { + return $"{context.Project.Name}.{context.Configuration.Name}.{context.Compiler}{ProjectExtension}"; + } + + private string GetCompilerDBPath(GenerationContext context) + { + return $"{Path.Combine(context.Configuration.ProjectPath, "clang_tools", $"{Template.PerConfigFolderFormat(context)}", "compile_commands.json")}"; + } + private string GetPerConfigFilePath(GenerationContext context) { - return Path.Combine(context.Configuration.ProjectPath, "ninja", $"{context.Project.Name}.{context.Configuration.Name}.{context.Compiler}{ProjectExtension}"); + return Path.Combine(context.Configuration.ProjectPath, "ninja", GetPerConfigFileName(context)); } private static void WriteIfNotEmpty(FileGenerator fileGenerator, string key, string value) @@ -548,11 +573,11 @@ private void GenerateRules(FileGenerator fileGenerator, GenerationContext contex fileGenerator.WriteLine($"# Rules to specify how to do things"); fileGenerator.WriteLine($""); fileGenerator.WriteLine($"# Rule for compiling C++ files using {context.Compiler}"); - fileGenerator.WriteLine($"{Template.Project.RuleBegin} {Template.Project.BuildCPPFileName}"); - fileGenerator.WriteLine($" depfile = ${Template.Project.DepFile}"); + fileGenerator.WriteLine($"{Template.RuleBegin} {Template.RuleStatement.CompileCppFile(context)}"); + fileGenerator.WriteLine($" depfile = ${Template.BuildStatement.DepFile(context)}"); fileGenerator.WriteLine($" deps = gcc"); - fileGenerator.WriteLine($"{Template.Project.CommandBegin}{GetCompilerPath(context)} ${Template.Project.Defines} ${Template.Project.SystemIncludes} ${Template.Project.Includes} ${Template.Project.CompilerFlags} ${Template.Project.CompilerImplicitFlags} $in"); - fileGenerator.WriteLine($"{Template.Project.DescriptionBegin} Building C++ object $out"); + 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 @@ -562,17 +587,23 @@ private void GenerateRules(FileGenerator fileGenerator, GenerationContext contex : "archive"; fileGenerator.WriteLine($"# Rule for linking C++ objects"); - fileGenerator.WriteLine($"{Template.Project.RuleBegin}{Template.Project.BuildLinkExeName}"); - fileGenerator.WriteLine($"{Template.Project.CommandBegin}cmd.exe /C \"${Template.Project.PreBuild} && {GetLinkerPath(context)} ${Template.Project.LinkerImplicitFlags} ${Template.Project.LinkerFlags} ${Template.Project.ImplicitLinkPaths} ${Template.Project.ImplicitLinkLibraries} ${Template.Project.LinkLibraries} $in && ${Template.Project.PostBuild}\""); - fileGenerator.WriteLine($"{Template.Project.DescriptionBegin}Linking C++ {outputType} ${Template.Project.TargetFile}"); + 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.Project.RuleBegin}{Template.Project.Clean}"); - fileGenerator.WriteLine($"{Template.Project.CommandBegin}{KitsRootPaths.GetNinjaPath()} $FILE_ARG -t clean $TARGETS"); - fileGenerator.WriteLine($"{Template.Project.DescriptionBegin}Cleaning all built files"); + fileGenerator.WriteLine($"{Template.RuleBegin}{Template.RuleStatement.Clean(context)}"); + fileGenerator.WriteLine($"{Template.CommandBegin}{KitsRootPaths.GetNinjaPath()} -f {GetPerConfigFilePath(context)} -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)} -t compdb {Template.RuleStatement.CompileCppFile(context)}"); fileGenerator.WriteLine($""); } @@ -616,8 +647,8 @@ private List GenerateLinking(GenerationContext context, Strings o linkStatement.LinkerPaths = GetLinkerPaths(context); linkStatement.ImplicitLinkerLibs = GetImplicitLinkLibraries(context); linkStatement.LinkerLibs = GetLinkLibraries(context); - linkStatement.PreBuild = ""; - linkStatement.PostBuild = ""; + linkStatement.PreBuild = GetPreBuildCommands(context); + linkStatement.PostBuild = GetPostBuildCommands(context); linkStatement.TargetPdb = context.Configuration.LinkerPdbFilePath; statements.Add(linkStatement); @@ -629,7 +660,10 @@ private void GenerateProjectBuilds(FileGenerator fileGenerator, GenerationContex { //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.Project.BuildBegin}{phony_name}: phony {FullOutputPath(context)}"); + 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}"); } @@ -824,6 +858,47 @@ 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); diff --git a/UpgradeLog.htm b/UpgradeLog.htm new file mode 100644 index 0000000000000000000000000000000000000000..82181709e7ec8af365db239cfa67ef9743a14ee3 GIT binary patch literal 81518 zcmeI5X>;5-l7{(pH)8)ojlI)$uSb{VyQh0Xr(2c}$&&51M;#NgZtJv4mpwE4(|7lI zk%B?8SS+%{k~y)AiYgXKAdyJCNF);1|NhUPqd!E`(W_`GT8`dF3(-u}ingPZXg}JE zeu@4g`u9j7hWNCicC;FuMH|sN|2L!K=#WsY=#+nZ(a+KCXq3-bbT9gma36Vl3Y{m> zPISO^gHQ+jo)AOSjCKp^KDAbK;Zi*yohSTjbKiE9Z@4rLc-oHE2*1JGRsIig-QkHi zY4hEL`VjZx>&a#8ljsI%DU}W4th@jFj*nG1QCQCpiEfa}-?$!<|2axO|YIFa^@%Ia%v*M&_`1_IQzlbpjuj^0{QazP-h$RhsnmsarCWyMzn2Q_^Z5}8uSL5~)~a6zr27Pp zZ$`7x_~rLr^iyB7RTqSb<4cNT=mPuB_DNB4mqdpsfmK&m_mGnKy%8-T?JeG`1m1wc z8<9$CnQ+@YRsGieQ&%P%)H=I=%l$EVR&BE<(n-=7LwxmahqU_3{}Ghd`AA=FIW9;0 zq$KW-p&?4jZCN`1bmdnDO@{wpk%00bIgF8RvKC0EdEKp24)sC&idQ`e8lr41*e1;~ zJoi@vI!kE``5vK1C1<;aC;nf5hzR(VM*NEORGN3m=Mj?Xk7ia4wl*tX_hv}NfBQ{G zWo%d&a;@ZnRM+hCs(aa zp0iMz=ai({D_I^Y(F1aQ>~zjvNgk`HsV4V$d(~M}Z(yNW+k6J+8_~J51f=<7iye{= zwQQ=>s^e?iTPxh=N%?ww_ZsSPD2;gC8jBuXp>745)s?VEPnO=f|4r|-qVWIwpu7qs zjywG1Be9Lu@$s^?jpIzMwcg1-Z_%Czc}F1fF#2?fNYyi00c!EfV{-gjFTd zEBuC5t~{1kuK~${KecZ+X@SSltaoYYXRb-6vgAJ^J4q|pp}svTXIq?nqcwQ@Qhm8# zH?^sq>T$*U1m*2{--aYlM#L z4?(=Xk4oa+%hLO3hA1a#f-N+F>XeWze^Y-Y6sXEVSEq_LrX)={4&*IT;Y(zI(i>3URmS`I3~ z{%FOunvkpBvCt6ul4^mjUK6vd2y5MDsp0l5Tg%I%%{(p7DPb#nX#%qkT3pq>$*&w* zyx@JzwkXtdlh-s(NBB{^9j9fU;EmKL?X8x@?fZRdWzA|59rXvriAo@8t5|q>?ae~J zg*FR)-&;KQnn`|r^ODLMvUqxCUbYr?y!?;4Q~%TZjmuj@!;W8*+Fus8L)4k={{?iFOwnX&#A7pD3AWE(s}}dJp#T*$@Od5dR^GPxK|%c_{SO*U$P{(&O;%sO&Bw;X z%x03NkVa8h(=ehTe?YlD!LZAPM$h7Tl7D;f81!;WxBHTcmu@+{l&^_ap3BrdY2dV^ z$tEf0NSjsBVy9Pis%4@q2<_38|#_*O{@Rf8|V zbFjQlKDV7MuTg^0=#M4qc)w+~fDFSpleOD^EHAXQzApJO$yL|e@b%V8T_Z02)Sa8I z_8C(3TdwB)-IdS35v$mz)1nRIGRISLTx^15ryD*8f} zYB^2kF=O%>ipfy6{6qZcs)ywedDXH{>P9PHui$2)mP z^1{4xC4S&~BU`y4XYku-jN>>JYVakenNOOj6wvpC)GEm*+t|7+4An*XO!YQt7c-|!YIe`wAj3xvii;A+GP7z>WDtSL2r*7zlE}VPnr!SsY%uC${PeOZw`z`)$LH{Xt^3+ZcVwdza*YzF$pM$yQgpoE{ zC)_cyUocN$o!rfl!Xopa-;vLIyg5KpYw)%JS4v&|fQN1*wT*1{iLnGXqfnEi&j@#b z)E1D4dTjGN`%0>3gnUU#8dF|}TZLbMr{~B?^0+`2DxV4dFT(K$WVg=m8|d%z|AOaA zb(B<|@?N?B3Wpbbmr3OVX)F-`f-t}G{w;5hkklU6Q7Aqpr}NPGLWoh)eM)MN;7IaY z=KdY!JJ0nIF{b$ciZo~7;MB$0BK{sS5Iy;9UXj)kx!WhLaj3lE`hYi!(4Oc2bMmnP zzt1TBGk!G#L=w0ImlLkso)KypKIh>}w#E$a&PekN`Aef+KtppyKElx)vU(2(8-$rc z9`X|Z29GoFy9s}X@URR&>!khwy3a^M-5n)`BAMC+JAPMv`pLIuQl(jYMVvpEv>=WIXvlu63M8`>vzu4$$7~d{24v8vU!4Opl2Df|g>8=dwcXKPXu!LURqBJPXYe{>i>xL{p24Rl>eRE6W=s3t-o^A&;>aUO?vo&tw;G zKuvuStz>!*2e06JjjMc}v;4at2eaty4VSAaTK0LqpJ^9l89pLiwVJZj)VjXqet|e^ zq`601pfq2S)4Rk{J}!7R>(X2zw(OL)3n^Of$n9@%@))X*c{2h}XZ+iOisnGe`kCh6 znv1!Gj9(L5cFrbgeInK*aejsVn0q6seny@z$-xU~Xtu*D@73n-A<=o#SadDo9BrcR z+vG`o!>35~F}Zo{+Uil#`~dA;Ld(NC0;i7%^_u&0;w(Bz-{r|ToXNtzOFQ}&K4m$6 zb@ zS+d;bh;!jkb;h$z{(a%CO8G6)yASUV9m?i;{*ZhvI*z7DXPfsb%W-TNZlRmJ)wB*S&n)dtz6g3_T?;S|uA$3iWYba&iiafGg1LiaABRj0Tr%q;r%9@hzU?Ih2h^X7uztL*U!P6IF z-sk$6RK`jDgs|$Vz9P0fChD)t6LX)CAD}Rf-k;(#&-?dKQC(hiE$lto#~E_)8SVd^ z>nSbNIjzVve0|~bmHep}_=$IFm0m*q4sj-Ueg`UAd#0ZKTR4$5(ne;xv>@^gEWpzl zbRLj5^|p@)B~ImIc|aKTo=4zlmpjpWKpIQrM&6GD=$yJ7-zR;Ihs%O^MC=i+?}$AQ zMLqkK7kr8lGNwtYwYock)Oe| zje&kr4>tW=jiGzbyD;2%^1TnucZBqr}CRWKo=hnQ-0?qczue_eoBfn-0h&Hzw+6GqcNU8Cm-rHsx5p= z5AhfpABj6gD(9{RoI;CO%L%A|fTl(pG$%--$aAix z(JYBES6Xv~xKFqpcwQ&ed-5wE@GNSC>{06r%C-OTt4LOS0}qUWW7vkpZLtd`wYCCLrZ<@XS`YC|1O+P z6JDPCRbp$@X#qJYuhZn|9yycUq*e8S3xm5n_n&I}&b|G^+Q}r$__v)*v@4BJ zqw!$X7}-PGXGJ5lw&%+ya-jK?8U^rSZxCAkhxlGHij^HUZwpN?-M|2F=u-@Lp?=C)Eko`3oIWJ`pxi=Q3e$)~p&QE5eg=bPkAdS1H{S$=O* zV(B?$H{4iEEBa@T`Eq%jOA5CWk{Tv2+SfsTENNOV@gH*~(0lwNUK-ufxEAsVdjvZ52_hL(ou@3S|Z&S^qRcp^5_bmS}h?xsM$Eu2Kju;5=!bHX+Y2CGBj*1 z^6SggC*khpCFR@S(zt59*D4RwjzZxc?Yqybv|%R}WL=+75j z-wwlr+F4m4uUvcLxsZ002Sw}Ki%74m4AZhyZF>thR_9cTd2$T))iB&E))6JIx!9iT zTS&C*%yIFQ#m8TGp2V3i&wM^wu2gN82(6~nytsbpC^vc9%*#{P{C3kq=7-6Do5x3| z<}!;`dunJ@?$GrQG~-5d7USh@+9j^N@^xg9`s!(Tsrr+8)S|8?lm7MfVPxHGSV)38b82fbzcq^eG8zJ#m`)kf_lcH6a0ns1=iIlm6Z zwT}JQJZJSG<^7Q*q%jKZTTz@&zV0cay(~(atZ@X$L=TB%{DUEh1v`#k0za{ObExax{d`Z-QUVr5?hwx5DoV_Ve%9^0x__73O!= z1^gKO#nJc+p|ZkwI)5XSLjK8xUg38I%0IB$a3%UrRvD~-t^Y=At$>gf?5W?OtW^gZ zBhJ?jq5O);EgMn8shWM;Y1BP@sir%Gfm`%{w6=8Hh24bX8}R-EzrVPv{E(~sSAU|_ zgX``FZjPES5KgPExl%q4~%(FJJR3tRAPeeeZb1Er@&s=D*D=;ZDrNJw7kU zd)SjA^hbiv=QcW3J|4esrSIkEmqBmY`?AfZ-aWIcqY_I-1(9D)t5uZ~TZf<3Aqxr8k`f<#tl-8x3qlsIz zGWFq0W0ms#^yVwS{PIgbujD&x=MomI>RT^wK@tH?Exn#v8f;SY;8+hYzUKDUH?*hs zp=mpuscg@CY6Gtw%leM0tBd*iT^g&HCiN22E=X#_ZATrgh1QsWS@yEx&bW*FK21(x ztTbP)vIo`IR!PX_*RMt|bppvAcN%dB?VKOA$gkDPqdwJ?LD0@u)i&ZOU*qJxwbA)7 z#;);sow#D!T6daPq1pZVZ+q&LJsssLXQSvmoR+IY8hJUQmYbTuxnxvHMKPKp+yH?1(6uAM_K9;!FZ z94Rb78oB3dULFHv94>E~rjIxBut*1nAW_4>+sidJVIi^A%&-N|ZK z-)`FBKvt*fw@zRDg?ZP-!iv?A&CYV$6o13embE1N z?NhDnoNn4*HRY-{Q(fB@AxrxiY9+bG;Wp^e`O`~0^18jR4r$30w1<~`jK|< z*4yx!{QFudQ}nU5gOv6vGUSB&s*rMo-Z0Bw$O!ZsB-9HDpeh&U@Y3mWi%QE@4dNgTg%8+^zN6EAs z1l1KmZ?Qvnn8lvfNB(*Bs5!e#F^LzSUW1gnBIO}mBVImgD?bhdA3n=Gvc zA@xFtR*!4m$3EV;Q`ehc$DWXH{^$}dc_FGoPDn#*gXB}t9(BfrG);Kl$z_A6Iw5Kr zENNAk=EJM!tN!>bzqZQD?ABe@uzO23X;b$fyBZ{FUZd?mCV!)GzuCckwjJI-?+t?M zis1f`TP#-fi0ucd#dvKHT33X=pl#HCG&>nuRy(5f*0bd)RFB;KZ@K8iu>2oB7jeHw zT;G<@LxbqLBKj5fXZi9}4>*p9{-{)sY@NGvRdn~4mj>Z=Lb%StP>&|`UuMyH2UwYY zewXH~E~DubN@y+@qZ;IDHK@`Ly|DCLb#bYFnL@3Usz%L*TMwr-H<~A#oo0iWdLqX5LOH#h^AXA}Jg*up zw*Q4vjAJFF*C3^yNO?_<#`}^2PW;oVQKB8s%qP^DR)dgwA|yHX9?C5|uNo!s@tdsl z8l=<{DLNfe`vau=OW}FdNYN>emSVis3F$RRsS{FkuH^(h5SUr-_WsuN)--gdl z!`QwOntvj%lGdk$IY}!8cxhUWI<*{2=y*R@$3{AmPs$*tGiK9Tc%9*|*QYze`aZvB zqjW{*({d&3SG;?gD;X4<8eXp&o-VUtJVM&-LgPm|pTo~{&BjN!&{xAvH>%lq%I3Gh zS>16a-}F8oS*)G?iEenyk9Aetb@GvoxqL4AiPPYYW;W8YLN@rSJHFna2epr?_da(=S7*pF*y`Sg)0(~XuD}{05m(;Zthq;>cH%In z!Kb-z5LYk6g>@IUNK~=6^wVcYBu@sh_R;p>_a{MXXa96sVHf}H zXq^32(>w4dIiH4a?Gmf;jc`u6Wu_@18 zoe+)eQz&faxK2k=PLuM`j{KVSp!}xum^?3```Hr7aLQGj6Yr-|j^Ywe?!#~Su$k=Q zG@WP3PdV)F?Ml*1?@+JUI(H$?K{|~jg@AzkF{*CzREo)!XjvAJouBX|^SmHQGD$%c z?M#SYF3*?MrqEFSf1WC^H@Ej?KUUPI{FHg7v)TiC-(Tf$S*2(s3tY95YeGU)6e(bg(Z z@h(0N;lI^W2InrGrLSD&$GFRW`eS@`I?V$A!r7sR$o7PLvmWf^A?19FXGvY8lO8vm z40Ya-V6uYZH^QNarz0LGgtP>A7&q#xl>g_y|eK@Y$yz_ItWU zx6|Le1X`{=R6CHCL;BRJc2_N+6H-jC+B(*{(q2>UG+_0j z&gdBnsj>{Rd&w(2m;O0+X{@-DG(=VOvU}CxOrFqMH0a5)9rh`KaB5tzg$CVrr}ddM zf%ddFFQMV38?K7CCdKP@QrjkLVrR?aPt{E4q8=@e=kEV+%i|?5*p^3akhk!%^!qS) zR=dBArqT&d-ny_JPx7rWU8EB^0U0UwW3~vS#i5*vQEoPGt`qc zyv+