godot/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs
Ignacio Etcheverry 270af6fa08 Re-write mono module editor code in C#
Make the build system automatically build the C# Api assemblies to be shipped with the editor.
Make the editor, editor player and debug export templates use Api assemblies built with debug symbols.
Always run MSBuild to build the editor tools and Api assemblies when building Godot.
Several bugs fixed related to assembly hot reloading and restoring state.
Fix StringExtensions internal calls not being registered correctly, resulting in MissingMethodException.
2019-07-05 09:38:23 +02:00

173 lines
6.2 KiB
C#

using GodotTools.Core;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using GodotTools.BuildLogger;
using GodotTools.Internals;
using GodotTools.Utils;
using Directory = System.IO.Directory;
namespace GodotTools.Build
{
public static class BuildSystem
{
private static string GetMsBuildPath()
{
string msbuildPath = MsBuildFinder.FindMsBuild();
if (msbuildPath == null)
throw new FileNotFoundException("Cannot find the MSBuild executable.");
return msbuildPath;
}
private static string MonoWindowsBinDir
{
get
{
string monoWinBinDir = Path.Combine(Internal.MonoWindowsInstallRoot, "bin");
if (!Directory.Exists(monoWinBinDir))
throw new FileNotFoundException("Cannot find the Windows Mono install bin directory.");
return monoWinBinDir;
}
}
private static Godot.EditorSettings EditorSettings =>
GodotSharpEditor.Instance.GetEditorInterface().GetEditorSettings();
private static bool UsingMonoMsBuildOnWindows
{
get
{
if (OS.IsWindows())
{
return (GodotSharpBuilds.BuildTool) EditorSettings.GetSetting("mono/builds/build_tool")
== GodotSharpBuilds.BuildTool.MsBuildMono;
}
return false;
}
}
private static bool PrintBuildOutput =>
(bool) EditorSettings.GetSetting("mono/builds/print_build_output");
private static Process LaunchBuild(string solution, string config, string loggerOutputDir, IEnumerable<string> customProperties = null)
{
var customPropertiesList = new List<string>();
if (customProperties != null)
customPropertiesList.AddRange(customProperties);
string compilerArgs = BuildArguments(solution, config, loggerOutputDir, customPropertiesList);
var startInfo = new ProcessStartInfo(GetMsBuildPath(), compilerArgs);
bool redirectOutput = !IsDebugMsBuildRequested() && !PrintBuildOutput;
if (!redirectOutput || Godot.OS.IsStdoutVerbose())
Console.WriteLine($"Running: \"{startInfo.FileName}\" {startInfo.Arguments}");
startInfo.RedirectStandardOutput = redirectOutput;
startInfo.RedirectStandardError = redirectOutput;
startInfo.UseShellExecute = false;
if (UsingMonoMsBuildOnWindows)
{
// These environment variables are required for Mono's MSBuild to find the compilers.
// We use the batch files in Mono's bin directory to make sure the compilers are executed with mono.
string monoWinBinDir = MonoWindowsBinDir;
startInfo.EnvironmentVariables.Add("CscToolExe", Path.Combine(monoWinBinDir, "csc.bat"));
startInfo.EnvironmentVariables.Add("VbcToolExe", Path.Combine(monoWinBinDir, "vbc.bat"));
startInfo.EnvironmentVariables.Add("FscToolExe", Path.Combine(monoWinBinDir, "fsharpc.bat"));
}
// Needed when running from Developer Command Prompt for VS
RemovePlatformVariable(startInfo.EnvironmentVariables);
var process = new Process {StartInfo = startInfo};
process.Start();
if (redirectOutput)
{
process.BeginOutputReadLine();
process.BeginErrorReadLine();
}
return process;
}
public static int Build(MonoBuildInfo monoBuildInfo)
{
return Build(monoBuildInfo.Solution, monoBuildInfo.Configuration,
monoBuildInfo.LogsDirPath, monoBuildInfo.CustomProperties);
}
public static async Task<int> BuildAsync(MonoBuildInfo monoBuildInfo)
{
return await BuildAsync(monoBuildInfo.Solution, monoBuildInfo.Configuration,
monoBuildInfo.LogsDirPath, monoBuildInfo.CustomProperties);
}
public static int Build(string solution, string config, string loggerOutputDir, IEnumerable<string> customProperties = null)
{
using (var process = LaunchBuild(solution, config, loggerOutputDir, customProperties))
{
process.WaitForExit();
return process.ExitCode;
}
}
public static async Task<int> BuildAsync(string solution, string config, string loggerOutputDir, IEnumerable<string> customProperties = null)
{
using (var process = LaunchBuild(solution, config, loggerOutputDir, customProperties))
{
await process.WaitForExitAsync();
return process.ExitCode;
}
}
private static string BuildArguments(string solution, string config, string loggerOutputDir, List<string> customProperties)
{
string arguments = $@"""{solution}"" /v:normal /t:Rebuild ""/p:{"Configuration=" + config}"" " +
$@"""/l:{typeof(GodotBuildLogger).FullName},{GodotBuildLogger.AssemblyPath};{loggerOutputDir}""";
foreach (string customProperty in customProperties)
{
arguments += " /p:" + customProperty;
}
return arguments;
}
private static void RemovePlatformVariable(StringDictionary environmentVariables)
{
// EnvironmentVariables is case sensitive? Seriously?
var platformEnvironmentVariables = new List<string>();
foreach (string env in environmentVariables.Keys)
{
if (env.ToUpper() == "PLATFORM")
platformEnvironmentVariables.Add(env);
}
foreach (string env in platformEnvironmentVariables)
environmentVariables.Remove(env);
}
private static bool IsDebugMsBuildRequested()
{
return Environment.GetEnvironmentVariable("GODOT_DEBUG_MSBUILD")?.Trim() == "1";
}
}
}