Sharpmake.Platforms/Sharpmake.CommonPlatforms/Linux/LinuxPlatform.cs (537 lines of code) (raw):
// Copyright (c) Ubisoft. All Rights Reserved.
// Licensed under the Apache 2.0 License. See LICENSE.md in the project root for license information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Sharpmake.Generators;
using Sharpmake.Generators.FastBuild;
using Sharpmake.Generators.VisualStudio;
namespace Sharpmake
{
public static partial class Linux
{
[PlatformImplementation(Platform.linux,
typeof(IPlatformDescriptor),
typeof(IFastBuildCompilerSettings),
typeof(IPlatformBff),
typeof(IClangPlatformBff),
typeof(IPlatformVcxproj),
typeof(Project.Configuration.IConfigurationTasks))]
public sealed partial class LinuxPlatform : BasePlatform, Project.Configuration.IConfigurationTasks, IFastBuildCompilerSettings, IClangPlatformBff
{
#region IPlatformDescriptor implementation
public override string SimplePlatformString => "Linux";
public override string GetToolchainPlatformString(ITarget target) => "x64";
public override bool IsMicrosoftPlatform => false; // No way!
public override bool IsPcPlatform => true;
public override bool IsUsingClang => true; // Maybe now? Traditionally GCC but only the GNU project is backing it now.
public override bool IsLinkerInvokedViaCompiler { get; set; } = false;
public override bool HasDotNetSupport => false; // Technically false with .NET Core and Mono.
public override bool HasSharedLibrarySupport => true;
public override EnvironmentVariableResolver GetPlatformEnvironmentResolver(params VariableAssignment[] parameters)
{
return new EnvironmentVariableResolver(parameters);
}
#endregion
#region Project.Configuration.IConfigurationTasks implementation
// The below method was replaced by GetDefaultOutputFullExtension
// string GetDefaultOutputExtension(OutputType outputType);
public string GetDefaultOutputFullExtension(Project.Configuration.OutputType outputType)
{
switch (outputType)
{
case Project.Configuration.OutputType.Exe:
return ExecutableFileFullExtension;
case Project.Configuration.OutputType.Dll:
return SharedLibraryFileFullExtension;
default:
return StaticLibraryFileFullExtension;
}
}
public string GetOutputFileNamePrefix(Project.Configuration.OutputType outputType)
{
if (outputType != Project.Configuration.OutputType.Exe)
return "lib";
return string.Empty;
}
public IEnumerable<string> GetPlatformLibraryPaths(Project.Configuration conf)
{
if (GlobalSettings.SystemPathProvider != null)
return GlobalSettings.SystemPathProvider.GetSystemLibraryPaths(conf);
return Enumerable.Empty<string>();
}
public void SetupDynamicLibraryPaths(Project.Configuration configuration, DependencySetting dependencySetting, Project.Configuration dependency)
{
// There's no implib on linux platforms, the so does both
if (dependency.Project.SharpmakeProjectType != Project.ProjectTypeAttribute.Export &&
!(configuration.IsFastBuild && !dependency.IsFastBuild))
{
if (dependencySetting.HasFlag(DependencySetting.LibraryPaths))
configuration.AddDependencyBuiltTargetLibraryPath(dependency.TargetPath, dependency.TargetLibraryPathOrderNumber);
if (dependencySetting.HasFlag(DependencySetting.LibraryFiles))
configuration.AddDependencyBuiltTargetLibraryFile(dependency.TargetFileFullNameWithExtension, dependency.TargetFileOrderNumber);
}
else
{
if (dependencySetting.HasFlag(DependencySetting.LibraryPaths))
configuration.DependenciesOtherLibraryPaths.Add(dependency.TargetPath, dependency.TargetLibraryPathOrderNumber);
if (dependencySetting.HasFlag(DependencySetting.LibraryFiles))
configuration.DependenciesOtherLibraryFiles.Add(dependency.TargetFileFullNameWithExtension, dependency.TargetFileOrderNumber);
}
}
public void SetupStaticLibraryPaths(Project.Configuration configuration, DependencySetting dependencySetting, Project.Configuration dependency)
{
DefaultPlatform.SetupLibraryPaths(configuration, dependencySetting, dependency);
}
#endregion
#region IPlatformVcxproj implementation
public override string ProgramDatabaseFileFullExtension => string.Empty;
public override string StaticLibraryFileFullExtension => ".a";
public override string SharedLibraryFileFullExtension => ".so";
public override string StaticOutputLibraryFileFullExtension => string.Empty;
public override string ExecutableFileFullExtension => string.Empty;
// Ideally the object files should be suffixed .o when compiling with FastBuild, using the CompilerOutputExtension property in ObjectLists
public override void SetupPlatformToolsetOptions(IGenerationContext context)
{
context.SelectOption
(
Sharpmake.Options.Option(Options.General.VcPlatformToolset.Default, () => { context.Options["PlatformToolset"] = FileGeneratorUtilities.RemoveLineTag; }),
Sharpmake.Options.Option(Options.General.VcPlatformToolset.Remote_GCC_1_0, () => { context.Options["PlatformToolset"] = "Remote_GCC_1_0"; }),
Sharpmake.Options.Option(Options.General.VcPlatformToolset.Remote_Clang_1_0, () => { context.Options["PlatformToolset"] = "Remote_Clang_1_0"; }),
Sharpmake.Options.Option(Options.General.VcPlatformToolset.WSL_1_0, () => { context.Options["PlatformToolset"] = "WSL_1_0"; }),
Sharpmake.Options.Option(Options.General.VcPlatformToolset.WSL_Clang_1_0, () => { context.Options["PlatformToolset"] = "WSL_Clang_1_0"; }),
Sharpmake.Options.Option(Options.General.VcPlatformToolset.WSL2_1_0, () => { context.Options["PlatformToolset"] = "WSL2_1_0"; })
);
}
public override void SetupPlatformTargetOptions(IGenerationContext context)
{
context.Options["TargetMachine"] = "MachineX64";
context.Options["RandomizedBaseAddress"] = "true";
context.CommandLineOptions["TargetMachine"] = "/MACHINE:X64";
context.CommandLineOptions["RandomizedBaseAddress"] = "/DYNAMICBASE";
context.CommandLineOptions["NasmCompilerFormat"] = "-felf64";
}
public override void SetupSdkOptions(IGenerationContext context)
{
var options = context.Options;
var cmdLineOptions = context.CommandLineOptions;
if (context.Configuration.Output == Project.Configuration.OutputType.Lib)
{
context.Options["ProjectDirectory"] = Util.ConvertToMountedUnixPath(context.Configuration.TargetLibraryPath);
context.Options["RemoteBuildOutputs"] = context.Configuration.TargetFileFullNameWithExtension;
}
else if (context.Configuration.Output != Project.Configuration.OutputType.None)
{
context.Options["ProjectDirectory"] = Util.ConvertToMountedUnixPath(context.Configuration.TargetPath);
context.Options["RemoteBuildOutputs"] = context.Configuration.TargetFileFullNameWithExtension;
}
else
{
context.Options["ProjectDirectory"] = FileGeneratorUtilities.RemoveLineTag;
context.Options["RemoteBuildOutputs"] = FileGeneratorUtilities.RemoveLineTag;
}
context.Options["OutputDirectoryRemote"] = @"$(RemoteProjectDir)" + Util.ConvertToUnixSeparators(Util.EnsureTrailingSeparator(context.Options["OutputDirectory"]));
context.Options["IntermediateDirectoryRemote"] = @"$(RemoteProjectDir)" + Util.ConvertToUnixSeparators(Util.EnsureTrailingSeparator(context.Options["IntermediateDirectory"]));
context.SelectOption
(
Sharpmake.Options.Option(Options.General.CopySources.Enable, () => { context.Options["CopySources"] = "true"; }),
Sharpmake.Options.Option(Options.General.CopySources.Disable, () => { context.Options["CopySources"] = "false"; })
);
context.SelectOption
(
Sharpmake.Options.Option(Options.General.PlatformRemoteTool.Gpp, () => { context.Options["RemoteCppCompileToolExe"] = "g++"; }),
Sharpmake.Options.Option(Options.General.PlatformRemoteTool.Clang, () => { context.Options["RemoteCppCompileToolExe"] = "clang++"; }),
Sharpmake.Options.Option(Options.General.PlatformRemoteTool.Clang38, () => { context.Options["RemoteCppCompileToolExe"] = "clang++-3.8"; })
);
context.SelectOption
(
Sharpmake.Options.Option(Options.General.PlatformRemoteTool.Gpp, () => { context.Options["RemoteCCompileToolExe"] = "g++"; }),
Sharpmake.Options.Option(Options.General.PlatformRemoteTool.Clang, () => { context.Options["RemoteCCompileToolExe"] = "clang"; }),
Sharpmake.Options.Option(Options.General.PlatformRemoteTool.Clang38, () => { context.Options["RemoteCCompileToolExe"] = "clang-3.8"; })
);
context.SelectOption
(
Sharpmake.Options.Option(Options.General.PlatformRemoteTool.Gpp, () => { context.Options["RemoteLdToolExe"] = "g++"; }),
Sharpmake.Options.Option(Options.General.PlatformRemoteTool.Clang, () => { context.Options["RemoteLdToolExe"] = "clang"; }),
Sharpmake.Options.Option(Options.General.PlatformRemoteTool.Clang38, () => { context.Options["RemoteLdToolExe"] = "clang-3.8"; })
);
context.SelectOption(
Sharpmake.Options.Option(Options.General.StdLib.Default, () => { cmdLineOptions["StdLib"] = FileGeneratorUtilities.RemoveLineTag; }),
Sharpmake.Options.Option(Options.General.StdLib.LibCpp, () => { cmdLineOptions["StdLib"] = "--stdlib=libc++"; }),
Sharpmake.Options.Option(Options.General.StdLib.LibStdCpp, () => { cmdLineOptions["StdLib"] = "--stdlib=libstdc++"; }),
Sharpmake.Options.Option(Options.General.StdLib.Platform, () => { cmdLineOptions["StdLib"] = "--stdlib=platform"; })
);
// FastBuild only atm
string sysRoot = Sharpmake.Options.PathOption.Get<Options.General.SysRoot>(context.Configuration, rootpath: context.ProjectDirectoryCapitalized);
string bffSysRoot = Bff.CurrentBffPathKeyCombine(sysRoot);
context.CommandLineOptions["BffSysRoot"] = $" --sysroot=\"{bffSysRoot}\"";
}
public override void SelectCompilerOptions(IGenerationContext context)
{
var options = context.Options;
var cmdLineOptions = context.CommandLineOptions;
var conf = context.Configuration;
context.SelectOption(
Sharpmake.Options.Option(Options.Compiler.DebugInformationFormat.None, () => { options["DebugInformationFormat"] = "None"; cmdLineOptions["DebugInformationFormat"] = "-g0"; }),
Sharpmake.Options.Option(Options.Compiler.DebugInformationFormat.MinimalDebugInformation, () => { options["DebugInformationFormat"] = "Minimal"; cmdLineOptions["DebugInformationFormat"] = "-g"; }),
Sharpmake.Options.Option(Options.Compiler.DebugInformationFormat.FullDebugInformation, () => { options["DebugInformationFormat"] = "FullDebug"; cmdLineOptions["DebugInformationFormat"] = "-g2 -gdwarf-2"; })
);
context.SelectOption
(
Sharpmake.Options.Option(Options.Compiler.Warnings.NormalWarnings, () => { options["Warnings"] = "NormalWarnings"; cmdLineOptions["Warnings"] = FileGeneratorUtilities.RemoveLineTag; }),
Sharpmake.Options.Option(Options.Compiler.Warnings.MoreWarnings, () => { options["Warnings"] = "MoreWarnings"; cmdLineOptions["Warnings"] = "-Wall"; }),
Sharpmake.Options.Option(Options.Compiler.Warnings.Disable, () => { options["Warnings"] = "WarningsOff"; cmdLineOptions["Warnings"] = "-w"; })
);
context.SelectOption
(
Sharpmake.Options.Option(Options.Compiler.ExtraWarnings.Enable, () => { options["ExtraWarnings"] = "true"; cmdLineOptions["ExtraWarnings"] = "-Wextra"; }),
Sharpmake.Options.Option(Options.Compiler.ExtraWarnings.Disable, () => { options["ExtraWarnings"] = "false"; cmdLineOptions["ExtraWarnings"] = FileGeneratorUtilities.RemoveLineTag; })
);
context.SelectOption
(
Sharpmake.Options.Option(Sharpmake.Options.Vc.General.TreatWarningsAsErrors.Enable, () => { options["WarningsAsErrors"] = "true"; cmdLineOptions["WarningsAsErrors"] = "-Werror"; }),
Sharpmake.Options.Option(Sharpmake.Options.Vc.General.TreatWarningsAsErrors.Disable, () => { options["WarningsAsErrors"] = "false"; cmdLineOptions["WarningsAsErrors"] = FileGeneratorUtilities.RemoveLineTag; })
);
context.SelectOption
(
Sharpmake.Options.Option(Options.Compiler.InlineFunctionDebugInformation.Enable, () => { options["InlineFunctionDebugInformation"] = "true"; if (conf.IsFastBuild) throw new NotImplementedException("FIXME!"); }),
Sharpmake.Options.Option(Options.Compiler.InlineFunctionDebugInformation.Disable, () => { options["InlineFunctionDebugInformation"] = FileGeneratorUtilities.RemoveLineTag; })
);
Options.Compiler.ProcessorNumber processorNumber = Sharpmake.Options.GetObject<Options.Compiler.ProcessorNumber>(conf);
if (processorNumber == null)
options["ProcessorNumber"] = FileGeneratorUtilities.RemoveLineTag;
else
options["ProcessorNumber"] = processorNumber.Value.ToString();
string linkerOptionPrefix = conf.Platform.GetLinkerOptionPrefix();
context.SelectOption
(
Sharpmake.Options.Option(Options.Compiler.Distributable.Enable, () => { options["Distributable"] = "true"; }),
Sharpmake.Options.Option(Options.Compiler.Distributable.Disable, () => { options["Distributable"] = "false"; })
);
context.SelectOption
(
Sharpmake.Options.Option(Options.Compiler.OptimizationLevel.Disable, () => { options["OptimizationLevel"] = "Level0"; cmdLineOptions["OptimizationLevel"] = "-O0"; }),
Sharpmake.Options.Option(Options.Compiler.OptimizationLevel.Standard, () => { options["OptimizationLevel"] = "Level1"; cmdLineOptions["OptimizationLevel"] = "-O1"; }),
Sharpmake.Options.Option(Options.Compiler.OptimizationLevel.Full, () => { options["OptimizationLevel"] = "Level2"; cmdLineOptions["OptimizationLevel"] = "-O2"; }),
Sharpmake.Options.Option(Options.Compiler.OptimizationLevel.FullWithInlining, () => { options["OptimizationLevel"] = "Level3"; cmdLineOptions["OptimizationLevel"] = "-O3"; }),
Sharpmake.Options.Option(Options.Compiler.OptimizationLevel.ForSize, () => { options["OptimizationLevel"] = "Levels"; cmdLineOptions["OptimizationLevel"] = "-Os"; })
);
context.SelectOption
(
Sharpmake.Options.Option(Options.Compiler.PositionIndependentCode.Disable, () => { options["PositionIndependentCode"] = "false"; cmdLineOptions["PositionIndependentCode"] = FileGeneratorUtilities.RemoveLineTag; }),
Sharpmake.Options.Option(Options.Compiler.PositionIndependentCode.Enable, () => { options["PositionIndependentCode"] = "true"; cmdLineOptions["PositionIndependentCode"] = "-fPIC"; })
);
context.SelectOption
(
Sharpmake.Options.Option(Options.Compiler.FastMath.Enable, () => { options["FastMath"] = "true"; cmdLineOptions["FastMath"] = "-ffast-math"; }),
Sharpmake.Options.Option(Options.Compiler.FastMath.Disable, () => { options["FastMath"] = "false"; cmdLineOptions["FastMath"] = FileGeneratorUtilities.RemoveLineTag; })
);
context.SelectOption
(
Sharpmake.Options.Option(Options.Compiler.NoStrictAliasing.Enable, () => { options["NoStrictAliasing"] = "true"; cmdLineOptions["NoStrictAliasing"] = "-fno-strict-aliasing"; }),
Sharpmake.Options.Option(Options.Compiler.NoStrictAliasing.Disable, () => { options["NoStrictAliasing"] = "false"; cmdLineOptions["NoStrictAliasing"] = FileGeneratorUtilities.RemoveLineTag; })
);
context.SelectOption
(
Sharpmake.Options.Option(Options.Compiler.UnrollLoops.Enable, () => { options["UnrollLoops"] = "true"; cmdLineOptions["UnrollLoops"] = "-funroll-loops"; }),
Sharpmake.Options.Option(Options.Compiler.UnrollLoops.Disable, () => { options["UnrollLoops"] = "false"; cmdLineOptions["UnrollLoops"] = FileGeneratorUtilities.RemoveLineTag; })
);
context.SelectOption
(
Sharpmake.Options.Option(Options.Compiler.LinkTimeOptimization.Enable, () => { options["LinkTimeOptimization"] = "true"; cmdLineOptions["LinkTimeOptimization"] = "-flto"; }),
Sharpmake.Options.Option(Options.Compiler.LinkTimeOptimization.Disable, () => { options["LinkTimeOptimization"] = "false"; cmdLineOptions["LinkTimeOptimization"] = FileGeneratorUtilities.RemoveLineTag; })
);
context.SelectOption
(
Sharpmake.Options.Option(Options.Compiler.CheckAnsiCompliance.Enable, () => { options["AnsiCompliance"] = "true"; cmdLineOptions["AnsiCompliance"] = "-ansi"; }),
Sharpmake.Options.Option(Options.Compiler.CheckAnsiCompliance.Disable, () => { options["AnsiCompliance"] = "false"; cmdLineOptions["AnsiCompliance"] = FileGeneratorUtilities.RemoveLineTag; })
);
context.SelectOption
(
Sharpmake.Options.Option(Options.Compiler.DefaultCharUnsigned.Enable, () => { options["CharUnsigned"] = "true"; cmdLineOptions["CharUnsigned"] = "-funsigned-char"; }),
Sharpmake.Options.Option(Options.Compiler.DefaultCharUnsigned.Disable, () => { options["CharUnsigned"] = "false"; cmdLineOptions["CharUnsigned"] = FileGeneratorUtilities.RemoveLineTag; })
);
context.SelectOption
(
Sharpmake.Options.Option(Options.Compiler.MsExtensions.Enable, () => { options["MsExtensions"] = "true"; cmdLineOptions["MsExtensions"] = "-fms-extensions"; }),
Sharpmake.Options.Option(Options.Compiler.MsExtensions.Disable, () => { options["MsExtensions"] = "false"; cmdLineOptions["MsExtensions"] = FileGeneratorUtilities.RemoveLineTag; })
);
context.SelectOption
(
Sharpmake.Options.Option(Sharpmake.Options.Vc.Compiler.RTTI.Enable, () => { options["RuntimeTypeInfo"] = "true"; cmdLineOptions["RuntimeTypeInfo"] = "-frtti"; }),
Sharpmake.Options.Option(Sharpmake.Options.Vc.Compiler.RTTI.Disable, () => { options["RuntimeTypeInfo"] = FileGeneratorUtilities.RemoveLineTag; cmdLineOptions["RuntimeTypeInfo"] = "-fno-rtti"; })
);
context.SelectOption
(
Sharpmake.Options.Option(Options.Linker.EditAndContinue.Enable, () => { options["EditAndContinue"] = "true"; cmdLineOptions["EditAndContinue"] = $"{linkerOptionPrefix}--enc"; }),
Sharpmake.Options.Option(Options.Linker.EditAndContinue.Disable, () => { options["EditAndContinue"] = "false"; cmdLineOptions["EditAndContinue"] = FileGeneratorUtilities.RemoveLineTag; })
);
context.SelectOption
(
Sharpmake.Options.Option(Options.Linker.InfoStripping.None, () => { options["InfoStripping"] = "None"; cmdLineOptions["InfoStripping"] = FileGeneratorUtilities.RemoveLineTag; }),
Sharpmake.Options.Option(Options.Linker.InfoStripping.StripDebug, () => { options["InfoStripping"] = "StripDebug"; cmdLineOptions["InfoStripping"] = $"{linkerOptionPrefix}-S"; }),
Sharpmake.Options.Option(Options.Linker.InfoStripping.StripSymsAndDebug, () => { options["InfoStripping"] = "StripSymsAndDebug"; cmdLineOptions["InfoStripping"] = $"{linkerOptionPrefix}-s"; })
);
context.SelectOption
(
Sharpmake.Options.Option(Options.Linker.DataStripping.None, () => { options["DataStripping"] = "None"; cmdLineOptions["DataStripping"] = FileGeneratorUtilities.RemoveLineTag; }),
Sharpmake.Options.Option(Options.Linker.DataStripping.StripFuncs, () => { options["DataStripping"] = "StripFuncs"; cmdLineOptions["DataStripping"] = FileGeneratorUtilities.RemoveLineTag; }),
Sharpmake.Options.Option(Options.Linker.DataStripping.StripFuncsAndData, () => { options["DataStripping"] = "StripFuncsAndData"; cmdLineOptions["DataStripping"] = FileGeneratorUtilities.RemoveLineTag; })
);
context.SelectOption
(
Sharpmake.Options.Option(Options.Linker.DuplicateStripping.Enable, () => { options["DuplicateStripping"] = "true"; cmdLineOptions["DuplicateStripping"] = "-strip-duplicates"; }),
Sharpmake.Options.Option(Options.Linker.DuplicateStripping.Disable, () => { options["DuplicateStripping"] = "false"; cmdLineOptions["DuplicateStripping"] = FileGeneratorUtilities.RemoveLineTag; })
);
context.SelectOption
(
Sharpmake.Options.Option(Options.Linker.Addressing.ASLR, () => { options["Addressing"] = "ASLR"; cmdLineOptions["Addressing"] = FileGeneratorUtilities.RemoveLineTag; }),
Sharpmake.Options.Option(Options.Linker.Addressing.NonASLR, () => { options["Addressing"] = "NonASLR"; cmdLineOptions["Addressing"] = FileGeneratorUtilities.RemoveLineTag; })
);
context.SelectOption
(
Sharpmake.Options.Option(Options.Linker.UseThinArchives.Enable, () => { options["UseThinArchives"] = "true"; cmdLineOptions["UseThinArchives"] = "T"; }),
Sharpmake.Options.Option(Options.Linker.UseThinArchives.Disable, () => { options["UseThinArchives"] = "false"; cmdLineOptions["UseThinArchives"] = ""; })
);
context.SelectOption
(
Sharpmake.Options.Option(Options.Linker.WholeArchive.Enable, () => { options["WholeArchive"] = "true"; cmdLineOptions["WholeArchiveBegin"] = "--whole-archive"; cmdLineOptions["WholeArchiveEnd"] = "--no-whole-archive"; }),
Sharpmake.Options.Option(Options.Linker.WholeArchive.Disable, () => { options["WholeArchive"] = "false"; cmdLineOptions["WholeArchiveBegin"] = FileGeneratorUtilities.RemoveLineTag; cmdLineOptions["WholeArchiveEnd"] = FileGeneratorUtilities.RemoveLineTag; })
);
}
public override void SelectPlatformAdditionalDependenciesOptions(IGenerationContext context)
{
// the libs must be prefixed with -l: in the additional dependencies field in VS
var additionalDependencies = context.Options["AdditionalDependencies"].Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
context.Options["AdditionalDependencies"] = string.Join(";", additionalDependencies.Select(d => "-l:" + d));
}
public override void GenerateProjectCompileVcxproj(IVcxprojGenerationContext context, IFileGenerator generator)
{
generator.Write(_projectConfigurationsCompileTemplate);
}
public override void GeneratePlatformSpecificProjectDescription(IVcxprojGenerationContext context, IFileGenerator generator)
{
var linuxConfigurations = context.ProjectConfigurations.Where(c => c.Platform == Platform.linux);
string configurationsConditional = string.Join(" or ",
linuxConfigurations.Select(c => $"'$(Configuration)'=='{c.Name}'")
);
using (generator.Declare("platformName", GetToolchainPlatformString(null)))
using (generator.Declare("configurationsConditional", configurationsConditional))
using (generator.Declare("applicationType", "Linux"))
using (generator.Declare("applicationTypeRevision", "1.0"))
using (generator.Declare("targetLinuxPlatform", "Generic"))
{
generator.Write(_projectStartPlatformConditional);
generator.Write(_projectDescriptionPlatformSpecific);
generator.Write(Vcxproj.Template.Project.PropertyGroupEnd);
}
}
public override void GenerateUserConfigurationFile(Project.Configuration conf, IFileGenerator generator)
{
generator.Write(_userFileConfigurationGeneralTemplate);
}
public override void GenerateProjectConfigurationGeneral2(IVcxprojGenerationContext context, IFileGenerator generator)
{
generator.Write(_projectConfigurationsGeneral2);
}
public override void GenerateProjectConfigurationFastBuildMakeFile(IVcxprojGenerationContext context, IFileGenerator generator)
{
base.GenerateProjectConfigurationFastBuildMakeFile(context, generator);
generator.Write(_projectConfigurationsFastBuildMakefile);
}
public override void SetupPlatformLibraryOptions(out string platformLibExtension, out string platformOutputLibExtension, out string platformPrefixExtension, out string platformLibPrefix)
{
platformLibExtension = ".a";
platformOutputLibExtension = ".a";
platformPrefixExtension = "-l:";
platformLibPrefix = "lib";
}
protected override string GetProjectLinkSharedVcxprojTemplate()
{
return _projectConfigurationsLinkTemplate;
}
protected override string GetProjectStaticLinkVcxprojTemplate()
{
return _projectConfigurationsStaticLinkTemplate;
}
protected override IEnumerable<IncludeWithPrefix> GetPlatformIncludePathsWithPrefixImpl(IGenerationContext context)
{
if (!context.Configuration.IsFastBuild || GlobalSettings.SystemPathProvider == null)
yield break;
foreach (string systemIncludePath in GlobalSettings.SystemPathProvider.GetSystemIncludePaths(context.Configuration))
yield return new IncludeWithPrefix("-isystem", systemIncludePath);
}
#endregion
#region IFastBuildCompilerSettings implementation
public IDictionary<DevEnv, string> BinPath { get; set; } = new Dictionary<DevEnv, string>();
public IDictionary<IFastBuildCompilerKey, CompilerFamily> CompilerFamily { get; set; } = new Dictionary<IFastBuildCompilerKey, CompilerFamily>();
public IDictionary<DevEnv, string> LinkerPath { get; set; } = new Dictionary<DevEnv, string>();
public IDictionary<DevEnv, string> LinkerExe { get; set; } = new Dictionary<DevEnv, string>();
public IDictionary<DevEnv, bool> LinkerInvokedViaCompiler { get; set; } = new Dictionary<DevEnv, bool>();
public IDictionary<DevEnv, string> LibrarianExe { get; set; } = new Dictionary<DevEnv, string>();
public IDictionary<DevEnv, Strings> ExtraFiles { get; set; } = new Dictionary<DevEnv, Strings>();
#endregion
#region IClangPlatformBff implementation
public override string BffPlatformDefine => "_LINUX";
public override string CConfigName(Configuration conf)
{
return ".linuxConfig";
}
public override string CppConfigName(Configuration conf)
{
return ".linuxppConfig";
}
public void SetupClangOptions(IFileGenerator generator)
{
generator.Write(_compilerExtraOptions);
generator.Write(_compilerOptimizationOptions);
}
public override void SetupExtraLinkerSettings(IFileGenerator fileGenerator, Project.Configuration configuration, string fastBuildOutputFile)
{
string sharedOption = string.Empty;
if (configuration.Output == Project.Configuration.OutputType.Dll)
sharedOption = " -shared";
using (fileGenerator.Resolver.NewScopedParameter("sharedOption", sharedOption))
{
fileGenerator.Write(_linkerOptionsTemplate);
}
}
public override IEnumerable<Project.Configuration.BuildStepExecutable> GetExtraStampEvents(Project.Configuration configuration, string fastBuildOutputFile)
{
if (FastBuildSettings.FastBuildSupportLinkerStampList)
{
foreach (var step in GetStripDebugSymbolsSteps(configuration, asStampSteps: true))
yield return step;
}
}
public override IEnumerable<Project.Configuration.BuildStepBase> GetExtraPostBuildEvents(Project.Configuration configuration, string fastBuildOutputFile)
{
if (!FastBuildSettings.FastBuildSupportLinkerStampList)
{
foreach (var step in GetStripDebugSymbolsSteps(configuration, asStampSteps: false))
yield return step;
}
}
/// <summary>
/// Get the list of steps (if any), to strip the exe/dll from debug symbols for FastBuild
/// </summary>
/// <param name="configuration">The configuration</param>
/// <param name="asStampSteps">Indicates if those steps are post build or stamp, the latter being more efficient</param>
/// <returns>The list of steps</returns>
private IEnumerable<Project.Configuration.BuildStepExecutable> GetStripDebugSymbolsSteps(Project.Configuration configuration, bool asStampSteps)
{
if (configuration.Output == Project.Configuration.OutputType.Exe || configuration.Output == Project.Configuration.OutputType.Dll)
{
var stripDebugSymbols = Sharpmake.Options.GetObject<Options.Linker.ShouldStripDebugSymbols>(configuration);
if (stripDebugSymbols == Options.Linker.ShouldStripDebugSymbols.Enable)
{
if (!configuration.IsFastBuild)
throw new NotImplementedException("ShouldStripDebugSymbols.Enable is only supported when using FastBuild");
var fastBuildSettings = PlatformRegistry.Get<IFastBuildCompilerSettings>(Platform.linux);
var devEnv = configuration.Target.GetFragment<DevEnv>();
string binPath;
if (!fastBuildSettings.BinPath.TryGetValue(devEnv, out binPath))
binPath = ClangForWindows.GetWindowsClangExecutablePath();
string fileFullname = configuration.TargetFileFullNameWithExtension;
string targetFileFullPath = @"[conf.TargetPath]\" + fileFullname;
string targetDebugFileFullPath = targetFileFullPath + ".debug";
string objCopySentinelFile = @"[conf.IntermediatePath]\" + fileFullname + ".extracted";
yield return new Project.Configuration.BuildStepExecutable(
Path.Combine(binPath, GlobalSettings.UseLlvmObjCopy ? "llvm-objcopy.exe" : "objcopy.exe"),
asStampSteps ? string.Empty : targetFileFullPath,
asStampSteps ? string.Empty : objCopySentinelFile,
string.Join(" ",
"--only-keep-debug",
targetFileFullPath,
targetDebugFileFullPath
),
useStdOutAsOutput: true
);
string strippedSentinelFile = @"[conf.IntermediatePath]\" + fileFullname + ".stripped";
yield return new Project.Configuration.BuildStepExecutable(
Path.Combine(binPath, GlobalSettings.UseLlvmObjCopy ? "llvm-objcopy.exe" : "strip.exe"),
asStampSteps ? string.Empty : objCopySentinelFile,
asStampSteps ? string.Empty : strippedSentinelFile,
string.Join(" ",
"--strip-debug",
"--strip-unneeded",
targetFileFullPath
),
useStdOutAsOutput: true
);
string linkedSentinelFile = @"[conf.IntermediatePath]\" + fileFullname + ".linked";
yield return new Project.Configuration.BuildStepExecutable(
Path.Combine(binPath, GlobalSettings.UseLlvmObjCopy ? "llvm-objcopy.exe" : "objcopy.exe"),
asStampSteps ? string.Empty : strippedSentinelFile,
asStampSteps ? string.Empty : linkedSentinelFile,
string.Join(" ",
$@"--add-gnu-debuglink=""{targetDebugFileFullPath}""",
targetFileFullPath
),
useStdOutAsOutput: true
);
}
}
}
public override void AddCompilerSettings(IDictionary<string, CompilerSettings> masterCompilerSettings, Project.Configuration conf)
{
var devEnv = conf.Target.GetFragment<DevEnv>();
var platform = conf.Target.GetFragment<Platform>();
string compilerName = $"Compiler-{Util.GetToolchainPlatformString(platform, conf.Target)}-{devEnv}";
string CCompilerSettingsName = "C-" + compilerName + "-" + "Linux";
string CompilerSettingsName = compilerName + "-" + "Linux";
var projectRootPath = conf.Project.RootPath;
CompilerSettings compilerSettings = GetMasterCompilerSettings(masterCompilerSettings, CompilerSettingsName, devEnv, projectRootPath, false);
compilerSettings.PlatformFlags |= Platform.linux;
CompilerSettings CcompilerSettings = GetMasterCompilerSettings(masterCompilerSettings, CCompilerSettingsName, devEnv, projectRootPath, true);
CcompilerSettings.PlatformFlags |= Platform.linux;
SetConfiguration(compilerSettings, CompilerSettingsName, projectRootPath, devEnv, false);
SetConfiguration(CcompilerSettings, CCompilerSettingsName, projectRootPath, devEnv, true);
}
private CompilerSettings GetMasterCompilerSettings(IDictionary<string, CompilerSettings> masterCompilerSettings, string compilerName, DevEnv devEnv, string projectRootPath, bool useCCompiler)
{
CompilerSettings compilerSettings;
if (masterCompilerSettings.ContainsKey(compilerName))
{
compilerSettings = masterCompilerSettings[compilerName];
}
else
{
var fastBuildSettings = PlatformRegistry.Get<IFastBuildCompilerSettings>(Platform.linux);
string binPath;
if (!fastBuildSettings.BinPath.TryGetValue(devEnv, out binPath))
binPath = ClangForWindows.GetWindowsClangExecutablePath();
string pathToCompiler = Util.GetCapitalizedPath(Util.PathGetAbsolute(projectRootPath, binPath));
Strings extraFiles = new Strings();
{
Strings userExtraFiles;
if (fastBuildSettings.ExtraFiles.TryGetValue(devEnv, out userExtraFiles))
extraFiles.AddRange(userExtraFiles);
}
var compilerFamilyKey = new FastBuildCompilerKey(devEnv);
CompilerFamily compilerFamily;
if (!fastBuildSettings.CompilerFamily.TryGetValue(compilerFamilyKey, out compilerFamily))
compilerFamily = Sharpmake.CompilerFamily.Clang;
string executable = useCCompiler ? @"$ExecutableRootPath$\clang.exe" : @"$ExecutableRootPath$\clang++.exe";
compilerSettings = new CompilerSettings(compilerName, compilerFamily, Platform.linux, extraFiles, executable, pathToCompiler, devEnv, new Dictionary<string, CompilerSettings.Configuration>());
masterCompilerSettings.Add(compilerName, compilerSettings);
}
return compilerSettings;
}
private void SetConfiguration(CompilerSettings compilerSettings, string compilerName, string projectRootPath, DevEnv devEnv, bool useCCompiler)
{
string configName = useCCompiler ? ".linuxConfig" : ".linuxppConfig";
IDictionary<string, CompilerSettings.Configuration> configurations = compilerSettings.Configurations;
if (!configurations.ContainsKey(configName))
{
var fastBuildSettings = PlatformRegistry.Get<IFastBuildCompilerSettings>(Platform.linux);
string binPath = compilerSettings.RootPath;
string linkerPath;
if (!fastBuildSettings.LinkerPath.TryGetValue(devEnv, out linkerPath))
linkerPath = binPath;
string linkerExe;
if (!fastBuildSettings.LinkerExe.TryGetValue(devEnv, out linkerExe))
linkerExe = "ld.lld.exe";
bool isLinkerInvokedViaCompiler;
if (fastBuildSettings.LinkerInvokedViaCompiler.TryGetValue(devEnv, out isLinkerInvokedViaCompiler))
IsLinkerInvokedViaCompiler = isLinkerInvokedViaCompiler;
string librarianExe;
if (!fastBuildSettings.LibrarianExe.TryGetValue(devEnv, out librarianExe))
librarianExe = "llvm-ar.exe";
configurations.Add(configName,
new CompilerSettings.Configuration(
Platform.linux,
compiler: compilerName,
binPath: binPath,
linkerPath: Util.GetCapitalizedPath(Util.PathGetAbsolute(projectRootPath, linkerPath)),
librarian: @"$LinkerPath$\" + librarianExe,
linker: @"$LinkerPath$\" + linkerExe,
fastBuildLinkerType: CompilerSettings.LinkerType.GCC // Workaround: set GCC linker type since it will only enable response files
)
);
}
}
#endregion
}
}
}