1177 lines
50 KiB
C#
1177 lines
50 KiB
C#
// Copyright (c) Wojciech Figat. All rights reserved.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
using System.Xml;
|
|
using Flax.Build.Graph;
|
|
using Flax.Build.NativeCpp;
|
|
using Flax.Build.Projects.VisualStudio;
|
|
|
|
// ReSharper disable InconsistentNaming
|
|
|
|
namespace Flax.Build.Platforms
|
|
{
|
|
/// <summary>
|
|
/// The Microsoft Windows base toolchain implementation.
|
|
/// </summary>
|
|
/// <seealso cref="Toolchain" />
|
|
public abstract class WindowsToolchainBase : Toolchain
|
|
{
|
|
/// <summary>
|
|
/// The VC tools root path.
|
|
/// </summary>
|
|
protected readonly string _vcToolPath;
|
|
|
|
/// <summary>
|
|
/// The compiler path.
|
|
/// </summary>
|
|
protected readonly string _compilerPath;
|
|
|
|
/// <summary>
|
|
/// The resource compiler path.
|
|
/// </summary>
|
|
protected readonly string _resourceCompilerPath;
|
|
|
|
/// <summary>
|
|
/// The linker path.
|
|
/// </summary>
|
|
protected readonly string _linkerPath;
|
|
|
|
/// <summary>
|
|
/// The library tool path.
|
|
/// </summary>
|
|
protected readonly string _libToolPath;
|
|
|
|
/// <summary>
|
|
/// The xdcmake tool path.
|
|
/// </summary>
|
|
protected readonly string _xdcmakePath;
|
|
|
|
/// <summary>
|
|
/// The makepri tool path.
|
|
/// </summary>
|
|
protected readonly string _makepriPath;
|
|
|
|
/// <summary>
|
|
/// Gets the platform toolset.
|
|
/// </summary>
|
|
public WindowsPlatformToolset Toolset { get; }
|
|
|
|
/// <summary>
|
|
/// Gets the target platform SDK.
|
|
/// </summary>
|
|
public WindowsPlatformSDK SDK { get; }
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="WindowsToolchainBase"/> class.
|
|
/// </summary>
|
|
/// <param name="platform">The platform.</param>
|
|
/// <param name="architecture">The target architecture.</param>
|
|
/// <param name="toolsetVer">The target platform toolset version.</param>
|
|
/// <param name="sdkVer">The target platform SDK version.</param>
|
|
protected WindowsToolchainBase(WindowsPlatformBase platform, TargetArchitecture architecture, WindowsPlatformToolset toolsetVer, WindowsPlatformSDK sdkVer)
|
|
: base(platform, architecture)
|
|
{
|
|
var toolsets = WindowsPlatformBase.GetToolsets();
|
|
var sdks = WindowsPlatformBase.GetSDKs();
|
|
|
|
// Pick the overriden toolset
|
|
if (Configuration.Compiler != null)
|
|
{
|
|
if (Enum.TryParse(Configuration.Compiler, out WindowsPlatformToolset compiler))
|
|
toolsetVer = compiler;
|
|
}
|
|
|
|
// Pick the newest installed Visual Studio version if using the default toolset
|
|
if (toolsetVer == WindowsPlatformToolset.Default)
|
|
{
|
|
if (VisualStudioInstance.HasIDE(VisualStudioVersion.VisualStudio2022))
|
|
{
|
|
if (toolsets.Keys.Contains(WindowsPlatformToolset.v144))
|
|
{
|
|
toolsetVer = WindowsPlatformToolset.v144;
|
|
}
|
|
else
|
|
{
|
|
toolsetVer = WindowsPlatformToolset.v143;
|
|
}
|
|
}
|
|
else if (VisualStudioInstance.HasIDE(VisualStudioVersion.VisualStudio2019))
|
|
{
|
|
toolsetVer = WindowsPlatformToolset.v142;
|
|
}
|
|
else if (VisualStudioInstance.HasIDE(VisualStudioVersion.VisualStudio2017))
|
|
{
|
|
toolsetVer = WindowsPlatformToolset.v141;
|
|
}
|
|
else
|
|
{
|
|
toolsetVer = WindowsPlatformToolset.v140;
|
|
}
|
|
}
|
|
// Pick the latest toolset
|
|
else if (toolsetVer == WindowsPlatformToolset.Latest)
|
|
{
|
|
toolsetVer = toolsets.Keys.Max();
|
|
}
|
|
|
|
// Pick the latest SDK
|
|
if (sdkVer == WindowsPlatformSDK.Latest)
|
|
{
|
|
sdkVer = sdks.Keys.Max();
|
|
}
|
|
|
|
// Get tools
|
|
Toolset = toolsetVer;
|
|
SDK = sdkVer;
|
|
if (!toolsets.ContainsKey(Toolset))
|
|
throw new Exception(string.Format("Missing toolset {0} for platform Windows", Toolset));
|
|
if (!sdks.ContainsKey(SDK))
|
|
throw new Exception(string.Format("Missing SDK {0} for platform Windows", SDK));
|
|
|
|
// Get the tools paths
|
|
var hostArchitecture = Platform.BuildTargetArchitecture;
|
|
_vcToolPath = WindowsPlatformBase.GetVCToolPath(Toolset, hostArchitecture, Architecture);
|
|
if (string.IsNullOrEmpty(_vcToolPath))
|
|
throw new Exception(string.Format("No {0} host compiler tools found for target architecture {1}", hostArchitecture, Architecture));
|
|
_compilerPath = Path.Combine(_vcToolPath, "cl.exe");
|
|
_linkerPath = Path.Combine(_vcToolPath, "link.exe");
|
|
_libToolPath = Path.Combine(_vcToolPath, "lib.exe");
|
|
_xdcmakePath = Path.Combine(_vcToolPath, "xdcmake.exe");
|
|
|
|
// Add Visual C++ toolset include and library paths
|
|
var vcToolChainDir = toolsets[Toolset];
|
|
SystemIncludePaths.Add(Path.Combine(vcToolChainDir, "include"));
|
|
switch (Toolset)
|
|
{
|
|
case WindowsPlatformToolset.v140:
|
|
{
|
|
switch (Architecture)
|
|
{
|
|
case TargetArchitecture.AnyCPU: break;
|
|
case TargetArchitecture.ARM:
|
|
SystemLibraryPaths.Add(Path.Combine(vcToolChainDir, "lib", "arm"));
|
|
break;
|
|
case TargetArchitecture.ARM64:
|
|
SystemLibraryPaths.Add(Path.Combine(vcToolChainDir, "lib", "arm64"));
|
|
break;
|
|
case TargetArchitecture.x86:
|
|
SystemLibraryPaths.Add(Path.Combine(vcToolChainDir, "lib"));
|
|
break;
|
|
case TargetArchitecture.x64:
|
|
SystemLibraryPaths.Add(Path.Combine(vcToolChainDir, "lib", "amd64"));
|
|
break;
|
|
default: throw new InvalidArchitectureException(Architecture);
|
|
}
|
|
|
|
// When using Visual Studio 2015 toolset and using pre-Windows 10 SDK, find a Windows 10 SDK and add the UCRT include paths
|
|
if (SDK == WindowsPlatformSDK.v8_1)
|
|
{
|
|
var sdk = sdks.FirstOrDefault(x => x.Key != WindowsPlatformSDK.v8_1);
|
|
if (sdk.Value == null)
|
|
{
|
|
throw new Exception("Combination of Windows Toolset v140 and Windows SDK 8.1 requires the Universal CRT to be installed.");
|
|
}
|
|
|
|
var sdkVersionName = WindowsPlatformBase.GetSDKVersion(sdk.Key).ToString();
|
|
string includeRootDir = Path.Combine(sdk.Value, "include", sdkVersionName);
|
|
SystemIncludePaths.Add(Path.Combine(includeRootDir, "ucrt"));
|
|
|
|
string libraryRootDir = Path.Combine(sdk.Value, "lib", sdkVersionName);
|
|
switch (Architecture)
|
|
{
|
|
case TargetArchitecture.AnyCPU: break;
|
|
case TargetArchitecture.ARM:
|
|
SystemLibraryPaths.Add(Path.Combine(libraryRootDir, "ucrt", "arm"));
|
|
break;
|
|
case TargetArchitecture.ARM64:
|
|
SystemLibraryPaths.Add(Path.Combine(libraryRootDir, "ucrt", "arm64"));
|
|
break;
|
|
case TargetArchitecture.x86:
|
|
SystemLibraryPaths.Add(Path.Combine(libraryRootDir, "ucrt", "x86"));
|
|
break;
|
|
case TargetArchitecture.x64:
|
|
SystemLibraryPaths.Add(Path.Combine(libraryRootDir, "ucrt", "x64"));
|
|
break;
|
|
default: throw new InvalidArchitectureException(Architecture);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case WindowsPlatformToolset.v141:
|
|
case WindowsPlatformToolset.v142:
|
|
case WindowsPlatformToolset.v143:
|
|
case WindowsPlatformToolset.v144:
|
|
{
|
|
switch (Architecture)
|
|
{
|
|
case TargetArchitecture.AnyCPU: break;
|
|
case TargetArchitecture.ARM:
|
|
SystemLibraryPaths.Add(Path.Combine(vcToolChainDir, "lib", "arm"));
|
|
break;
|
|
case TargetArchitecture.ARM64:
|
|
SystemLibraryPaths.Add(Path.Combine(vcToolChainDir, "lib", "arm64"));
|
|
break;
|
|
case TargetArchitecture.x86:
|
|
SystemLibraryPaths.Add(Path.Combine(vcToolChainDir, "lib", "x86"));
|
|
break;
|
|
case TargetArchitecture.x64:
|
|
SystemLibraryPaths.Add(Path.Combine(vcToolChainDir, "lib", "x64"));
|
|
break;
|
|
default: throw new InvalidArchitectureException(Architecture);
|
|
}
|
|
break;
|
|
}
|
|
default: throw new ArgumentOutOfRangeException();
|
|
}
|
|
|
|
// Add Windows SDK include and library paths
|
|
var windowsSdkDir = sdks[SDK];
|
|
switch (SDK)
|
|
{
|
|
case WindowsPlatformSDK.v8_1:
|
|
{
|
|
string includeRootDir = Path.Combine(windowsSdkDir, "include");
|
|
SystemIncludePaths.Add(Path.Combine(includeRootDir, "shared"));
|
|
SystemIncludePaths.Add(Path.Combine(includeRootDir, "um"));
|
|
SystemIncludePaths.Add(Path.Combine(includeRootDir, "winrt"));
|
|
SystemIncludePaths.Add(Path.Combine(includeRootDir, "ucrt"));
|
|
|
|
string libraryRootDir = Path.Combine(windowsSdkDir, "lib", "winv6.3");
|
|
switch (Architecture)
|
|
{
|
|
case TargetArchitecture.AnyCPU: break;
|
|
case TargetArchitecture.ARM:
|
|
{
|
|
SystemLibraryPaths.Add(Path.Combine(libraryRootDir, "um", "arm"));
|
|
break;
|
|
}
|
|
case TargetArchitecture.ARM64:
|
|
{
|
|
SystemLibraryPaths.Add(Path.Combine(libraryRootDir, "um", "arm64"));
|
|
break;
|
|
}
|
|
case TargetArchitecture.x86:
|
|
{
|
|
SystemLibraryPaths.Add(Path.Combine(libraryRootDir, "um", "x86"));
|
|
SystemLibraryPaths.Add(Path.Combine(libraryRootDir, "ucrt", "x86"));
|
|
var binRootDir = Path.Combine(windowsSdkDir, "bin", "x86");
|
|
_resourceCompilerPath = Path.Combine(binRootDir, "rc.exe");
|
|
_makepriPath = Path.Combine(binRootDir, "makepri.exe");
|
|
break;
|
|
}
|
|
case TargetArchitecture.x64:
|
|
{
|
|
SystemLibraryPaths.Add(Path.Combine(libraryRootDir, "um", "x64"));
|
|
SystemLibraryPaths.Add(Path.Combine(libraryRootDir, "ucrt", "x64"));
|
|
var binRootDir = Path.Combine(windowsSdkDir, "bin", "x64");
|
|
_resourceCompilerPath = Path.Combine(binRootDir, "rc.exe");
|
|
_makepriPath = Path.Combine(binRootDir, "makepri.exe");
|
|
break;
|
|
}
|
|
default: throw new InvalidArchitectureException(Architecture);
|
|
}
|
|
break;
|
|
}
|
|
case WindowsPlatformSDK.v10_0_10240_0:
|
|
case WindowsPlatformSDK.v10_0_10586_0:
|
|
case WindowsPlatformSDK.v10_0_14393_0:
|
|
case WindowsPlatformSDK.v10_0_15063_0:
|
|
case WindowsPlatformSDK.v10_0_16299_0:
|
|
case WindowsPlatformSDK.v10_0_17134_0:
|
|
case WindowsPlatformSDK.v10_0_17763_0:
|
|
case WindowsPlatformSDK.v10_0_18362_0:
|
|
case WindowsPlatformSDK.v10_0_19041_0:
|
|
case WindowsPlatformSDK.v10_0_20348_0:
|
|
case WindowsPlatformSDK.v10_0_22000_0:
|
|
case WindowsPlatformSDK.v10_0_22621_0:
|
|
case WindowsPlatformSDK.v10_0_26100_0:
|
|
{
|
|
var sdkVersionName = WindowsPlatformBase.GetSDKVersion(SDK).ToString();
|
|
string includeRootDir = Path.Combine(windowsSdkDir, "include", sdkVersionName);
|
|
SystemIncludePaths.Add(Path.Combine(includeRootDir, "ucrt"));
|
|
SystemIncludePaths.Add(Path.Combine(includeRootDir, "shared"));
|
|
SystemIncludePaths.Add(Path.Combine(includeRootDir, "um"));
|
|
SystemIncludePaths.Add(Path.Combine(includeRootDir, "winrt"));
|
|
|
|
string libraryRootDir = Path.Combine(windowsSdkDir, "lib", sdkVersionName);
|
|
switch (Architecture)
|
|
{
|
|
case TargetArchitecture.AnyCPU: break;
|
|
case TargetArchitecture.ARM:
|
|
{
|
|
SystemLibraryPaths.Add(Path.Combine(libraryRootDir, "ucrt", "arm"));
|
|
SystemLibraryPaths.Add(Path.Combine(libraryRootDir, "um", "arm"));
|
|
break;
|
|
}
|
|
case TargetArchitecture.ARM64:
|
|
{
|
|
SystemLibraryPaths.Add(Path.Combine(libraryRootDir, "ucrt", "arm64"));
|
|
SystemLibraryPaths.Add(Path.Combine(libraryRootDir, "um", "arm64"));
|
|
var binRootDir = Path.Combine(windowsSdkDir, "bin", sdkVersionName, hostArchitecture.ToString().ToLower());
|
|
_resourceCompilerPath = Path.Combine(binRootDir, "rc.exe");
|
|
_makepriPath = Path.Combine(binRootDir, "makepri.exe");
|
|
break;
|
|
}
|
|
case TargetArchitecture.x86:
|
|
{
|
|
SystemLibraryPaths.Add(Path.Combine(libraryRootDir, "ucrt", "x86"));
|
|
SystemLibraryPaths.Add(Path.Combine(libraryRootDir, "um", "x86"));
|
|
var binRootDir = Path.Combine(windowsSdkDir, "bin", sdkVersionName, hostArchitecture.ToString().ToLower());
|
|
_resourceCompilerPath = Path.Combine(binRootDir, "rc.exe");
|
|
_makepriPath = Path.Combine(binRootDir, "makepri.exe");
|
|
break;
|
|
}
|
|
case TargetArchitecture.x64:
|
|
{
|
|
SystemLibraryPaths.Add(Path.Combine(libraryRootDir, "ucrt", "x64"));
|
|
SystemLibraryPaths.Add(Path.Combine(libraryRootDir, "um", "x64"));
|
|
var binRootDir = Path.Combine(windowsSdkDir, "bin", sdkVersionName, hostArchitecture.ToString().ToLower());
|
|
_resourceCompilerPath = Path.Combine(binRootDir, "rc.exe");
|
|
_makepriPath = Path.Combine(binRootDir, "makepri.exe");
|
|
break;
|
|
}
|
|
default: throw new InvalidArchitectureException(Architecture);
|
|
}
|
|
break;
|
|
}
|
|
default: throw new ArgumentOutOfRangeException(nameof(SDK));
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override bool UseImportLibraryWhenLinking => true;
|
|
|
|
/// <inheritdoc />
|
|
public override bool GeneratesImportLibraryWhenLinking => true;
|
|
|
|
/// <inheritdoc />
|
|
public override string DllExport => "__declspec(dllexport)";
|
|
|
|
/// <inheritdoc />
|
|
public override string DllImport => "__declspec(dllimport)";
|
|
|
|
/// <inheritdoc />
|
|
public override TargetCompiler Compiler => TargetCompiler.MSVC;
|
|
|
|
/// <inheritdoc />
|
|
public override string NativeCompilerPath => _compilerPath;
|
|
|
|
/// <inheritdoc />
|
|
public override void LogInfo()
|
|
{
|
|
var sdkPath = WindowsPlatformBase.GetSDKs()[SDK];
|
|
Log.Info(string.Format("Using Windows Toolset {0} ({1})", Toolset, sdkPath));
|
|
Log.Info(string.Format("Using Windows SDK {0} ({1})", WindowsPlatformBase.GetSDKVersion(SDK), _vcToolPath));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds the include path to the command line arguments.
|
|
/// </summary>
|
|
/// <param name="args">The arguments.</param>
|
|
/// <param name="path">The include path.</param>
|
|
protected static void AddIncludePath(List<string> args, string path)
|
|
{
|
|
if (path.Contains(' '))
|
|
args.Add(string.Format("/I\"{0}\"", path));
|
|
else
|
|
args.Add(string.Format("/I{0}", path));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the C++/CX metadata file directory.
|
|
/// </summary>
|
|
/// <returns>The folder path or null if not found.</returns>
|
|
protected string GetCppCXMetadataDirectory()
|
|
{
|
|
var toolsets = WindowsPlatformBase.GetToolsets();
|
|
var vcToolChainDir = toolsets[Toolset];
|
|
switch (Toolset)
|
|
{
|
|
case WindowsPlatformToolset.v144:
|
|
case WindowsPlatformToolset.v143:
|
|
case WindowsPlatformToolset.v142:
|
|
case WindowsPlatformToolset.v141: return Path.Combine(vcToolChainDir, "lib", "x86", "store", "references");
|
|
case WindowsPlatformToolset.v140: return Path.Combine(vcToolChainDir, "lib", "store", "references");
|
|
default: return null;
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override void SetupEnvironment(BuildOptions options)
|
|
{
|
|
base.SetupEnvironment(options);
|
|
|
|
options.CompileEnv.PreprocessorDefinitions.Add("PLATFORM_WIN32");
|
|
options.CompileEnv.PreprocessorDefinitions.Add("WIN32");
|
|
options.CompileEnv.PreprocessorDefinitions.Add("_CRT_SECURE_NO_DEPRECATE");
|
|
options.CompileEnv.PreprocessorDefinitions.Add("_CRT_SECURE_NO_WARNINGS");
|
|
options.CompileEnv.PreprocessorDefinitions.Add("_WINDOWS");
|
|
if (Architecture == TargetArchitecture.x64 || Architecture == TargetArchitecture.ARM64)
|
|
options.CompileEnv.PreprocessorDefinitions.Add("WIN64");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Setups the C++ files compilation arguments.
|
|
/// </summary>
|
|
/// <param name="graph">The graph.</param>
|
|
/// <param name="options">The options.</param>
|
|
/// <param name="args">The arguments.</param>
|
|
protected virtual void SetupCompileCppFilesArgs(TaskGraph graph, BuildOptions options, List<string> args)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Setups the linking files arguments.
|
|
/// </summary>
|
|
/// <param name="graph">The graph.</param>
|
|
/// <param name="options">The options.</param>
|
|
/// <param name="args">The arguments.</param>
|
|
protected virtual void SetupLinkFilesArgs(TaskGraph graph, BuildOptions options, List<string> args)
|
|
{
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override CompileOutput CompileCppFiles(TaskGraph graph, BuildOptions options, List<string> sourceFiles, string outputPath)
|
|
{
|
|
var compileEnvironment = options.CompileEnv;
|
|
var output = new CompileOutput();
|
|
|
|
// Setup arguments shared by all source files
|
|
var commonArgs = new List<string>();
|
|
commonArgs.AddRange(options.CompileEnv.CustomArgs);
|
|
SetupCompileCppFilesArgs(graph, options, commonArgs);
|
|
var useSeparatePdb = true; //compileEnvironment.PrecompiledHeaderUsage == PrecompiledHeaderFileUsage.None;
|
|
{
|
|
// Suppress Startup Banner
|
|
commonArgs.Add("/nologo");
|
|
|
|
// Compile Without Linking
|
|
commonArgs.Add("/c");
|
|
|
|
// C++ version
|
|
switch (compileEnvironment.CppVersion)
|
|
{
|
|
case CppVersion.Cpp14:
|
|
commonArgs.Add("/std:c++14");
|
|
break;
|
|
case CppVersion.Cpp17:
|
|
commonArgs.Add("/std:c++17");
|
|
break;
|
|
case CppVersion.Cpp20:
|
|
commonArgs.Add("/std:c++20");
|
|
break;
|
|
case CppVersion.Latest:
|
|
commonArgs.Add("/std:c++latest");
|
|
break;
|
|
}
|
|
commonArgs.Add("/Zc:__cplusplus");
|
|
|
|
// Generate Intrinsic Functions
|
|
if (compileEnvironment.IntrinsicFunctions)
|
|
commonArgs.Add("/Oi");
|
|
|
|
// Enable Function-Level Linking
|
|
if (compileEnvironment.FunctionLevelLinking)
|
|
commonArgs.Add("/Gy");
|
|
else
|
|
commonArgs.Add("/Gy-");
|
|
|
|
// List Include Files
|
|
//commonArgs.Add("/showIncludes");
|
|
|
|
// Code Analysis
|
|
commonArgs.Add("/analyze-");
|
|
|
|
// Remove unreferenced COMDAT
|
|
commonArgs.Add("/Zc:inline");
|
|
|
|
// Run-Time Error Checks
|
|
if (compileEnvironment.RuntimeChecks && !compileEnvironment.CompileAsWinRT)
|
|
commonArgs.Add("/RTC1");
|
|
|
|
// Inline Function Expansion
|
|
if (compileEnvironment.Inlining)
|
|
commonArgs.Add("/Ob2");
|
|
|
|
if (compileEnvironment.DebugInformation)
|
|
{
|
|
// Debug Information Format
|
|
if (useSeparatePdb)
|
|
commonArgs.Add("/Zi");
|
|
else
|
|
commonArgs.Add("/Z7");
|
|
|
|
// Enhance Optimized Debugging
|
|
commonArgs.Add("/Zo");
|
|
}
|
|
|
|
// Favor Small Code, Favor Fast Code
|
|
if (compileEnvironment.FavorSizeOrSpeed == FavorSizeOrSpeed.FastCode)
|
|
commonArgs.Add("/Ot");
|
|
else if (compileEnvironment.FavorSizeOrSpeed == FavorSizeOrSpeed.SmallCode)
|
|
commonArgs.Add("/Os");
|
|
if (compileEnvironment.Optimization)
|
|
{
|
|
// Generate Intrinsic Functions
|
|
commonArgs.Add("/Oi");
|
|
|
|
// Frame-Pointer Omission
|
|
commonArgs.Add("/Oy");
|
|
|
|
// Only use /Ox with /GL to prevent too long build times
|
|
if (compileEnvironment.WholeProgramOptimization)
|
|
{
|
|
// Enable Most Speed Optimizations
|
|
commonArgs.Add("/Ox");
|
|
|
|
// Whole Program Optimization
|
|
commonArgs.Add("/GL");
|
|
}
|
|
else
|
|
{
|
|
// Enable SEE2 and other code optimizations but without breaking incremental linking
|
|
//commonArgs.Add("/Og"); // Results in D9035 warning
|
|
commonArgs.Add("/O2");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Disable compiler optimizations (Debug)
|
|
commonArgs.Add("/Od");
|
|
|
|
// Frame-Pointer Omission
|
|
commonArgs.Add("/Oy-");
|
|
}
|
|
|
|
// Full Path of Source Code File in Diagnostics
|
|
commonArgs.Add("/FC");
|
|
|
|
// Report Internal Compiler Errors
|
|
commonArgs.Add("/errorReport:prompt");
|
|
|
|
// Exception Handling Model
|
|
if (!compileEnvironment.CompileAsWinRT)
|
|
{
|
|
if (compileEnvironment.EnableExceptions)
|
|
commonArgs.Add("/EHsc");
|
|
else
|
|
commonArgs.Add("/D_HAS_EXCEPTIONS=0");
|
|
}
|
|
|
|
// Eliminate Duplicate Strings
|
|
if (compileEnvironment.StringPooling)
|
|
commonArgs.Add("/GF");
|
|
else
|
|
commonArgs.Add("/GF-");
|
|
|
|
// Use Run-Time Library
|
|
if (compileEnvironment.UseDebugCRT)
|
|
commonArgs.Add("/MDd");
|
|
else
|
|
commonArgs.Add("/MD");
|
|
|
|
// Specify floating-point behavior
|
|
commonArgs.Add("/fp:fast");
|
|
commonArgs.Add("/fp:except-");
|
|
|
|
// Buffer Security Check
|
|
if (compileEnvironment.BufferSecurityCheck)
|
|
commonArgs.Add("/GS");
|
|
else
|
|
commonArgs.Add("/GS-");
|
|
|
|
// Enable Run-Time Type Information
|
|
if (compileEnvironment.RuntimeTypeInfo)
|
|
commonArgs.Add("/GR");
|
|
else
|
|
commonArgs.Add("/GR-");
|
|
|
|
// Treats all compiler warnings as errors
|
|
if (compileEnvironment.TreatWarningsAsErrors)
|
|
commonArgs.Add("/WX");
|
|
else
|
|
commonArgs.Add("/WX-");
|
|
|
|
// Show warnings
|
|
commonArgs.Add("/W3");
|
|
|
|
// Silence macro redefinition warning
|
|
commonArgs.Add("/wd\"4005\"");
|
|
|
|
// wchar_t is Native Type
|
|
commonArgs.Add("/Zc:wchar_t");
|
|
|
|
// Common Language Runtime Compilation
|
|
if (compileEnvironment.CompileAsWinRT)
|
|
commonArgs.Add("/clr");
|
|
|
|
// Windows Runtime Compilation
|
|
if (compileEnvironment.WinRTComponentExtensions)
|
|
{
|
|
commonArgs.Add("/ZW");
|
|
//commonArgs.Add("/ZW:nostdlib");
|
|
|
|
var dir = GetCppCXMetadataDirectory();
|
|
if (dir != null)
|
|
{
|
|
commonArgs.Add(string.Format("/AI\"{0}\"", dir));
|
|
commonArgs.Add(string.Format("/FU\"{0}\\platform.winmd\"", dir));
|
|
}
|
|
}
|
|
|
|
// Preprocessor conformance mode
|
|
commonArgs.Add("/Zc:preprocessor");
|
|
}
|
|
|
|
// Add preprocessor definitions
|
|
foreach (var definition in compileEnvironment.PreprocessorDefinitions)
|
|
{
|
|
commonArgs.Add(string.Format("/D \"{0}\"", definition));
|
|
}
|
|
|
|
// Add include paths
|
|
foreach (var includePath in compileEnvironment.IncludePaths)
|
|
{
|
|
AddIncludePath(commonArgs, includePath);
|
|
}
|
|
|
|
var args = new List<string>();
|
|
|
|
// Create precompiled header
|
|
string pchFile = null, pchSource = null;
|
|
if (compileEnvironment.PrecompiledHeaderUsage == PrecompiledHeaderFileUsage.UseManual)
|
|
{
|
|
pchFile = compileEnvironment.PrecompiledHeaderFile;
|
|
pchSource = compileEnvironment.PrecompiledHeaderSource;
|
|
}
|
|
else if (compileEnvironment.PrecompiledHeaderUsage == PrecompiledHeaderFileUsage.CreateManual)
|
|
{
|
|
// Use intermediate cpp file that includes the PCH path but also contains compiler info to properly recompile when it's modified
|
|
pchSource = compileEnvironment.PrecompiledHeaderSource;
|
|
var pchFilName = Path.GetFileName(pchSource);
|
|
var pchSourceFile = Path.Combine(options.IntermediateFolder, Path.ChangeExtension(pchFilName, "cpp"));
|
|
var contents = Bindings.BindingsGenerator.GetStringBuilder();
|
|
contents.AppendLine("// This code was auto-generated. Do not modify it.");
|
|
// TODO: write compiler version to properly rebuild pch on Visual Studio updates
|
|
contents.Append("// Compiler: ").AppendLine(_compilerPath);
|
|
contents.Append("#include \"").Append(pchSource).AppendLine("\"");
|
|
Utilities.WriteFileIfChanged(pchSourceFile, contents.ToString());
|
|
Bindings.BindingsGenerator.PutStringBuilder(contents);
|
|
|
|
// Compile intermediate cpp file into actual PCH (and obj+pdb files)
|
|
pchFile = Path.Combine(options.IntermediateFolder, Path.ChangeExtension(pchFilName, "pch"));
|
|
if (pchFile.EndsWith(".pch.pch"))
|
|
pchFile = pchFile.Substring(0, pchFile.Length - 4);
|
|
var pchPdbFile = Path.Combine(options.IntermediateFolder, Path.ChangeExtension(pchFilName, "pdb"));
|
|
var pchObjFile = Path.Combine(options.IntermediateFolder, Path.ChangeExtension(pchFilName, "obj"));
|
|
var task = graph.Add<Task>();
|
|
task.PrerequisiteFiles.Add(pchSourceFile);
|
|
task.PrerequisiteFiles.Add(pchSource);
|
|
task.PrerequisiteFiles.AddRange(IncludesCache.FindAllIncludedFiles(pchSource));
|
|
task.ProducedFiles.Add(pchFile);
|
|
task.ProducedFiles.Add(pchObjFile);
|
|
args.AddRange(commonArgs);
|
|
args.Add(string.Format("/Yc\"{0}\"", pchSource));
|
|
args.Add(string.Format("/Fp\"{0}\"", pchFile));
|
|
args.Add(string.Format("/Fd\"{0}\"", pchPdbFile));
|
|
args.Add(string.Format("/Fo\"{0}\"", pchObjFile));
|
|
args.Add("/FS");
|
|
args.Add(string.Format("\"{0}\"", pchSourceFile));
|
|
task.WorkingDirectory = options.WorkingDirectory;
|
|
task.CommandPath = _compilerPath;
|
|
task.CommandArguments = string.Join(" ", args);
|
|
task.Cost = int.MaxValue; // Run it before any other tasks
|
|
|
|
// Setup outputs
|
|
output.PrecompiledHeaderFile = pchFile;
|
|
output.ObjectFiles.Add(pchObjFile);
|
|
}
|
|
if (pchFile != null)
|
|
{
|
|
// Include PCH file
|
|
commonArgs.Add(string.Format("/FI\"{0}\"", pchSource));
|
|
commonArgs.Add(string.Format("/Yu\"{0}\"", pchSource));
|
|
commonArgs.Add(string.Format("/Fp\"{0}\"", pchFile));
|
|
}
|
|
|
|
// Compile all C++ files
|
|
foreach (var sourceFile in sourceFiles)
|
|
{
|
|
var sourceFilename = Path.GetFileNameWithoutExtension(sourceFile);
|
|
var task = graph.Add<CompileCppTask>();
|
|
|
|
// Use shared arguments
|
|
args.Clear();
|
|
args.AddRange(commonArgs);
|
|
|
|
if (compileEnvironment.DebugInformation)
|
|
{
|
|
// Program Database File Name
|
|
string pdbFile = null;
|
|
if (pchFile != null)
|
|
{
|
|
// When using PCH we need to share the same PDB file that was used when building PCH
|
|
pdbFile = pchFile + ".pdb";
|
|
|
|
// Turn on sync for file access to prevent issues when compiling on multiple threads at once
|
|
if (useSeparatePdb)
|
|
args.Add("/FS");
|
|
}
|
|
else if (useSeparatePdb)
|
|
{
|
|
pdbFile = Path.Combine(outputPath, sourceFilename + ".pdb");
|
|
}
|
|
if (pdbFile != null)
|
|
{
|
|
args.Add(string.Format("/Fd\"{0}\"", pdbFile));
|
|
output.DebugDataFiles.Add(pdbFile);
|
|
}
|
|
}
|
|
|
|
if (compileEnvironment.GenerateDocumentation)
|
|
{
|
|
// Process Documentation Comments
|
|
var docFile = Path.Combine(outputPath, sourceFilename + ".xdc");
|
|
args.Add(string.Format("/doc\"{0}\"", docFile));
|
|
output.DocumentationFiles.Add(docFile);
|
|
}
|
|
|
|
// Object File Name
|
|
var objFile = Path.Combine(outputPath, sourceFilename + ".obj");
|
|
args.Add(string.Format("/Fo\"{0}\"", objFile));
|
|
output.ObjectFiles.Add(objFile);
|
|
task.ProducedFiles.Add(objFile);
|
|
|
|
// Source File Name
|
|
args.Add("\"" + sourceFile + "\"");
|
|
|
|
// Request included files to exist
|
|
var includes = IncludesCache.FindAllIncludedFiles(sourceFile);
|
|
task.PrerequisiteFiles.AddRange(includes);
|
|
if (pchFile != null)
|
|
{
|
|
task.PrerequisiteFiles.Add(pchFile);
|
|
}
|
|
|
|
// Compile
|
|
task.WorkingDirectory = options.WorkingDirectory;
|
|
task.CommandPath = _compilerPath;
|
|
task.CommandArguments = string.Join(" ", args);
|
|
task.PrerequisiteFiles.Add(sourceFile);
|
|
task.Cost = task.PrerequisiteFiles.Count; // TODO: include source file size estimation to improve tasks sorting
|
|
}
|
|
|
|
return output;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override void LinkFiles(TaskGraph graph, BuildOptions options, string outputFilePath)
|
|
{
|
|
var linkEnvironment = options.LinkEnv;
|
|
var task = graph.Add<LinkTask>();
|
|
|
|
// Setup arguments
|
|
var args = new List<string>();
|
|
args.AddRange(options.LinkEnv.CustomArgs);
|
|
SetupLinkFilesArgs(graph, options, args);
|
|
{
|
|
// Suppress startup banner
|
|
args.Add("/NOLOGO");
|
|
|
|
// Report internal compiler errors
|
|
args.Add("/ERRORREPORT:PROMPT");
|
|
|
|
// Output File Name
|
|
args.Add(string.Format("/OUT:\"{0}\"", outputFilePath));
|
|
|
|
// Specify target platform
|
|
switch (Architecture)
|
|
{
|
|
case TargetArchitecture.x86:
|
|
args.Add("/MACHINE:x86");
|
|
break;
|
|
case TargetArchitecture.x64:
|
|
args.Add("/MACHINE:x64");
|
|
break;
|
|
case TargetArchitecture.ARM:
|
|
args.Add("/MACHINE:ARM");
|
|
break;
|
|
case TargetArchitecture.ARM64:
|
|
args.Add("/MACHINE:ARM64");
|
|
break;
|
|
default: throw new InvalidArchitectureException(Architecture);
|
|
}
|
|
|
|
// Specify subsystem
|
|
if (linkEnvironment.LinkAsConsoleProgram)
|
|
{
|
|
args.Add("/SUBSYSTEM:CONSOLE");
|
|
}
|
|
else
|
|
{
|
|
args.Add("/SUBSYSTEM:WINDOWS");
|
|
}
|
|
|
|
// Generate Windows Metadata
|
|
if (linkEnvironment.GenerateWindowsMetadata)
|
|
{
|
|
args.Add("/WINMD");
|
|
args.Add(string.Format("/WINMDFILE:\"{0}\"", Path.ChangeExtension(outputFilePath, "winmd")));
|
|
args.Add("/APPCONTAINER");
|
|
if (linkEnvironment.Output == LinkerOutput.SharedLibrary)
|
|
args.Add("/DYNAMICBASE");
|
|
}
|
|
|
|
if (linkEnvironment.LinkTimeCodeGeneration)
|
|
{
|
|
// Link-time code generation
|
|
args.Add("/LTCG");
|
|
}
|
|
|
|
if (linkEnvironment.Output == LinkerOutput.ImportLibrary)
|
|
{
|
|
// Create an import library
|
|
args.Add("/DEF");
|
|
|
|
// Ignore libraries
|
|
args.Add("/NODEFAULTLIB");
|
|
|
|
// Specify the name
|
|
args.Add(string.Format("/NAME:\"{0}\"", Path.GetFileNameWithoutExtension(outputFilePath)));
|
|
|
|
// Ignore warnings about files with no public symbols
|
|
args.Add("/IGNORE:4221");
|
|
}
|
|
else
|
|
{
|
|
// Don't create Side-by-Side Assembly Manifest
|
|
args.Add("/MANIFEST:NO");
|
|
|
|
// Fixed Base Address
|
|
args.Add("/FIXED:NO");
|
|
|
|
if (Architecture == TargetArchitecture.x86)
|
|
{
|
|
// Handle Large Addresses
|
|
args.Add("/LARGEADDRESSAWARE");
|
|
}
|
|
|
|
// Compatible with Data Execution Prevention
|
|
args.Add("/NXCOMPAT");
|
|
|
|
// Allow delay-loaded DLLs to be explicitly unloaded
|
|
args.Add("/DELAY:UNLOAD");
|
|
|
|
if (linkEnvironment.Output == LinkerOutput.SharedLibrary)
|
|
{
|
|
// Build a DLL
|
|
args.Add("/DLL");
|
|
}
|
|
|
|
// Redirect imports LIB file auto-generated for EXE/DLL
|
|
var libFile = Path.ChangeExtension(outputFilePath, Platform.StaticLibraryFileExtension);
|
|
args.Add("/IMPLIB:\"" + libFile + "\"");
|
|
task.ProducedFiles.Add(libFile);
|
|
|
|
// Don't embed the full PDB path
|
|
args.Add("/PDBALTPATH:%_PDB%");
|
|
|
|
// Optimize
|
|
if (linkEnvironment.Optimization && !linkEnvironment.UseIncrementalLinking)
|
|
{
|
|
// Generate an EXE checksum
|
|
args.Add("/RELEASE");
|
|
|
|
// Eliminate unreferenced symbols
|
|
args.Add("/OPT:REF");
|
|
|
|
// Remove redundant COMDATs
|
|
args.Add("/OPT:ICF");
|
|
}
|
|
else
|
|
{
|
|
// Keep symbols that are unreferenced
|
|
args.Add("/OPT:NOREF");
|
|
|
|
// Disable identical COMDAT folding
|
|
args.Add("/OPT:NOICF");
|
|
}
|
|
|
|
// Link Incrementally
|
|
if (linkEnvironment.UseIncrementalLinking && !linkEnvironment.LinkTimeCodeGeneration)
|
|
{
|
|
args.Add("/INCREMENTAL");
|
|
}
|
|
else
|
|
{
|
|
args.Add("/INCREMENTAL:NO");
|
|
}
|
|
|
|
if (linkEnvironment.DebugInformation)
|
|
{
|
|
// Generate debug information
|
|
if (Toolset != WindowsPlatformToolset.v140 && linkEnvironment.UseFastPDBLinking)
|
|
{
|
|
args.Add("/DEBUG:FASTLINK");
|
|
}
|
|
else if (linkEnvironment.UseFullDebugInformation)
|
|
{
|
|
args.Add("/DEBUG:FULL");
|
|
}
|
|
else
|
|
{
|
|
args.Add("/DEBUG"); // Same as /DEBUG:FULL
|
|
}
|
|
|
|
// Use Program Database
|
|
var pdbFile = Path.ChangeExtension(outputFilePath, Platform.ProgramDatabaseFileExtension);
|
|
args.Add(string.Format("/PDB:\"{0}\"", pdbFile));
|
|
task.ProducedFiles.Add(pdbFile);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Delay-load DLLs
|
|
if (linkEnvironment.Output == LinkerOutput.Executable || linkEnvironment.Output == LinkerOutput.SharedLibrary)
|
|
{
|
|
foreach (var dll in options.DelayLoadLibraries)
|
|
{
|
|
args.Add(string.Format("/DELAYLOAD:\"{0}\"", dll));
|
|
}
|
|
}
|
|
|
|
// Additional lib paths
|
|
foreach (var libpath in linkEnvironment.LibraryPaths)
|
|
{
|
|
args.Add(string.Format("/LIBPATH:\"{0}\"", libpath));
|
|
}
|
|
|
|
// Input libraries
|
|
task.PrerequisiteFiles.AddRange(linkEnvironment.InputLibraries);
|
|
foreach (var library in linkEnvironment.InputLibraries)
|
|
{
|
|
args.Add(string.Format("\"{0}\"", library));
|
|
}
|
|
|
|
// Input files
|
|
task.PrerequisiteFiles.AddRange(linkEnvironment.InputFiles);
|
|
foreach (var file in linkEnvironment.InputFiles)
|
|
{
|
|
if (file.EndsWith(".pch", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
// PCH file
|
|
args.Add(string.Format("/Yu:\"{0}\"", file));
|
|
continue;
|
|
}
|
|
|
|
args.Add(string.Format("\"{0}\"", file));
|
|
}
|
|
|
|
// Use a response file (it can contain any commands that you would specify on the command line)
|
|
bool useResponseFile = true;
|
|
string responseFile = null;
|
|
if (useResponseFile)
|
|
{
|
|
responseFile = Path.Combine(options.IntermediateFolder, Path.GetFileName(outputFilePath) + ".response");
|
|
task.PrerequisiteFiles.Add(responseFile);
|
|
Utilities.WriteFileIfChanged(responseFile, string.Join(Environment.NewLine, args));
|
|
}
|
|
|
|
// Link
|
|
task.WorkingDirectory = options.WorkingDirectory;
|
|
task.CommandPath = linkEnvironment.Output == LinkerOutput.ImportLibrary ? _libToolPath : _linkerPath;
|
|
task.CommandArguments = useResponseFile ? string.Format("@\"{0}\"", responseFile) : string.Join(" ", args);
|
|
if (linkEnvironment.Output == LinkerOutput.ImportLibrary)
|
|
task.InfoMessage = "Building import library " + outputFilePath;
|
|
else
|
|
task.InfoMessage = "Linking " + outputFilePath;
|
|
task.Cost = task.PrerequisiteFiles.Count;
|
|
task.ProducedFiles.Add(outputFilePath);
|
|
|
|
// Check if need to generate documentation
|
|
if (linkEnvironment.GenerateDocumentation)
|
|
{
|
|
args.Clear();
|
|
var docTask = graph.Add<Task>();
|
|
|
|
// Use old input format
|
|
args.Add("/old");
|
|
args.Add(string.Format("\"{0}\"", Path.GetFileNameWithoutExtension(outputFilePath)));
|
|
|
|
// Suppress copyright message
|
|
args.Add("/nologo");
|
|
|
|
// Output file
|
|
var outputDocFile = Path.ChangeExtension(outputFilePath, "xml");
|
|
docTask.ProducedFiles.Add(outputDocFile);
|
|
args.Add(string.Format("/Fo\"{0}\"", outputDocFile));
|
|
|
|
// Input files
|
|
docTask.PrerequisiteFiles.AddRange(linkEnvironment.DocumentationFiles);
|
|
foreach (var file in linkEnvironment.DocumentationFiles)
|
|
{
|
|
args.Add(string.Format("/Fs\"{0}\"", file));
|
|
}
|
|
|
|
// Generate docs
|
|
docTask.WorkingDirectory = options.WorkingDirectory;
|
|
docTask.CommandPath = _xdcmakePath;
|
|
docTask.CommandArguments = string.Join(" ", args);
|
|
docTask.Cost = linkEnvironment.DocumentationFiles.Count;
|
|
}
|
|
|
|
// Check if need to generate metadata file
|
|
if (linkEnvironment.GenerateWindowsMetadata)
|
|
{
|
|
var configFile = Path.Combine(options.IntermediateFolder, Path.GetFileNameWithoutExtension(outputFilePath) + ".priconfig.xml");
|
|
var manifestFile = Path.Combine(options.IntermediateFolder, Path.GetFileNameWithoutExtension(outputFilePath) + ".AppxManifest.xml");
|
|
var priFile = Path.ChangeExtension(outputFilePath, "pri");
|
|
|
|
// Generate pri config file
|
|
var priConfigTask = graph.Add<Task>();
|
|
priConfigTask.WorkingDirectory = options.WorkingDirectory;
|
|
priConfigTask.CommandPath = _makepriPath;
|
|
priConfigTask.CommandArguments = string.Format("createconfig /cf \"{0}\" /dq en-US /o", configFile);
|
|
priConfigTask.Cost = 1;
|
|
priConfigTask.ProducedFiles.Add(configFile);
|
|
|
|
// Create AppxManifest file
|
|
{
|
|
using (var stringWriter = new StringWriterWithEncoding(Encoding.UTF8))
|
|
using (var xmlTextWriter = XmlWriter.Create(stringWriter, new XmlWriterSettings { Encoding = Encoding.UTF8, Indent = true, }))
|
|
{
|
|
xmlTextWriter.WriteStartDocument();
|
|
|
|
// Package
|
|
{
|
|
xmlTextWriter.WriteStartElement("Package", "http://schemas.microsoft.com/appx/2010/manifest");
|
|
|
|
// Identity
|
|
{
|
|
xmlTextWriter.WriteStartElement("Identity");
|
|
|
|
xmlTextWriter.WriteAttributeString("Name", "FlaxGame");
|
|
xmlTextWriter.WriteAttributeString("Publisher", "CN=Flax, O=Flax, C=Poland");
|
|
xmlTextWriter.WriteAttributeString("Version", "1.0.0.0"); // TODO: get Flax version number
|
|
|
|
switch (Architecture)
|
|
{
|
|
case TargetArchitecture.AnyCPU:
|
|
xmlTextWriter.WriteAttributeString("ProcessorArchitecture", "neutral");
|
|
break;
|
|
case TargetArchitecture.x86:
|
|
xmlTextWriter.WriteAttributeString("ProcessorArchitecture", "x86");
|
|
break;
|
|
case TargetArchitecture.x64:
|
|
xmlTextWriter.WriteAttributeString("ProcessorArchitecture", "x64");
|
|
break;
|
|
case TargetArchitecture.ARM:
|
|
case TargetArchitecture.ARM64:
|
|
xmlTextWriter.WriteAttributeString("ProcessorArchitecture", "arm");
|
|
break;
|
|
default: throw new InvalidArchitectureException(Architecture);
|
|
}
|
|
|
|
xmlTextWriter.WriteEndElement();
|
|
}
|
|
|
|
// Properties
|
|
{
|
|
xmlTextWriter.WriteStartElement("Properties");
|
|
|
|
// TODO: better logo handling
|
|
var logoSrcPath = Path.Combine(Globals.EngineRoot, "Source", "Logo.png");
|
|
var logoDstPath = Path.Combine(options.IntermediateFolder, "Logo.png");
|
|
if (!File.Exists(logoDstPath))
|
|
Utilities.FileCopy(logoSrcPath, logoDstPath);
|
|
|
|
xmlTextWriter.WriteElementString("DisplayName", "FlaxGame");
|
|
xmlTextWriter.WriteElementString("PublisherDisplayName", "Flax");
|
|
xmlTextWriter.WriteElementString("Logo", "Logo.png");
|
|
|
|
xmlTextWriter.WriteEndElement();
|
|
}
|
|
|
|
// Resources
|
|
{
|
|
xmlTextWriter.WriteStartElement("Resources");
|
|
|
|
xmlTextWriter.WriteStartElement("Resource");
|
|
xmlTextWriter.WriteAttributeString("Language", "en-us");
|
|
xmlTextWriter.WriteEndElement();
|
|
|
|
xmlTextWriter.WriteEndElement();
|
|
}
|
|
|
|
// Prerequisites
|
|
{
|
|
xmlTextWriter.WriteStartElement("Prerequisites");
|
|
|
|
xmlTextWriter.WriteElementString("OSMinVersion", "6.2");
|
|
xmlTextWriter.WriteElementString("OSMaxVersionTested", "6.2");
|
|
|
|
xmlTextWriter.WriteEndElement();
|
|
}
|
|
}
|
|
|
|
xmlTextWriter.WriteEndDocument();
|
|
xmlTextWriter.Flush();
|
|
|
|
// Save manifest to file
|
|
var contents = stringWriter.GetStringBuilder().ToString();
|
|
Utilities.WriteFileIfChanged(manifestFile, contents);
|
|
}
|
|
}
|
|
|
|
var dummyWorkspace = Path.Combine(options.IntermediateFolder, "Dummy");
|
|
if (!Directory.Exists(dummyWorkspace))
|
|
Directory.CreateDirectory(dummyWorkspace);
|
|
|
|
// Generate pri file
|
|
var priNewFile = graph.Add<Task>();
|
|
priNewFile.WorkingDirectory = options.WorkingDirectory;
|
|
priNewFile.CommandPath = _makepriPath;
|
|
priNewFile.CommandArguments = string.Format("new /cf \"{0}\" /pr \"{1}\" /of \"{2}\" /mn \"{3}\" /o", configFile, dummyWorkspace, priFile, manifestFile);
|
|
priNewFile.Cost = 1;
|
|
priNewFile.PrerequisiteFiles.Add(configFile);
|
|
priNewFile.ProducedFiles.Add(priFile);
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override bool CompileCSharp(ref CSharpOptions options)
|
|
{
|
|
switch (options.Action)
|
|
{
|
|
case CSharpOptions.ActionTypes.MonoCompile:
|
|
{
|
|
var aotCompilerPath = Path.Combine(options.PlatformToolsPath, "mono-aot-cross.exe");
|
|
|
|
// Setup options
|
|
var monoAotMode = "full";
|
|
var monoDebugMode = options.EnableDebugSymbols ? "soft-debug" : "nodebug";
|
|
var aotCompilerArgs = $"--aot={monoAotMode},verbose,stats,print-skipped,{monoDebugMode} -O=all";
|
|
if (options.EnableDebugSymbols || options.EnableToolDebug)
|
|
aotCompilerArgs = "--debug " + aotCompilerArgs;
|
|
var envVars = new Dictionary<string, string>();
|
|
envVars["MONO_PATH"] = options.AssembliesPath + ";" + options.ClassLibraryPath;
|
|
if (options.EnableToolDebug)
|
|
{
|
|
envVars["MONO_LOG_LEVEL"] = "debug";
|
|
}
|
|
|
|
// Run cross-compiler compiler
|
|
int result = Utilities.Run(aotCompilerPath, $"{aotCompilerArgs} \"{options.InputFiles[0]}\"", null, options.PlatformToolsPath, Utilities.RunOptions.AppMustExist | Utilities.RunOptions.ConsoleLogOutput, envVars);
|
|
return result != 0;
|
|
}
|
|
}
|
|
return base.CompileCSharp(ref options);
|
|
}
|
|
}
|
|
}
|