godot/modules/mono/editor/godotsharp_builds.cpp

633 lines
22 KiB
C++
Raw Normal View History

2017-10-02 21:24:00 +00:00
/*************************************************************************/
/* godotsharp_builds.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
2017-10-02 21:24:00 +00:00
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
2017-10-02 21:24:00 +00:00
#include "godotsharp_builds.h"
#include "core/os/os.h"
#include "core/vector.h"
#include "main/main.h"
2018-09-12 00:50:16 +00:00
#include "../glue/cs_glue_version.gen.h"
2017-10-02 21:24:00 +00:00
#include "../godotsharp_dirs.h"
#include "../mono_gd/gd_mono_class.h"
#include "../mono_gd/gd_mono_marshal.h"
#include "../utils/path_utils.h"
#include "bindings_generator.h"
#include "csharp_project.h"
2017-10-02 21:24:00 +00:00
#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)"
2017-10-02 21:24:00 +00:00
void godot_icall_BuildInstance_ExitCallback(MonoString *p_solution, MonoString *p_config, int p_exit_code) {
String solution = GDMonoMarshal::mono_string_to_godot(p_solution);
String config = GDMonoMarshal::mono_string_to_godot(p_config);
GodotSharpBuilds::get_singleton()->build_exit_callback(MonoBuildInfo(solution, config), p_exit_code);
}
static Vector<const char *> _get_msbuild_hint_dirs() {
Vector<const char *> ret;
#ifdef OSX_ENABLED
ret.push_back("/Library/Frameworks/Mono.framework/Versions/Current/bin/");
ret.push_back("/usr/local/var/homebrew/linked/mono/bin/");
#endif
ret.push_back("/opt/novell/mono/bin/");
return ret;
}
#ifdef UNIX_ENABLED
String _find_build_engine_on_unix(const String &p_name) {
String ret = path_which(p_name);
if (ret.length())
return ret;
String ret_fallback = path_which(p_name + ".exe");
if (ret_fallback.length())
return ret_fallback;
static Vector<const char *> locations = _get_msbuild_hint_dirs();
for (int i = 0; i < locations.size(); i++) {
String hint_path = locations[i] + p_name;
if (FileAccess::exists(hint_path)) {
return hint_path;
}
}
return String();
}
#endif
MonoString *godot_icall_BuildInstance_get_MSBuildPath() {
2017-10-02 21:24:00 +00:00
GodotSharpBuilds::BuildTool build_tool = GodotSharpBuilds::BuildTool(int(EditorSettings::get_singleton()->get("mono/builds/build_tool")));
#if defined(WINDOWS_ENABLED)
2017-10-02 21:24:00 +00:00
switch (build_tool) {
case GodotSharpBuilds::MSBUILD_VS: {
static String msbuild_tools_path;
if (msbuild_tools_path.empty() || !FileAccess::exists(msbuild_tools_path)) {
// Try to search it again if it wasn't found last time or if it was removed from its location
msbuild_tools_path = MonoRegUtils::find_msbuild_tools_path();
2017-10-02 21:24:00 +00:00
if (msbuild_tools_path.empty()) {
ERR_PRINTS("Cannot find executable for '" PROP_NAME_MSBUILD_VS "'. Tried with path: " + msbuild_tools_path);
return NULL;
}
2017-10-02 21:24:00 +00:00
}
if (!msbuild_tools_path.ends_with("\\"))
msbuild_tools_path += "\\";
return GDMonoMarshal::mono_string_from_godot(msbuild_tools_path + "MSBuild.exe");
} break;
2017-10-02 21:24:00 +00:00
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)) {
ERR_PRINTS("Cannot find executable for '" PROP_NAME_MSBUILD_MONO "'. Tried with path: " + msbuild_path);
return NULL;
2017-10-02 21:24:00 +00:00
}
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");
2017-10-29 09:11:20 +00:00
if (!FileAccess::exists(xbuild_path)) {
ERR_PRINTS("Cannot find executable for '" PROP_NAME_XBUILD "'. Tried with path: " + xbuild_path);
return NULL;
}
return GDMonoMarshal::mono_string_from_godot(xbuild_path);
} break;
2017-10-02 21:24:00 +00:00
default:
ERR_EXPLAIN("You don't deserve to live");
CRASH_NOW();
}
#elif defined(UNIX_ENABLED)
static String msbuild_path;
static String xbuild_path;
if (build_tool == GodotSharpBuilds::XBUILD) {
if (xbuild_path.empty() || !FileAccess::exists(xbuild_path)) {
// Try to search it again if it wasn't found last time or if it was removed from its location
xbuild_path = _find_build_engine_on_unix("msbuild");
}
if (xbuild_path.empty()) {
ERR_PRINT("Cannot find binary for '" PROP_NAME_XBUILD "'");
return NULL;
}
} else {
if (msbuild_path.empty() || !FileAccess::exists(msbuild_path)) {
// Try to search it again if it wasn't found last time or if it was removed from its location
msbuild_path = _find_build_engine_on_unix("msbuild");
}
if (msbuild_path.empty()) {
ERR_PRINT("Cannot find binary for '" PROP_NAME_MSBUILD_MONO "'");
return NULL;
}
2017-10-02 21:24:00 +00:00
}
return GDMonoMarshal::mono_string_from_godot(build_tool != GodotSharpBuilds::XBUILD ? msbuild_path : xbuild_path);
#else
(void)build_tool; // UNUSED
ERR_EXPLAIN("Not implemented on this platform");
ERR_FAIL_V(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;
2017-10-02 21:24:00 +00:00
#endif
}
MonoBoolean godot_icall_BuildInstance_get_PrintBuildOutput() {
return (bool)EDITOR_GET("mono/builds/print_build_output");
}
void GodotSharpBuilds::register_internal_calls() {
static bool registered = false;
ERR_FAIL_COND(registered);
registered = true;
2017-10-02 21:24:00 +00:00
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_MSBuildPath", (void *)godot_icall_BuildInstance_get_MSBuildPath);
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);
mono_add_internal_call("GodotSharpTools.Build.BuildInstance::godot_icall_BuildInstance_get_PrintBuildOutput", (void *)godot_icall_BuildInstance_get_PrintBuildOutput);
2017-10-02 21:24:00 +00:00
}
void GodotSharpBuilds::show_build_error_dialog(const String &p_message) {
GodotSharpEditor::get_singleton()->show_error_dialog(p_message, "Build error");
MonoBottomPanel::get_singleton()->show_build_tab();
}
bool GodotSharpBuilds::build_api_sln(const String &p_api_sln_dir, const String &p_config) {
2017-10-02 21:24:00 +00:00
String api_sln_file = p_api_sln_dir.plus_file(API_SOLUTION_NAME ".sln");
2017-10-02 21:24:00 +00:00
String core_api_assembly_dir = p_api_sln_dir.plus_file(CORE_API_ASSEMBLY_NAME).plus_file("bin").plus_file(p_config);
String core_api_assembly_file = core_api_assembly_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll");
String editor_api_assembly_dir = p_api_sln_dir.plus_file(EDITOR_API_ASSEMBLY_NAME).plus_file("bin").plus_file(p_config);
String editor_api_assembly_file = editor_api_assembly_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll");
if (!FileAccess::exists(core_api_assembly_file) || !FileAccess::exists(editor_api_assembly_file)) {
2017-10-02 21:24:00 +00:00
MonoBuildInfo api_build_info(api_sln_file, p_config);
// TODO Replace this global NoWarn with '#pragma warning' directives on generated files,
// once we start to actively document manually maintained C# classes
2017-10-02 21:24:00 +00:00
api_build_info.custom_props.push_back("NoWarn=1591"); // Ignore missing documentation warnings
if (!GodotSharpBuilds::get_singleton()->build(api_build_info)) {
show_build_error_dialog("Failed to build " API_SOLUTION_NAME " solution.");
2017-10-02 21:24:00 +00:00
return false;
}
}
return true;
}
bool GodotSharpBuilds::copy_api_assembly(const String &p_src_dir, const String &p_dst_dir, const String &p_assembly_name, APIAssembly::Type p_api_type) {
2017-10-02 21:24:00 +00:00
Mono: Editor and export template dependencies and fixes - Bundle editor dependencies: - 'GodotSharp': Root data directory for the editor - 'Tools': Editor dependencies. Only GodotSharp.dll for now. - 'Api': Prebuilt GodotSharp and GodotSharpEditor API assemblies. - 'Mono': Mono files to bundle with the editor. - 'bin': (Optional, not used for now) Mono bin directory. - 'etc': Mono configuration files. - 'lib': Mono dependency shared libraries. - 'lib/mono/4.5': Framework assemblies. - Added build option to copy the required files from the mono installation to 'GodotSharp/Mono'. Enable with 'copy_mono_root=yes'. Disabled by default. - Export template dependencies: - 'data_AppName'/'data_Godot': - 'Mono': Mono files to bundle with the game. - 'etc': Mono configuration files. - 'lib': Mono dependency shared libraries. - The data directory is generated when compiling and must be bundled with the export templates. In the case of OSX, the data directory must be placed inside the 'osx.zip' export template. - In OSX, alternative location for directories (needed for app bundles) are: - 'data_AppName/Mono/etc' --> '../Resources/GodotSharp/Mono/etc' - 'data_AppName/Mono/lib' --> '../Frameworks/GodotSharp/Mono/lib' - The editor can bundle prebuilt API assemblies. - Generate them with a tools build by running: `--generate-cs-core-api <GodotSharp_OutputDir> --generate-cs-editor-api <GodotSharpEditor_OutputDir> <GodotSharp_OutputDir>/bin/Release/GodotSharp.dll` (This command will be simplified in the future and both projects will be in the same solution) - Build the solutions and copy the output files to '#bin/GodotSharp/Api'. - Fixed API assembly being added twice during the export process.
2018-10-03 17:01:57 +00:00
// Create destination directory if needed
if (!DirAccess::exists(p_dst_dir)) {
DirAccess *da = DirAccess::create_for_path(p_dst_dir);
Error err = da->make_dir_recursive(p_dst_dir);
memdelete(da);
if (err != OK) {
show_build_error_dialog("Failed to create destination directory for the API assemblies. Error: " + itos(err));
return false;
}
}
2017-10-02 21:24:00 +00:00
String assembly_file = p_assembly_name + ".dll";
String assembly_src = p_src_dir.plus_file(assembly_file);
String assembly_dst = p_dst_dir.plus_file(assembly_file);
if (!FileAccess::exists(assembly_dst) ||
FileAccess::get_modified_time(assembly_src) > FileAccess::get_modified_time(assembly_dst) ||
GDMono::get_singleton()->metadata_is_api_assembly_invalidated(p_api_type)) {
DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
2017-10-02 21:24:00 +00:00
String xml_file = p_assembly_name + ".xml";
if (da->copy(p_src_dir.plus_file(xml_file), p_dst_dir.plus_file(xml_file)) != OK)
WARN_PRINTS("Failed to copy " + xml_file);
String pdb_file = p_assembly_name + ".pdb";
if (da->copy(p_src_dir.plus_file(pdb_file), p_dst_dir.plus_file(pdb_file)) != OK)
WARN_PRINTS("Failed to copy " + pdb_file);
Error err = da->copy(assembly_src, assembly_dst);
if (err != OK) {
2018-02-22 12:39:41 +00:00
show_build_error_dialog("Failed to copy " + assembly_file);
2017-10-02 21:24:00 +00:00
return false;
}
GDMono::get_singleton()->metadata_set_api_assembly_invalidated(p_api_type, false);
2017-10-02 21:24:00 +00:00
}
return true;
}
String GodotSharpBuilds::_api_folder_name(APIAssembly::Type p_api_type) {
uint64_t api_hash = p_api_type == APIAssembly::API_CORE ?
GDMono::get_singleton()->get_api_core_hash() :
GDMono::get_singleton()->get_api_editor_hash();
return String::num_uint64(api_hash) +
"_" + String::num_uint64(BindingsGenerator::get_version()) +
2018-09-12 00:50:16 +00:00
"_" + String::num_uint64(CS_GLUE_VERSION);
}
2017-10-02 21:24:00 +00:00
bool GodotSharpBuilds::make_api_assembly(APIAssembly::Type p_api_type) {
String api_name = p_api_type == APIAssembly::API_CORE ? CORE_API_ASSEMBLY_NAME : EDITOR_API_ASSEMBLY_NAME;
String editor_prebuilt_api_dir = GodotSharpDirs::get_data_editor_prebuilt_api_dir();
String res_assemblies_dir = GodotSharpDirs::get_res_assemblies_dir();
if (FileAccess::exists(editor_prebuilt_api_dir.plus_file(api_name + ".dll"))) {
EditorProgress pr("mono_copy_prebuilt_api_assembly", "Copying prebuilt " + api_name + " assembly...", 1);
pr.step("Copying " + api_name + " assembly", 0);
return GodotSharpBuilds::copy_api_assembly(editor_prebuilt_api_dir, res_assemblies_dir, api_name, p_api_type);
}
2017-10-02 21:24:00 +00:00
String api_build_config = "Release";
EditorProgress pr("mono_build_release_" API_SOLUTION_NAME, "Building " API_SOLUTION_NAME " solution...", 3);
2017-10-02 21:24:00 +00:00
pr.step("Generating " API_SOLUTION_NAME " solution", 0);
2017-10-02 21:24:00 +00:00
String api_sln_dir = GodotSharpDirs::get_mono_solutions_dir()
.plus_file(_api_folder_name(APIAssembly::API_CORE));
2017-10-02 21:24:00 +00:00
String api_sln_file = api_sln_dir.plus_file(API_SOLUTION_NAME ".sln");
2017-10-02 21:24:00 +00:00
if (!DirAccess::exists(api_sln_dir) || !FileAccess::exists(api_sln_file)) {
BindingsGenerator bindings_generator;
2017-10-02 21:24:00 +00:00
if (!OS::get_singleton()->is_stdout_verbose()) {
bindings_generator.set_log_print_enabled(false);
}
Error err = bindings_generator.generate_cs_api(api_sln_dir);
2017-10-02 21:24:00 +00:00
if (err != OK) {
show_build_error_dialog("Failed to generate " API_SOLUTION_NAME " solution. Error: " + itos(err));
2017-10-02 21:24:00 +00:00
return false;
}
}
pr.step("Building " API_SOLUTION_NAME " solution", 1);
2017-10-02 21:24:00 +00:00
if (!GodotSharpBuilds::build_api_sln(api_sln_dir, api_build_config))
2017-10-02 21:24:00 +00:00
return false;
Mono: Editor and export template dependencies and fixes - Bundle editor dependencies: - 'GodotSharp': Root data directory for the editor - 'Tools': Editor dependencies. Only GodotSharp.dll for now. - 'Api': Prebuilt GodotSharp and GodotSharpEditor API assemblies. - 'Mono': Mono files to bundle with the editor. - 'bin': (Optional, not used for now) Mono bin directory. - 'etc': Mono configuration files. - 'lib': Mono dependency shared libraries. - 'lib/mono/4.5': Framework assemblies. - Added build option to copy the required files from the mono installation to 'GodotSharp/Mono'. Enable with 'copy_mono_root=yes'. Disabled by default. - Export template dependencies: - 'data_AppName'/'data_Godot': - 'Mono': Mono files to bundle with the game. - 'etc': Mono configuration files. - 'lib': Mono dependency shared libraries. - The data directory is generated when compiling and must be bundled with the export templates. In the case of OSX, the data directory must be placed inside the 'osx.zip' export template. - In OSX, alternative location for directories (needed for app bundles) are: - 'data_AppName/Mono/etc' --> '../Resources/GodotSharp/Mono/etc' - 'data_AppName/Mono/lib' --> '../Frameworks/GodotSharp/Mono/lib' - The editor can bundle prebuilt API assemblies. - Generate them with a tools build by running: `--generate-cs-core-api <GodotSharp_OutputDir> --generate-cs-editor-api <GodotSharpEditor_OutputDir> <GodotSharp_OutputDir>/bin/Release/GodotSharp.dll` (This command will be simplified in the future and both projects will be in the same solution) - Build the solutions and copy the output files to '#bin/GodotSharp/Api'. - Fixed API assembly being added twice during the export process.
2018-10-03 17:01:57 +00:00
pr.step("Copying " + api_name + " assembly", 2);
2017-10-02 21:24:00 +00:00
// Copy the built assembly to the assemblies directory
String api_assembly_dir = api_sln_dir.plus_file(api_name).plus_file("bin").plus_file(api_build_config);
if (!GodotSharpBuilds::copy_api_assembly(api_assembly_dir, res_assemblies_dir, api_name, p_api_type))
2017-10-02 21:24:00 +00:00
return false;
return true;
}
bool GodotSharpBuilds::build_project_blocking(const String &p_config, const Vector<String> &p_godot_defines) {
2017-10-02 21:24:00 +00:00
if (!FileAccess::exists(GodotSharpDirs::get_project_sln_path()))
return true; // No solution to build
if (!GodotSharpBuilds::make_api_assembly(APIAssembly::API_CORE))
return false;
Mono: Editor and export template dependencies and fixes - Bundle editor dependencies: - 'GodotSharp': Root data directory for the editor - 'Tools': Editor dependencies. Only GodotSharp.dll for now. - 'Api': Prebuilt GodotSharp and GodotSharpEditor API assemblies. - 'Mono': Mono files to bundle with the editor. - 'bin': (Optional, not used for now) Mono bin directory. - 'etc': Mono configuration files. - 'lib': Mono dependency shared libraries. - 'lib/mono/4.5': Framework assemblies. - Added build option to copy the required files from the mono installation to 'GodotSharp/Mono'. Enable with 'copy_mono_root=yes'. Disabled by default. - Export template dependencies: - 'data_AppName'/'data_Godot': - 'Mono': Mono files to bundle with the game. - 'etc': Mono configuration files. - 'lib': Mono dependency shared libraries. - The data directory is generated when compiling and must be bundled with the export templates. In the case of OSX, the data directory must be placed inside the 'osx.zip' export template. - In OSX, alternative location for directories (needed for app bundles) are: - 'data_AppName/Mono/etc' --> '../Resources/GodotSharp/Mono/etc' - 'data_AppName/Mono/lib' --> '../Frameworks/GodotSharp/Mono/lib' - The editor can bundle prebuilt API assemblies. - Generate them with a tools build by running: `--generate-cs-core-api <GodotSharp_OutputDir> --generate-cs-editor-api <GodotSharpEditor_OutputDir> <GodotSharp_OutputDir>/bin/Release/GodotSharp.dll` (This command will be simplified in the future and both projects will be in the same solution) - Build the solutions and copy the output files to '#bin/GodotSharp/Api'. - Fixed API assembly being added twice during the export process.
2018-10-03 17:01:57 +00:00
if (!GodotSharpBuilds::make_api_assembly(APIAssembly::API_EDITOR))
return false;
Mono: Editor and export template dependencies and fixes - Bundle editor dependencies: - 'GodotSharp': Root data directory for the editor - 'Tools': Editor dependencies. Only GodotSharp.dll for now. - 'Api': Prebuilt GodotSharp and GodotSharpEditor API assemblies. - 'Mono': Mono files to bundle with the editor. - 'bin': (Optional, not used for now) Mono bin directory. - 'etc': Mono configuration files. - 'lib': Mono dependency shared libraries. - 'lib/mono/4.5': Framework assemblies. - Added build option to copy the required files from the mono installation to 'GodotSharp/Mono'. Enable with 'copy_mono_root=yes'. Disabled by default. - Export template dependencies: - 'data_AppName'/'data_Godot': - 'Mono': Mono files to bundle with the game. - 'etc': Mono configuration files. - 'lib': Mono dependency shared libraries. - The data directory is generated when compiling and must be bundled with the export templates. In the case of OSX, the data directory must be placed inside the 'osx.zip' export template. - In OSX, alternative location for directories (needed for app bundles) are: - 'data_AppName/Mono/etc' --> '../Resources/GodotSharp/Mono/etc' - 'data_AppName/Mono/lib' --> '../Frameworks/GodotSharp/Mono/lib' - The editor can bundle prebuilt API assemblies. - Generate them with a tools build by running: `--generate-cs-core-api <GodotSharp_OutputDir> --generate-cs-editor-api <GodotSharpEditor_OutputDir> <GodotSharp_OutputDir>/bin/Release/GodotSharp.dll` (This command will be simplified in the future and both projects will be in the same solution) - Build the solutions and copy the output files to '#bin/GodotSharp/Api'. - Fixed API assembly being added twice during the export process.
2018-10-03 17:01:57 +00:00
EditorProgress pr("mono_project_debug_build", "Building project solution...", 1);
pr.step("Building project solution", 0);
2017-10-02 21:24:00 +00:00
2018-02-22 12:39:41 +00:00
MonoBuildInfo build_info(GodotSharpDirs::get_project_sln_path(), p_config);
// Add Godot defines
#ifdef WINDOWS_ENABLED
String constants = "GodotDefineConstants=\"";
#else
String constants = "GodotDefineConstants=\\\"";
#endif
for (int i = 0; i < p_godot_defines.size(); i++) {
constants += "GODOT_" + p_godot_defines[i].to_upper().replace("-", "_").replace(" ", "_").replace(";", "_") + ";";
}
#ifdef REAL_T_IS_DOUBLE
constants += "GODOT_REAL_T_IS_DOUBLE;";
#endif
#ifdef WINDOWS_ENABLED
constants += "\"";
#else
constants += "\\\"";
#endif
build_info.custom_props.push_back(constants);
2017-10-02 21:24:00 +00:00
if (!GodotSharpBuilds::get_singleton()->build(build_info)) {
GodotSharpBuilds::show_build_error_dialog("Failed to build project solution");
return false;
}
return true;
}
2018-02-22 12:39:41 +00:00
bool GodotSharpBuilds::editor_build_callback() {
if (!FileAccess::exists(GodotSharpDirs::get_project_sln_path()))
return true; // No solution to build
String scripts_metadata_path_editor = GodotSharpDirs::get_res_metadata_dir().plus_file("scripts_metadata.editor");
String scripts_metadata_path_player = GodotSharpDirs::get_res_metadata_dir().plus_file("scripts_metadata.editor_player");
Error metadata_err = CSharpProject::generate_scripts_metadata(GodotSharpDirs::get_project_csproj_path(), scripts_metadata_path_editor);
ERR_FAIL_COND_V(metadata_err != OK, false);
if (FileAccess::exists(scripts_metadata_path_editor)) {
DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
Error copy_err = da->copy(scripts_metadata_path_editor, scripts_metadata_path_player);
ERR_EXPLAIN("Failed to copy scripts metadata file");
ERR_FAIL_COND_V(copy_err != OK, false);
}
Vector<String> godot_defines;
godot_defines.push_back(OS::get_singleton()->get_name());
godot_defines.push_back(sizeof(void *) == 4 ? "32" : "64");
return build_project_blocking("Tools", godot_defines);
2018-02-22 12:39:41 +00:00
}
2017-10-02 21:24:00 +00:00
GodotSharpBuilds *GodotSharpBuilds::singleton = NULL;
void GodotSharpBuilds::build_exit_callback(const MonoBuildInfo &p_build_info, int p_exit_code) {
BuildProcess *match = builds.getptr(p_build_info);
ERR_FAIL_NULL(match);
2017-10-02 21:24:00 +00:00
BuildProcess &bp = *match;
bp.on_exit(p_exit_code);
}
void GodotSharpBuilds::restart_build(MonoBuildTab *p_build_tab) {
}
void GodotSharpBuilds::stop_build(MonoBuildTab *p_build_tab) {
}
bool GodotSharpBuilds::build(const MonoBuildInfo &p_build_info) {
BuildProcess *match = builds.getptr(p_build_info);
if (match) {
BuildProcess &bp = *match;
bp.start(true);
return bp.exit_code == 0;
} else {
BuildProcess bp = BuildProcess(p_build_info);
bp.start(true);
builds.set(p_build_info, bp);
return bp.exit_code == 0;
}
}
bool GodotSharpBuilds::build_async(const MonoBuildInfo &p_build_info, GodotSharpBuild_ExitCallback p_callback) {
BuildProcess *match = builds.getptr(p_build_info);
if (match) {
BuildProcess &bp = *match;
bp.start();
return !bp.exited; // failed to start
} else {
BuildProcess bp = BuildProcess(p_build_info, p_callback);
bp.start();
builds.set(p_build_info, bp);
return !bp.exited; // failed to start
}
}
GodotSharpBuilds::GodotSharpBuilds() {
singleton = this;
2018-02-22 12:39:41 +00:00
EditorNode::get_singleton()->add_build_callback(&GodotSharpBuilds::editor_build_callback);
2017-10-02 21:24:00 +00:00
// Build tool settings
EditorSettings *ed_settings = EditorSettings::get_singleton();
#ifdef WINDOWS_ENABLED
EDITOR_DEF("mono/builds/build_tool", MSBUILD_VS);
#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
"," PROP_NAME_MSBUILD_VS
#endif
"," PROP_NAME_XBUILD));
EDITOR_DEF("mono/builds/print_build_output", false);
2017-10-02 21:24:00 +00:00
}
GodotSharpBuilds::~GodotSharpBuilds() {
singleton = NULL;
}
void GodotSharpBuilds::BuildProcess::on_exit(int p_exit_code) {
exited = true;
exit_code = p_exit_code;
build_tab->on_build_exit(p_exit_code == 0 ? MonoBuildTab::RESULT_SUCCESS : MonoBuildTab::RESULT_ERROR);
build_instance.unref();
if (exit_callback)
exit_callback(exit_code);
}
void GodotSharpBuilds::BuildProcess::start(bool p_blocking) {
_GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN)
exit_code = -1;
String log_dirpath = build_info.get_log_dirpath();
2017-10-02 21:24:00 +00:00
if (build_tab) {
build_tab->on_build_start();
} else {
build_tab = memnew(MonoBuildTab(build_info, log_dirpath));
2017-10-02 21:24:00 +00:00
MonoBottomPanel::get_singleton()->add_build_tab(build_tab);
}
if (p_blocking) {
// Required in order to update the build tasks list
Main::iteration();
}
if (!exited) {
exited = true;
String message = "Tried to start build process, but it is already running";
build_tab->on_build_exec_failed(message);
ERR_EXPLAIN(message);
ERR_FAIL();
2017-10-02 21:24:00 +00:00
}
exited = false;
// Remove old issues file
2019-01-28 23:02:35 +00:00
String issues_file = get_msbuild_issues_filename();
DirAccessRef d = DirAccess::create_for_path(log_dirpath);
2017-10-02 21:24:00 +00:00
if (d->file_exists(issues_file)) {
Error err = d->remove(issues_file);
if (err != OK) {
exited = true;
String file_path = ProjectSettings::get_singleton()->localize_path(log_dirpath).plus_file(issues_file);
String message = "Cannot remove issues file: " + file_path;
build_tab->on_build_exec_failed(message);
ERR_EXPLAIN(message);
ERR_FAIL();
2017-10-02 21:24:00 +00:00
}
}
GDMonoClass *klass = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Build", "BuildInstance");
MonoObject *mono_object = mono_object_new(mono_domain_get(), klass->get_mono_ptr());
2017-10-02 21:24:00 +00:00
// Construct
Variant solution = build_info.solution;
Variant config = build_info.configuration;
const Variant *ctor_args[2] = { &solution, &config };
2018-06-26 19:03:42 +00:00
MonoException *exc = NULL;
2017-10-02 21:24:00 +00:00
GDMonoMethod *ctor = klass->get_method(".ctor", 2);
2018-06-26 19:03:42 +00:00
ctor->invoke(mono_object, ctor_args, &exc);
2017-10-02 21:24:00 +00:00
2018-06-26 19:03:42 +00:00
if (exc) {
2017-10-02 21:24:00 +00:00
exited = true;
2018-06-26 19:03:42 +00:00
GDMonoUtils::debug_unhandled_exception(exc);
String message = "The build constructor threw an exception.\n" + GDMonoUtils::get_exception_name_and_message(exc);
build_tab->on_build_exec_failed(message);
ERR_EXPLAIN(message);
2017-10-02 21:24:00 +00:00
ERR_FAIL();
}
// Call Build
String logger_assembly_path = GDMono::get_singleton()->get_editor_tools_assembly()->get_path();
Variant logger_assembly = ProjectSettings::get_singleton()->globalize_path(logger_assembly_path);
Variant logger_output_dir = log_dirpath;
2017-10-02 21:24:00 +00:00
Variant custom_props = build_info.custom_props;
const Variant *args[3] = { &logger_assembly, &logger_output_dir, &custom_props };
2018-06-26 19:03:42 +00:00
exc = NULL;
2017-10-02 21:24:00 +00:00
GDMonoMethod *build_method = klass->get_method(p_blocking ? "Build" : "BuildAsync", 3);
2018-06-26 19:03:42 +00:00
build_method->invoke(mono_object, args, &exc);
2017-10-02 21:24:00 +00:00
2018-06-26 19:03:42 +00:00
if (exc) {
2017-10-02 21:24:00 +00:00
exited = true;
2018-06-26 19:03:42 +00:00
GDMonoUtils::debug_unhandled_exception(exc);
String message = "The build method threw an exception.\n" + GDMonoUtils::get_exception_name_and_message(exc);
build_tab->on_build_exec_failed(message);
ERR_EXPLAIN(message);
2017-10-02 21:24:00 +00:00
ERR_FAIL();
}
// Build returned
if (p_blocking) {
exited = true;
exit_code = klass->get_field("exitCode")->get_int_value(mono_object);
2017-10-06 23:21:11 +00:00
if (exit_code != 0) {
2019-01-28 23:02:35 +00:00
String log_filepath = build_info.get_log_dirpath().plus_file(get_msbuild_log_filename());
print_verbose("MSBuild exited with code: " + itos(exit_code) + ". Log file: " + log_filepath);
}
2017-10-06 23:21:11 +00:00
2017-10-02 21:24:00 +00:00
build_tab->on_build_exit(exit_code == 0 ? MonoBuildTab::RESULT_SUCCESS : MonoBuildTab::RESULT_ERROR);
} else {
build_instance = MonoGCHandle::create_strong(mono_object);
exited = false;
}
}
GodotSharpBuilds::BuildProcess::BuildProcess(const MonoBuildInfo &p_build_info, GodotSharpBuild_ExitCallback p_callback) :
build_info(p_build_info),
build_tab(NULL),
exit_callback(p_callback),
exited(true),
exit_code(-1) {
2017-10-02 21:24:00 +00:00
}