From 01397a10d9f82e00638eb9b5c200b6dde8e515a9 Mon Sep 17 00:00:00 2001 From: Ignacio Etcheverry Date: Thu, 17 May 2018 01:26:02 +0200 Subject: [PATCH] Mono: Project building fixes - Set (Csc/Vbc/Fsc)ToolExe environment variables to point to the batch files in Mono's bin directory when building with Mono's MSBuild. - Set Mono's MSBuild as the default build tool on Windows. - Generate projects with portable DebugType instead of full. --- .../GodotSharpTools/Build/BuildSystem.cs | 90 ++++++++++---- .../GodotSharpTools/GodotSharpTools.csproj | 4 +- .../Project/ProjectGenerator.cs | 6 +- modules/mono/editor/godotsharp_builds.cpp | 115 ++++++++++++------ modules/mono/editor/godotsharp_builds.h | 5 +- 5 files changed, 150 insertions(+), 70 deletions(-) diff --git a/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs b/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs index 04da0600ccf..f3b4b666634 100644 --- a/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs +++ b/modules/mono/editor/GodotSharpTools/Build/BuildSystem.cs @@ -16,24 +16,48 @@ namespace GodotSharpTools.Build private extern static void godot_icall_BuildInstance_ExitCallback(string solution, string config, int exitCode); [MethodImpl(MethodImplOptions.InternalCall)] - private extern static void godot_icall_BuildInstance_get_MSBuildInfo(ref string msbuildPath, ref string frameworkPath); + private extern static string godot_icall_BuildInstance_get_MSBuildPath(); + [MethodImpl(MethodImplOptions.InternalCall)] + private extern static string godot_icall_BuildInstance_get_FrameworkPath(); + [MethodImpl(MethodImplOptions.InternalCall)] + private extern static string godot_icall_BuildInstance_get_MonoWindowsBinDir(); + [MethodImpl(MethodImplOptions.InternalCall)] + private extern static bool godot_icall_BuildInstance_get_UsingMonoMSBuildOnWindows(); - private struct MSBuildInfo + private static string GetMSBuildPath() { - public string path; - public string frameworkPathOverride; - } + string msbuildPath = godot_icall_BuildInstance_get_MSBuildPath(); - private static MSBuildInfo GetMSBuildInfo() - { - MSBuildInfo msbuildInfo = new MSBuildInfo(); - - godot_icall_BuildInstance_get_MSBuildInfo(ref msbuildInfo.path, ref msbuildInfo.frameworkPathOverride); - - if (msbuildInfo.path == null) + if (msbuildPath == null) throw new FileNotFoundException("Cannot find the MSBuild executable."); - return msbuildInfo; + return msbuildPath; + } + + private static string GetFrameworkPath() + { + return godot_icall_BuildInstance_get_FrameworkPath(); + } + + private static string MonoWindowsBinDir + { + get + { + string monoWinBinDir = godot_icall_BuildInstance_get_MonoWindowsBinDir(); + + if (monoWinBinDir == null) + throw new FileNotFoundException("Cannot find the Windows Mono binaries directory."); + + return monoWinBinDir; + } + } + + private static bool UsingMonoMSBuildOnWindows + { + get + { + return godot_icall_BuildInstance_get_UsingMonoMSBuildOnWindows(); + } } private string solution; @@ -54,25 +78,35 @@ namespace GodotSharpTools.Build public bool Build(string loggerAssemblyPath, string loggerOutputDir, string[] customProperties = null) { - MSBuildInfo msbuildInfo = GetMSBuildInfo(); - List customPropertiesList = new List(); if (customProperties != null) customPropertiesList.AddRange(customProperties); - if (msbuildInfo.frameworkPathOverride != null) - customPropertiesList.Add("FrameworkPathOverride=" + msbuildInfo.frameworkPathOverride); + string frameworkPath = GetFrameworkPath(); + + if (!string.IsNullOrEmpty(frameworkPath)) + customPropertiesList.Add("FrameworkPathOverride=" + frameworkPath); string compilerArgs = BuildArguments(loggerAssemblyPath, loggerOutputDir, customPropertiesList); - ProcessStartInfo startInfo = new ProcessStartInfo(msbuildInfo.path, compilerArgs); + ProcessStartInfo startInfo = new ProcessStartInfo(GetMSBuildPath(), compilerArgs); // No console output, thanks startInfo.RedirectStandardOutput = true; startInfo.RedirectStandardError = true; 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); @@ -98,25 +132,35 @@ namespace GodotSharpTools.Build if (process != null) throw new InvalidOperationException("Already in use"); - MSBuildInfo msbuildInfo = GetMSBuildInfo(); - List customPropertiesList = new List(); if (customProperties != null) customPropertiesList.AddRange(customProperties); - if (msbuildInfo.frameworkPathOverride.Length > 0) - customPropertiesList.Add("FrameworkPathOverride=" + msbuildInfo.frameworkPathOverride); + string frameworkPath = GetFrameworkPath(); + + if (!string.IsNullOrEmpty(frameworkPath)) + customPropertiesList.Add("FrameworkPathOverride=" + frameworkPath); string compilerArgs = BuildArguments(loggerAssemblyPath, loggerOutputDir, customPropertiesList); - ProcessStartInfo startInfo = new ProcessStartInfo(msbuildInfo.path, compilerArgs); + ProcessStartInfo startInfo = new ProcessStartInfo(GetMSBuildPath(), compilerArgs); // No console output, thanks startInfo.RedirectStandardOutput = true; startInfo.RedirectStandardError = true; 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); diff --git a/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj b/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj index 981083a3c20..1c8714e31d6 100644 --- a/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj +++ b/modules/mono/editor/GodotSharpTools/GodotSharpTools.csproj @@ -11,7 +11,7 @@ true - full + portable false bin\Debug DEBUG; @@ -20,7 +20,7 @@ false - full + portable true bin\Release prompt diff --git a/modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs b/modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs index 6bf54a01562..1d863e6f61f 100644 --- a/modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs +++ b/modules/mono/editor/GodotSharpTools/Project/ProjectGenerator.cs @@ -70,7 +70,7 @@ namespace GodotSharpTools.Project var toolsGroup = root.AddPropertyGroup(); toolsGroup.Condition = " '$(Configuration)|$(Platform)' == 'Tools|AnyCPU' "; toolsGroup.AddProperty("DebugSymbols", "true"); - toolsGroup.AddProperty("DebugType", "full"); + toolsGroup.AddProperty("DebugType", "portable"); toolsGroup.AddProperty("Optimize", "false"); toolsGroup.AddProperty("DefineConstants", "DEBUG;TOOLS;"); toolsGroup.AddProperty("ErrorReport", "prompt"); @@ -148,7 +148,7 @@ namespace GodotSharpTools.Project var debugGroup = root.AddPropertyGroup(); debugGroup.Condition = " '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "; debugGroup.AddProperty("DebugSymbols", "true"); - debugGroup.AddProperty("DebugType", "full"); + debugGroup.AddProperty("DebugType", "portable"); debugGroup.AddProperty("Optimize", "false"); debugGroup.AddProperty("DefineConstants", "DEBUG;"); debugGroup.AddProperty("ErrorReport", "prompt"); @@ -157,7 +157,7 @@ namespace GodotSharpTools.Project var releaseGroup = root.AddPropertyGroup(); releaseGroup.Condition = " '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "; - releaseGroup.AddProperty("DebugType", "full"); + releaseGroup.AddProperty("DebugType", "portable"); releaseGroup.AddProperty("Optimize", "true"); releaseGroup.AddProperty("ErrorReport", "prompt"); releaseGroup.AddProperty("WarningLevel", "4"); diff --git a/modules/mono/editor/godotsharp_builds.cpp b/modules/mono/editor/godotsharp_builds.cpp index 2f2b5768dbd..ef54046f121 100644 --- a/modules/mono/editor/godotsharp_builds.cpp +++ b/modules/mono/editor/godotsharp_builds.cpp @@ -39,6 +39,10 @@ #include "bindings_generator.h" #include "godotsharp_editor.h" +#define PROP_NAME_MSBUILD_MONO "MSBuild (Mono)" +#define PROP_NAME_MSBUILD_VS "MSBuild (VS Build Tools)" +#define PROP_NAME_XBUILD "xbuild (Deprecated)" + void godot_icall_BuildInstance_ExitCallback(MonoString *p_solution, MonoString *p_config, int p_exit_code) { String solution = GDMonoMarshal::mono_string_to_godot(p_solution); @@ -76,46 +80,42 @@ String _find_build_engine_on_unix(const String &p_name) { } #endif -void godot_icall_BuildInstance_get_MSBuildInfo(MonoString **r_msbuild_path, MonoString **r_framework_path) { +MonoString *godot_icall_BuildInstance_get_MSBuildPath() { GodotSharpBuilds::BuildTool build_tool = GodotSharpBuilds::BuildTool(int(EditorSettings::get_singleton()->get("mono/builds/build_tool"))); #if defined(WINDOWS_ENABLED) switch (build_tool) { - case GodotSharpBuilds::MSBUILD: { + case GodotSharpBuilds::MSBUILD_VS: { static String msbuild_tools_path = MonoRegUtils::find_msbuild_tools_path(); if (msbuild_tools_path.length()) { if (!msbuild_tools_path.ends_with("\\")) msbuild_tools_path += "\\"; - // FrameworkPathOverride - const MonoRegInfo &mono_reg_info = GDMono::get_singleton()->get_mono_reg_info(); - if (mono_reg_info.assembly_dir.length()) { - *r_msbuild_path = GDMonoMarshal::mono_string_from_godot(msbuild_tools_path + "MSBuild.exe"); - - String framework_path = path_join(mono_reg_info.assembly_dir, "mono", "4.5"); - *r_framework_path = GDMonoMarshal::mono_string_from_godot(framework_path); - } else { - ERR_PRINT("Cannot find Mono's assemblies directory in the registry"); - } - - return; + return GDMonoMarshal::mono_string_from_godot(msbuild_tools_path + "MSBuild.exe"); } if (OS::get_singleton()->is_stdout_verbose()) - OS::get_singleton()->print("Cannot find System's MSBuild. Trying with Mono's...\n"); - } // fall through + OS::get_singleton()->print("Cannot find executable for '" PROP_NAME_MSBUILD_VS "'. Trying with '" PROP_NAME_MSBUILD_MONO "'...\n"); + } // FALL THROUGH case GodotSharpBuilds::MSBUILD_MONO: { String msbuild_path = GDMono::get_singleton()->get_mono_reg_info().bin_dir.plus_file("msbuild.bat"); if (!FileAccess::exists(msbuild_path)) { - WARN_PRINTS("Cannot find msbuild ('mono/builds/build_tool'). Tried with path: " + msbuild_path); + WARN_PRINTS("Cannot find executable for '" PROP_NAME_MSBUILD_MONO "'. Tried with path: " + msbuild_path); } - *r_msbuild_path = GDMonoMarshal::mono_string_from_godot(msbuild_path); + return GDMonoMarshal::mono_string_from_godot(msbuild_path); + } break; + case GodotSharpBuilds::XBUILD: { + String xbuild_path = GDMono::get_singleton()->get_mono_reg_info().bin_dir.plus_file("xbuild.bat"); - return; + if (!FileAccess::exists(xbuild_path)) { + WARN_PRINTS("Cannot find executable for '" PROP_NAME_XBUILD "'. Tried with path: " + xbuild_path); + } + + return GDMonoMarshal::mono_string_from_godot(xbuild_path); } break; default: ERR_EXPLAIN("You don't deserve to live"); @@ -125,31 +125,74 @@ void godot_icall_BuildInstance_get_MSBuildInfo(MonoString **r_msbuild_path, Mono static String msbuild_path = _find_build_engine_on_unix("msbuild"); static String xbuild_path = _find_build_engine_on_unix("xbuild"); - if (build_tool != GodotSharpBuilds::XBUILD) { - if (msbuild_path.empty()) { - WARN_PRINT("Cannot find msbuild ('mono/builds/build_tool')."); + if (build_tool == GodotSharpBuilds::XBUILD) { + if (xbuild_path.empty()) { + WARN_PRINT("Cannot find binary for '" PROP_NAME_XBUILD "'"); return; } } else { - if (xbuild_path.empty()) { - WARN_PRINT("Cannot find xbuild ('mono/builds/build_tool')."); + if (msbuild_path.empty()) { + WARN_PRINT("Cannot find binary for '" PROP_NAME_MSBUILD_MONO "'"); return; } } - *r_msbuild_path = GDMonoMarshal::mono_string_from_godot(build_tool != GodotSharpBuilds::XBUILD ? msbuild_path : xbuild_path); - - return; + return GDMonoMarshal::mono_string_from_godot(build_tool != GodotSharpBuilds::XBUILD ? msbuild_path : xbuild_path); #else - ERR_PRINT("Not implemented on this platform"); - return; + (void)build_tool; // UNUSED + + ERR_EXPLAIN("Not implemented on this platform"); + ERR_FAIL_V(NULL); +#endif +} + +MonoString *godot_icall_BuildInstance_get_FrameworkPath() { + +#if defined(WINDOWS_ENABLED) + const MonoRegInfo &mono_reg_info = GDMono::get_singleton()->get_mono_reg_info(); + if (mono_reg_info.assembly_dir.length()) { + String framework_path = path_join(mono_reg_info.assembly_dir, "mono", "4.5"); + return GDMonoMarshal::mono_string_from_godot(framework_path); + } + + ERR_EXPLAIN("Cannot find Mono's assemblies directory in the registry"); + ERR_FAIL_V(NULL); +#else + return NULL; +#endif +} + +MonoString *godot_icall_BuildInstance_get_MonoWindowsBinDir() { + +#if defined(WINDOWS_ENABLED) + const MonoRegInfo &mono_reg_info = GDMono::get_singleton()->get_mono_reg_info(); + if (mono_reg_info.bin_dir.length()) { + return GDMonoMarshal::mono_string_from_godot(mono_reg_info.bin_dir); + } + + ERR_EXPLAIN("Cannot find Mono's binaries directory in the registry"); + ERR_FAIL_V(NULL); +#else + return NULL; +#endif +} + +MonoBoolean godot_icall_BuildInstance_get_UsingMonoMSBuildOnWindows() { + +#if defined(WINDOWS_ENABLED) + return GodotSharpBuilds::BuildTool(int(EditorSettings::get_singleton()->get("mono/builds/build_tool"))) == GodotSharpBuilds::MSBUILD_MONO; +#else + return false; #endif } void GodotSharpBuilds::_register_internal_calls() { mono_add_internal_call("GodotSharpTools.Build.BuildSystem::godot_icall_BuildInstance_ExitCallback", (void *)godot_icall_BuildInstance_ExitCallback); - mono_add_internal_call("GodotSharpTools.Build.BuildInstance::godot_icall_BuildInstance_get_MSBuildInfo", (void *)godot_icall_BuildInstance_get_MSBuildInfo); + mono_add_internal_call("GodotSharpTools.Build.BuildInstance::godot_icall_BuildInstance_get_MSBuildPath", (void *)godot_icall_BuildInstance_get_MSBuildPath); + mono_add_internal_call("GodotSharpTools.Build.BuildInstance::godot_icall_BuildInstance_get_FrameworkPath", (void *)godot_icall_BuildInstance_get_FrameworkPath); + mono_add_internal_call("GodotSharpTools.Build.BuildInstance::godot_icall_BuildInstance_get_MonoWindowsBinDir", (void *)godot_icall_BuildInstance_get_MonoWindowsBinDir); + mono_add_internal_call("GodotSharpTools.Build.BuildInstance::godot_icall_BuildInstance_get_UsingMonoMSBuildOnWindows", (void *)godot_icall_BuildInstance_get_UsingMonoMSBuildOnWindows); } void GodotSharpBuilds::show_build_error_dialog(const String &p_message) { @@ -386,20 +429,14 @@ GodotSharpBuilds::GodotSharpBuilds() { // Build tool settings EditorSettings *ed_settings = EditorSettings::get_singleton(); -#ifdef WINDOWS_ENABLED - // TODO: Default to MSBUILD_MONO if its csc.exe issue is fixed in the installed mono version - EDITOR_DEF("mono/builds/build_tool", MSBUILD); -#else EDITOR_DEF("mono/builds/build_tool", MSBUILD_MONO); -#endif ed_settings->add_property_hint(PropertyInfo(Variant::INT, "mono/builds/build_tool", PROPERTY_HINT_ENUM, + PROP_NAME_MSBUILD_MONO #ifdef WINDOWS_ENABLED - "MSBuild (Mono),MSBuild (System)" -#else - "MSBuild (Mono),xbuild (Deprecated)" + "," PROP_NAME_MSBUILD_VS #endif - )); + "," PROP_NAME_XBUILD)); } GodotSharpBuilds::~GodotSharpBuilds() { diff --git a/modules/mono/editor/godotsharp_builds.h b/modules/mono/editor/godotsharp_builds.h index 27b771e3241..4afc284d45d 100644 --- a/modules/mono/editor/godotsharp_builds.h +++ b/modules/mono/editor/godotsharp_builds.h @@ -68,10 +68,9 @@ public: enum BuildTool { MSBUILD_MONO, #ifdef WINDOWS_ENABLED - MSBUILD -#else - XBUILD // Deprecated + MSBUILD_VS, #endif + XBUILD // Deprecated }; _FORCE_INLINE_ static GodotSharpBuilds *get_singleton() { return singleton; }