Improve the C# API projects generation

- Now there is only one solution that contains both GodotSharp and GodotSharpEditor project. Previously we had one solution for each project
- GodotSharpEditor reference GodotShatp with a 'ProjectReference'. Previously it was a 'Reference' to the assembly
- This also simplifies the command line option to generate this solution: 'godot --generate-cs-api <OutputDir>'
This commit is contained in:
Ignacio Etcheverry 2018-11-08 01:05:19 +01:00
parent 2cf02f302f
commit 02d5ff4cd0
15 changed files with 238 additions and 208 deletions

View file

@ -2770,7 +2770,8 @@ Error ResourceFormatSaverCSharpScript::save(const String &p_path, const RES &p_r
"Compile", "Compile",
ProjectSettings::get_singleton()->globalize_path(p_path)); ProjectSettings::get_singleton()->globalize_path(p_path));
} else { } else {
ERR_PRINTS("Cannot add " + p_path + " to the C# project because it could not be created."); ERR_PRINTS("Failed to create C# project");
ERR_PRINTS("Cannot add " + p_path + " to the C# project");
} }
} }
#endif #endif

View file

@ -6,22 +6,24 @@ namespace GodotSharpTools.Project
{ {
public static class ProjectGenerator public static class ProjectGenerator
{ {
public const string CoreApiProjectName = "GodotSharp";
public const string EditorApiProjectName = "GodotSharpEditor";
const string CoreApiProjectGuid = "{AEBF0036-DA76-4341-B651-A3F2856AB2FA}"; const string CoreApiProjectGuid = "{AEBF0036-DA76-4341-B651-A3F2856AB2FA}";
const string EditorApiProjectGuid = "{8FBEC238-D944-4074-8548-B3B524305905}"; const string EditorApiProjectGuid = "{8FBEC238-D944-4074-8548-B3B524305905}";
public static string GenCoreApiProject(string dir, string[] compileItems) public static string GenCoreApiProject(string dir, string[] compileItems)
{ {
string path = Path.Combine(dir, CoreApiProject + ".csproj"); string path = Path.Combine(dir, CoreApiProjectName + ".csproj");
ProjectPropertyGroupElement mainGroup; ProjectPropertyGroupElement mainGroup;
var root = CreateLibraryProject(CoreApiProject, out mainGroup); var root = CreateLibraryProject(CoreApiProjectName, out mainGroup);
mainGroup.AddProperty("DocumentationFile", Path.Combine("$(OutputPath)", "$(AssemblyName).xml")); mainGroup.AddProperty("DocumentationFile", Path.Combine("$(OutputPath)", "$(AssemblyName).xml"));
mainGroup.SetProperty("RootNamespace", "Godot"); mainGroup.SetProperty("RootNamespace", "Godot");
mainGroup.SetProperty("ProjectGuid", CoreApiProjectGuid); mainGroup.SetProperty("ProjectGuid", CoreApiProjectGuid);
GenAssemblyInfoFile(root, dir, CoreApiProject, GenAssemblyInfoFile(root, dir, CoreApiProjectName,
new string[] { "[assembly: InternalsVisibleTo(\"" + EditorApiProject + "\")]" }, new string[] { "[assembly: InternalsVisibleTo(\"" + EditorApiProjectName + "\")]" },
new string[] { "System.Runtime.CompilerServices" }); new string[] { "System.Runtime.CompilerServices" });
foreach (var item in compileItems) foreach (var item in compileItems)
@ -31,34 +33,33 @@ namespace GodotSharpTools.Project
root.Save(path); root.Save(path);
return root.GetGuid().ToString().ToUpper(); return CoreApiProjectGuid;
} }
public static string GenEditorApiProject(string dir, string coreApiHintPath, string[] compileItems) public static string GenEditorApiProject(string dir, string coreApiProjPath, string[] compileItems)
{ {
string path = Path.Combine(dir, EditorApiProject + ".csproj"); string path = Path.Combine(dir, EditorApiProjectName + ".csproj");
ProjectPropertyGroupElement mainGroup; ProjectPropertyGroupElement mainGroup;
var root = CreateLibraryProject(EditorApiProject, out mainGroup); var root = CreateLibraryProject(EditorApiProjectName, out mainGroup);
mainGroup.AddProperty("DocumentationFile", Path.Combine("$(OutputPath)", "$(AssemblyName).xml")); mainGroup.AddProperty("DocumentationFile", Path.Combine("$(OutputPath)", "$(AssemblyName).xml"));
mainGroup.SetProperty("RootNamespace", "Godot"); mainGroup.SetProperty("RootNamespace", "Godot");
mainGroup.SetProperty("ProjectGuid", EditorApiProjectGuid); mainGroup.SetProperty("ProjectGuid", EditorApiProjectGuid);
GenAssemblyInfoFile(root, dir, EditorApiProject); GenAssemblyInfoFile(root, dir, EditorApiProjectName);
foreach (var item in compileItems) foreach (var item in compileItems)
{ {
root.AddItem("Compile", item.RelativeToPath(dir).Replace("/", "\\")); root.AddItem("Compile", item.RelativeToPath(dir).Replace("/", "\\"));
} }
var coreApiRef = root.AddItem("Reference", CoreApiProject); var coreApiRef = root.AddItem("ProjectReference", coreApiProjPath.Replace("/", "\\"));
coreApiRef.AddMetadata("HintPath", coreApiHintPath);
coreApiRef.AddMetadata("Private", "False"); coreApiRef.AddMetadata("Private", "False");
root.Save(path); root.Save(path);
return root.GetGuid().ToString().ToUpper(); return EditorApiProjectGuid;
} }
public static string GenGameProject(string dir, string name, string[] compileItems) public static string GenGameProject(string dir, string name, string[] compileItems)
@ -82,13 +83,13 @@ namespace GodotSharpTools.Project
toolsGroup.AddProperty("WarningLevel", "4"); toolsGroup.AddProperty("WarningLevel", "4");
toolsGroup.AddProperty("ConsolePause", "false"); toolsGroup.AddProperty("ConsolePause", "false");
var coreApiRef = root.AddItem("Reference", CoreApiProject); var coreApiRef = root.AddItem("Reference", CoreApiProjectName);
coreApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", CoreApiProject + ".dll")); coreApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", CoreApiProjectName + ".dll"));
coreApiRef.AddMetadata("Private", "False"); coreApiRef.AddMetadata("Private", "False");
var editorApiRef = root.AddItem("Reference", EditorApiProject); var editorApiRef = root.AddItem("Reference", EditorApiProjectName);
editorApiRef.Condition = " '$(Configuration)' == 'Tools' "; editorApiRef.Condition = " '$(Configuration)' == 'Tools' ";
editorApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", EditorApiProject + ".dll")); editorApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", EditorApiProjectName + ".dll"));
editorApiRef.AddMetadata("Private", "False"); editorApiRef.AddMetadata("Private", "False");
GenAssemblyInfoFile(root, dir, name); GenAssemblyInfoFile(root, dir, name);
@ -187,9 +188,6 @@ namespace GodotSharpTools.Project
} }
} }
public const string CoreApiProject = "GodotSharp";
public const string EditorApiProject = "GodotSharpEditor";
private const string assemblyInfoTemplate = private const string assemblyInfoTemplate =
@"using System.Reflection;{0} @"using System.Reflection;{0}

View file

@ -47,7 +47,6 @@
#include "../utils/path_utils.h" #include "../utils/path_utils.h"
#include "../utils/string_utils.h" #include "../utils/string_utils.h"
#include "csharp_project.h" #include "csharp_project.h"
#include "net_solution.h"
#define CS_INDENT " " // 4 whitespaces #define CS_INDENT " " // 4 whitespaces
@ -401,32 +400,29 @@ void BindingsGenerator::_generate_global_constants(List<String> &p_output) {
p_output.push_back(CLOSE_BLOCK); // end of namespace p_output.push_back(CLOSE_BLOCK); // end of namespace
} }
Error BindingsGenerator::generate_cs_core_project(const String &p_output_dir, bool p_verbose_output) { Error BindingsGenerator::generate_cs_core_project(const String &p_solution_dir, DotNetSolution &r_solution, bool p_verbose_output) {
verbose_output = p_verbose_output; verbose_output = p_verbose_output;
String proj_dir = p_solution_dir.plus_file(CORE_API_ASSEMBLY_NAME);
DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
ERR_FAIL_COND_V(!da, ERR_CANT_CREATE); ERR_FAIL_COND_V(!da, ERR_CANT_CREATE);
if (!DirAccess::exists(p_output_dir)) { if (!DirAccess::exists(proj_dir)) {
Error err = da->make_dir_recursive(p_output_dir); Error err = da->make_dir_recursive(proj_dir);
ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE); ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
} }
da->change_dir(p_output_dir); da->change_dir(proj_dir);
da->make_dir("Core"); da->make_dir("Core");
da->make_dir("ObjectType"); da->make_dir("ObjectType");
String core_dir = path_join(p_output_dir, "Core"); String core_dir = path_join(proj_dir, "Core");
String obj_type_dir = path_join(p_output_dir, "ObjectType"); String obj_type_dir = path_join(proj_dir, "ObjectType");
Vector<String> compile_items; Vector<String> compile_items;
NETSolution solution(API_ASSEMBLY_NAME);
if (!solution.set_path(p_output_dir))
return ERR_FILE_NOT_FOUND;
// Generate source file for global scope constants and enums // Generate source file for global scope constants and enums
{ {
List<String> constants_source; List<String> constants_source;
@ -530,15 +526,15 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_output_dir, bo
compile_items.push_back(internal_methods_file); compile_items.push_back(internal_methods_file);
String guid = CSharpProject::generate_core_api_project(p_output_dir, compile_items); String guid = CSharpProject::generate_core_api_project(proj_dir, compile_items);
solution.add_new_project(API_ASSEMBLY_NAME, guid); DotNetSolution::ProjectInfo proj_info;
proj_info.guid = guid;
proj_info.relpath = String(CORE_API_ASSEMBLY_NAME).plus_file(CORE_API_ASSEMBLY_NAME ".csproj");
proj_info.configs.push_back("Debug");
proj_info.configs.push_back("Release");
Error sln_error = solution.save(); r_solution.add_new_project(CORE_API_ASSEMBLY_NAME, proj_info);
if (sln_error != OK) {
ERR_PRINT("Could not to save .NET solution.");
return sln_error;
}
if (verbose_output) if (verbose_output)
OS::get_singleton()->print("The solution and C# project for the Core API was generated successfully\n"); OS::get_singleton()->print("The solution and C# project for the Core API was generated successfully\n");
@ -546,32 +542,29 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_output_dir, bo
return OK; return OK;
} }
Error BindingsGenerator::generate_cs_editor_project(const String &p_output_dir, const String &p_core_dll_path, bool p_verbose_output) { Error BindingsGenerator::generate_cs_editor_project(const String &p_solution_dir, DotNetSolution &r_solution, bool p_verbose_output) {
verbose_output = p_verbose_output; verbose_output = p_verbose_output;
String proj_dir = p_solution_dir.plus_file(EDITOR_API_ASSEMBLY_NAME);
DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
ERR_FAIL_COND_V(!da, ERR_CANT_CREATE); ERR_FAIL_COND_V(!da, ERR_CANT_CREATE);
if (!DirAccess::exists(p_output_dir)) { if (!DirAccess::exists(proj_dir)) {
Error err = da->make_dir_recursive(p_output_dir); Error err = da->make_dir_recursive(proj_dir);
ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE); ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
} }
da->change_dir(p_output_dir); da->change_dir(proj_dir);
da->make_dir("Core"); da->make_dir("Core");
da->make_dir("ObjectType"); da->make_dir("ObjectType");
String core_dir = path_join(p_output_dir, "Core"); String core_dir = path_join(proj_dir, "Core");
String obj_type_dir = path_join(p_output_dir, "ObjectType"); String obj_type_dir = path_join(proj_dir, "ObjectType");
Vector<String> compile_items; Vector<String> compile_items;
NETSolution solution(EDITOR_API_ASSEMBLY_NAME);
if (!solution.set_path(p_output_dir))
return ERR_FILE_NOT_FOUND;
for (OrderedHashMap<StringName, TypeInterface>::Element E = obj_types.front(); E; E = E.next()) { for (OrderedHashMap<StringName, TypeInterface>::Element E = obj_types.front(); E; E = E.next()) {
const TypeInterface &itype = E.get(); const TypeInterface &itype = E.get();
@ -632,15 +625,15 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_output_dir,
compile_items.push_back(internal_methods_file); compile_items.push_back(internal_methods_file);
String guid = CSharpProject::generate_editor_api_project(p_output_dir, p_core_dll_path, compile_items); String guid = CSharpProject::generate_editor_api_project(proj_dir, "../" CORE_API_ASSEMBLY_NAME "/" CORE_API_ASSEMBLY_NAME ".csproj", compile_items);
solution.add_new_project(EDITOR_API_ASSEMBLY_NAME, guid); DotNetSolution::ProjectInfo proj_info;
proj_info.guid = guid;
proj_info.relpath = String(EDITOR_API_ASSEMBLY_NAME).plus_file(EDITOR_API_ASSEMBLY_NAME ".csproj");
proj_info.configs.push_back("Debug");
proj_info.configs.push_back("Release");
Error sln_error = solution.save(); r_solution.add_new_project(EDITOR_API_ASSEMBLY_NAME, proj_info);
if (sln_error != OK) {
ERR_PRINT("Could not to save .NET solution.");
return sln_error;
}
if (verbose_output) if (verbose_output)
OS::get_singleton()->print("The solution and C# project for the Editor API was generated successfully\n"); OS::get_singleton()->print("The solution and C# project for the Editor API was generated successfully\n");
@ -648,6 +641,44 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_output_dir,
return OK; return OK;
} }
Error BindingsGenerator::generate_cs_api(const String &p_output_dir, bool p_verbose_output) {
DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
ERR_FAIL_COND_V(!da, ERR_CANT_CREATE);
if (!DirAccess::exists(p_output_dir)) {
Error err = da->make_dir_recursive(p_output_dir);
ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
}
DotNetSolution solution(API_SOLUTION_NAME);
if (!solution.set_path(p_output_dir))
return ERR_FILE_NOT_FOUND;
Error proj_err;
proj_err = generate_cs_core_project(p_output_dir, solution, p_verbose_output);
if (proj_err != OK) {
ERR_PRINT("Generation of the Core API C# project failed");
return proj_err;
}
proj_err = generate_cs_editor_project(p_output_dir, solution, p_verbose_output);
if (proj_err != OK) {
ERR_PRINT("Generation of the Editor API C# project failed");
return proj_err;
}
Error sln_error = solution.save();
if (sln_error != OK) {
ERR_PRINT("Failed to save API solution");
return sln_error;
}
return OK;
}
// FIXME: There are some members that hide other inherited members. // FIXME: There are some members that hide other inherited members.
// - In the case of both members being the same kind, the new one must be declared // - In the case of both members being the same kind, the new one must be declared
// explicitly as `new` to avoid the warning (and we must print a message about it). // explicitly as `new` to avoid the warning (and we must print a message about it).
@ -2368,12 +2399,11 @@ void BindingsGenerator::initialize() {
void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args) { void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args) {
const int NUM_OPTIONS = 3; const int NUM_OPTIONS = 2;
int options_left = NUM_OPTIONS; int options_left = NUM_OPTIONS;
String mono_glue_option = "--generate-mono-glue"; String mono_glue_option = "--generate-mono-glue";
String cs_core_api_option = "--generate-cs-core-api"; String cs_api_option = "--generate-cs-api";
String cs_editor_api_option = "--generate-cs-editor-api";
verbose_output = true; verbose_output = true;
@ -2387,42 +2417,24 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args)
if (path_elem) { if (path_elem) {
if (get_singleton()->generate_glue(path_elem->get()) != OK) if (get_singleton()->generate_glue(path_elem->get()) != OK)
ERR_PRINT("Mono glue generation failed"); ERR_PRINTS(mono_glue_option + ": Failed to generate mono glue");
elem = elem->next(); elem = elem->next();
} else { } else {
ERR_PRINTS("--generate-mono-glue: No output directory specified"); ERR_PRINTS(mono_glue_option + ": No output directory specified");
} }
--options_left; --options_left;
} else if (elem->get() == cs_core_api_option) { } else if (elem->get() == cs_api_option) {
const List<String>::Element *path_elem = elem->next(); const List<String>::Element *path_elem = elem->next();
if (path_elem) { if (path_elem) {
if (get_singleton()->generate_cs_core_project(path_elem->get()) != OK) if (get_singleton()->generate_cs_api(path_elem->get()) != OK)
ERR_PRINT("Generation of solution and C# project for the Core API failed"); ERR_PRINTS(cs_api_option + ": Failed to generate the C# API");
elem = elem->next(); elem = elem->next();
} else { } else {
ERR_PRINTS(cs_core_api_option + ": No output directory specified"); ERR_PRINTS(cs_api_option + ": No output directory specified");
}
--options_left;
} else if (elem->get() == cs_editor_api_option) {
const List<String>::Element *path_elem = elem->next();
if (path_elem) {
if (path_elem->next()) {
if (get_singleton()->generate_cs_editor_project(path_elem->get(), path_elem->next()->get()) != OK)
ERR_PRINT("Generation of solution and C# project for the Editor API failed");
elem = path_elem->next();
} else {
ERR_PRINTS(cs_editor_api_option + ": No hint path for the Core API dll specified");
}
} else {
ERR_PRINTS(cs_editor_api_option + ": No output directory specified");
} }
--options_left; --options_left;
@ -2434,7 +2446,7 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args)
verbose_output = false; verbose_output = false;
if (options_left != NUM_OPTIONS) if (options_left != NUM_OPTIONS)
exit(0); ::exit(0);
} }
#endif #endif

View file

@ -32,6 +32,7 @@
#define BINDINGS_GENERATOR_H #define BINDINGS_GENERATOR_H
#include "core/class_db.h" #include "core/class_db.h"
#include "dotnet_solution.h"
#include "editor/doc/doc_data.h" #include "editor/doc/doc_data.h"
#include "editor/editor_help.h" #include "editor/editor_help.h"
@ -556,8 +557,9 @@ class BindingsGenerator {
static BindingsGenerator *singleton; static BindingsGenerator *singleton;
public: public:
Error generate_cs_core_project(const String &p_output_dir, bool p_verbose_output = true); Error generate_cs_core_project(const String &p_solution_dir, DotNetSolution &r_solution, bool p_verbose_output = true);
Error generate_cs_editor_project(const String &p_output_dir, const String &p_core_dll_path, bool p_verbose_output = true); Error generate_cs_editor_project(const String &p_solution_dir, DotNetSolution &r_solution, bool p_verbose_output = true);
Error generate_cs_api(const String &p_output_dir, bool p_verbose_output = true);
Error generate_glue(const String &p_output_dir); Error generate_glue(const String &p_output_dir);
static uint32_t get_version(); static uint32_t get_version();

View file

@ -31,6 +31,8 @@
#include "csharp_project.h" #include "csharp_project.h"
#include "core/io/json.h" #include "core/io/json.h"
#include "core/os/dir_access.h"
#include "core/os/file_access.h"
#include "core/os/os.h" #include "core/os/os.h"
#include "core/project_settings.h" #include "core/project_settings.h"
@ -62,16 +64,16 @@ String generate_core_api_project(const String &p_dir, const Vector<String> &p_fi
return ret ? GDMonoMarshal::mono_string_to_godot((MonoString *)ret) : String(); return ret ? GDMonoMarshal::mono_string_to_godot((MonoString *)ret) : String();
} }
String generate_editor_api_project(const String &p_dir, const String &p_core_dll_path, const Vector<String> &p_files) { String generate_editor_api_project(const String &p_dir, const String &p_core_proj_path, const Vector<String> &p_files) {
_GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN) _GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN)
GDMonoClass *klass = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Project", "ProjectGenerator"); GDMonoClass *klass = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Project", "ProjectGenerator");
Variant dir = p_dir; Variant dir = p_dir;
Variant core_dll_path = p_core_dll_path; Variant core_proj_path = p_core_proj_path;
Variant compile_items = p_files; Variant compile_items = p_files;
const Variant *args[3] = { &dir, &core_dll_path, &compile_items }; const Variant *args[3] = { &dir, &core_proj_path, &compile_items };
MonoException *exc = NULL; MonoException *exc = NULL;
MonoObject *ret = klass->get_method("GenEditorApiProject", 3)->invoke(NULL, args, &exc); MonoObject *ret = klass->get_method("GenEditorApiProject", 3)->invoke(NULL, args, &exc);
@ -127,6 +129,14 @@ Error generate_scripts_metadata(const String &p_project_path, const String &p_ou
_GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN) _GDMONO_SCOPE_DOMAIN_(TOOLS_DOMAIN)
if (FileAccess::exists(p_output_path)) {
DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
Error rm_err = da->remove(p_output_path);
ERR_EXPLAIN("Failed to remove old scripts metadata file");
ERR_FAIL_COND_V(rm_err != OK, rm_err);
}
GDMonoClass *project_utils = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Project", "ProjectUtils"); GDMonoClass *project_utils = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Project", "ProjectUtils");
void *args[2] = { void *args[2] = {

View file

@ -1,5 +1,5 @@
/*************************************************************************/ /*************************************************************************/
/* net_solution.cpp */ /* dotnet_solution.cpp */
/*************************************************************************/ /*************************************************************************/
/* This file is part of: */ /* This file is part of: */
/* GODOT ENGINE */ /* GODOT ENGINE */
@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/ /*************************************************************************/
#include "net_solution.h" #include "dotnet_solution.h"
#include "core/os/dir_access.h" #include "core/os/dir_access.h"
#include "core/os/file_access.h" #include "core/os/file_access.h"
@ -58,27 +58,26 @@
"\t\t{%0}.%1|Any CPU.ActiveCfg = %1|Any CPU\n" \ "\t\t{%0}.%1|Any CPU.ActiveCfg = %1|Any CPU\n" \
"\t\t{%0}.%1|Any CPU.Build.0 = %1|Any CPU" "\t\t{%0}.%1|Any CPU.Build.0 = %1|Any CPU"
void NETSolution::add_new_project(const String &p_name, const String &p_guid, const Vector<String> &p_extra_configs) { void DotNetSolution::add_new_project(const String &p_name, const ProjectInfo &p_project_info) {
if (projects.has(p_name)) projects[p_name] = p_project_info;
WARN_PRINT("Overriding existing project.");
ProjectInfo procinfo;
procinfo.guid = p_guid;
procinfo.configs.push_back("Debug");
procinfo.configs.push_back("Release");
for (int i = 0; i < p_extra_configs.size(); i++) {
procinfo.configs.push_back(p_extra_configs[i]);
}
projects[p_name] = procinfo;
} }
Error NETSolution::save() { bool DotNetSolution::has_project(const String &p_name) const {
return projects.find(p_name) != NULL;
}
const DotNetSolution::ProjectInfo &DotNetSolution::get_project_info(const String &p_name) const {
return projects[p_name];
}
bool DotNetSolution::remove_project(const String &p_name) {
return projects.erase(p_name);
}
Error DotNetSolution::save() {
bool dir_exists = DirAccess::exists(path); bool dir_exists = DirAccess::exists(path);
ERR_EXPLAIN("The directory does not exist."); ERR_EXPLAIN("The directory does not exist.");
ERR_FAIL_COND_V(!dir_exists, ERR_FILE_BAD_PATH); ERR_FAIL_COND_V(!dir_exists, ERR_FILE_NOT_FOUND);
String projs_decl; String projs_decl;
String sln_platform_cfg; String sln_platform_cfg;
@ -86,34 +85,40 @@ Error NETSolution::save() {
for (Map<String, ProjectInfo>::Element *E = projects.front(); E; E = E->next()) { for (Map<String, ProjectInfo>::Element *E = projects.front(); E; E = E->next()) {
const String &name = E->key(); const String &name = E->key();
const ProjectInfo &procinfo = E->value(); const ProjectInfo &proj_info = E->value();
projs_decl += sformat(PROJECT_DECLARATION, name, name + ".csproj", procinfo.guid); bool is_front = E == projects.front();
for (int i = 0; i < procinfo.configs.size(); i++) { if (!is_front)
const String &config = procinfo.configs[i]; projs_decl += "\n";
if (i != 0) { projs_decl += sformat(PROJECT_DECLARATION, name, proj_info.relpath.replace("/", "\\"), proj_info.guid);
for (int i = 0; i < proj_info.configs.size(); i++) {
const String &config = proj_info.configs[i];
if (i != 0 || !is_front) {
sln_platform_cfg += "\n"; sln_platform_cfg += "\n";
proj_platform_cfg += "\n"; proj_platform_cfg += "\n";
} }
sln_platform_cfg += sformat(SOLUTION_PLATFORMS_CONFIG, config); sln_platform_cfg += sformat(SOLUTION_PLATFORMS_CONFIG, config);
proj_platform_cfg += sformat(PROJECT_PLATFORMS_CONFIG, procinfo.guid, config); proj_platform_cfg += sformat(PROJECT_PLATFORMS_CONFIG, proj_info.guid, config);
} }
} }
String content = sformat(SOLUTION_TEMPLATE, projs_decl, sln_platform_cfg, proj_platform_cfg); String content = sformat(SOLUTION_TEMPLATE, projs_decl, sln_platform_cfg, proj_platform_cfg);
FileAccessRef file = FileAccess::open(path_join(path, name + ".sln"), FileAccess::WRITE); FileAccess *file = FileAccess::open(path_join(path, name + ".sln"), FileAccess::WRITE);
ERR_FAIL_COND_V(!file, ERR_FILE_CANT_WRITE); ERR_FAIL_NULL_V(file, ERR_FILE_CANT_WRITE);
file->store_string(content); file->store_string(content);
file->close(); file->close();
memdelete(file);
return OK; return OK;
} }
bool NETSolution::set_path(const String &p_existing_path) { bool DotNetSolution::set_path(const String &p_existing_path) {
if (p_existing_path.is_abs_path()) { if (p_existing_path.is_abs_path()) {
path = p_existing_path; path = p_existing_path;
} else { } else {
@ -126,6 +131,10 @@ bool NETSolution::set_path(const String &p_existing_path) {
return true; return true;
} }
NETSolution::NETSolution(const String &p_name) { String DotNetSolution::get_path() {
return path;
}
DotNetSolution::DotNetSolution(const String &p_name) {
name = p_name; name = p_name;
} }

View file

@ -1,5 +1,5 @@
/*************************************************************************/ /*************************************************************************/
/* net_solution.h */ /* dotnet_solution.h */
/*************************************************************************/ /*************************************************************************/
/* This file is part of: */ /* This file is part of: */
/* GODOT ENGINE */ /* GODOT ENGINE */
@ -34,23 +34,28 @@
#include "core/map.h" #include "core/map.h"
#include "core/ustring.h" #include "core/ustring.h"
struct NETSolution { struct DotNetSolution {
String name; String name;
void add_new_project(const String &p_name, const String &p_guid, const Vector<String> &p_extra_configs = Vector<String>()); struct ProjectInfo {
String guid;
String relpath; // Must be relative to the solution directory
Vector<String> configs;
};
void add_new_project(const String &p_name, const ProjectInfo &p_project_info);
bool has_project(const String &p_name) const;
const ProjectInfo &get_project_info(const String &p_name) const;
bool remove_project(const String &p_name);
Error save(); Error save();
bool set_path(const String &p_existing_path); bool set_path(const String &p_existing_path);
String get_path();
NETSolution(const String &p_name); DotNetSolution(const String &p_name);
private: private:
struct ProjectInfo {
String guid;
Vector<String> configs;
};
String path; String path;
Map<String, ProjectInfo> projects; Map<String, ProjectInfo> projects;
}; };

View file

@ -227,20 +227,24 @@ void GodotSharpBuilds::show_build_error_dialog(const String &p_message) {
MonoBottomPanel::get_singleton()->show_build_tab(); MonoBottomPanel::get_singleton()->show_build_tab();
} }
bool GodotSharpBuilds::build_api_sln(const String &p_name, const String &p_api_sln_dir, const String &p_config) { bool GodotSharpBuilds::build_api_sln(const String &p_api_sln_dir, const String &p_config) {
String api_sln_file = p_api_sln_dir.plus_file(p_name + ".sln"); String api_sln_file = p_api_sln_dir.plus_file(API_SOLUTION_NAME ".sln");
String api_assembly_dir = p_api_sln_dir.plus_file("bin").plus_file(p_config);
String api_assembly_file = api_assembly_dir.plus_file(p_name + ".dll");
if (!FileAccess::exists(api_assembly_file)) { 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)) {
MonoBuildInfo api_build_info(api_sln_file, p_config); MonoBuildInfo api_build_info(api_sln_file, p_config);
// TODO Replace this global NoWarn with '#pragma warning' directives on generated files, // TODO Replace this global NoWarn with '#pragma warning' directives on generated files,
// once we start to actively document manually maintained C# classes // once we start to actively document manually maintained C# classes
api_build_info.custom_props.push_back("NoWarn=1591"); // Ignore missing documentation warnings api_build_info.custom_props.push_back("NoWarn=1591"); // Ignore missing documentation warnings
if (!GodotSharpBuilds::get_singleton()->build(api_build_info)) { if (!GodotSharpBuilds::get_singleton()->build(api_build_info)) {
show_build_error_dialog("Failed to build " + p_name + " solution."); show_build_error_dialog("Failed to build " API_SOLUTION_NAME " solution.");
return false; return false;
} }
} }
@ -302,9 +306,9 @@ String GodotSharpBuilds::_api_folder_name(APIAssembly::Type p_api_type) {
"_" + String::num_uint64(CS_GLUE_VERSION); "_" + String::num_uint64(CS_GLUE_VERSION);
} }
bool GodotSharpBuilds::make_api_sln(APIAssembly::Type p_api_type) { bool GodotSharpBuilds::make_api_assembly(APIAssembly::Type p_api_type) {
String api_name = p_api_type == APIAssembly::API_CORE ? API_ASSEMBLY_NAME : EDITOR_API_ASSEMBLY_NAME; 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 editor_prebuilt_api_dir = GodotSharpDirs::get_data_editor_prebuilt_api_dir();
String res_assemblies_dir = GodotSharpDirs::get_res_assemblies_dir(); String res_assemblies_dir = GodotSharpDirs::get_res_assemblies_dir();
@ -317,55 +321,35 @@ bool GodotSharpBuilds::make_api_sln(APIAssembly::Type p_api_type) {
String api_build_config = "Release"; String api_build_config = "Release";
EditorProgress pr("mono_build_release_" + api_name, "Building " + api_name + " solution...", 3); EditorProgress pr("mono_build_release_" API_SOLUTION_NAME, "Building " API_SOLUTION_NAME " solution...", 3);
pr.step("Generating " + api_name + " solution", 0); pr.step("Generating " API_SOLUTION_NAME " solution", 0);
String core_api_sln_dir = GodotSharpDirs::get_mono_solutions_dir() String api_sln_dir = GodotSharpDirs::get_mono_solutions_dir()
.plus_file(_api_folder_name(APIAssembly::API_CORE)) .plus_file(_api_folder_name(APIAssembly::API_CORE));
.plus_file(API_ASSEMBLY_NAME);
String editor_api_sln_dir = GodotSharpDirs::get_mono_solutions_dir()
.plus_file(_api_folder_name(APIAssembly::API_EDITOR))
.plus_file(EDITOR_API_ASSEMBLY_NAME);
String api_sln_dir = p_api_type == APIAssembly::API_CORE ? core_api_sln_dir : editor_api_sln_dir; String api_sln_file = api_sln_dir.plus_file(API_SOLUTION_NAME ".sln");
String api_sln_file = api_sln_dir.plus_file(api_name + ".sln");
if (!DirAccess::exists(api_sln_dir) || !FileAccess::exists(api_sln_file)) { if (!DirAccess::exists(api_sln_dir) || !FileAccess::exists(api_sln_file)) {
String core_api_assembly;
if (p_api_type == APIAssembly::API_EDITOR) {
core_api_assembly = core_api_sln_dir.plus_file("bin")
.plus_file(api_build_config)
.plus_file(API_ASSEMBLY_NAME ".dll");
}
#ifndef DEBUG_METHODS_ENABLED
#error "How am I supposed to generate the bindings?"
#endif
BindingsGenerator *gen = BindingsGenerator::get_singleton(); BindingsGenerator *gen = BindingsGenerator::get_singleton();
bool gen_verbose = OS::get_singleton()->is_stdout_verbose(); bool gen_verbose = OS::get_singleton()->is_stdout_verbose();
Error err = p_api_type == APIAssembly::API_CORE ? Error err = gen->generate_cs_api(api_sln_dir, gen_verbose);
gen->generate_cs_core_project(api_sln_dir, gen_verbose) :
gen->generate_cs_editor_project(api_sln_dir, core_api_assembly, gen_verbose);
if (err != OK) { if (err != OK) {
show_build_error_dialog("Failed to generate " + api_name + " solution. Error: " + itos(err)); show_build_error_dialog("Failed to generate " API_SOLUTION_NAME " solution. Error: " + itos(err));
return false; return false;
} }
} }
pr.step("Building " + api_name + " solution", 1); pr.step("Building " API_SOLUTION_NAME " solution", 1);
if (!GodotSharpBuilds::build_api_sln(api_name, api_sln_dir, api_build_config)) if (!GodotSharpBuilds::build_api_sln(api_sln_dir, api_build_config))
return false; return false;
pr.step("Copying " + api_name + " assembly", 2); pr.step("Copying " + api_name + " assembly", 2);
// Copy the built assembly to the assemblies directory // Copy the built assembly to the assemblies directory
String api_assembly_dir = api_sln_dir.plus_file("bin").plus_file(api_build_config); 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)) if (!GodotSharpBuilds::copy_api_assembly(api_assembly_dir, res_assemblies_dir, api_name, p_api_type))
return false; return false;
@ -377,10 +361,10 @@ bool GodotSharpBuilds::build_project_blocking(const String &p_config) {
if (!FileAccess::exists(GodotSharpDirs::get_project_sln_path())) if (!FileAccess::exists(GodotSharpDirs::get_project_sln_path()))
return true; // No solution to build return true; // No solution to build
if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_CORE)) if (!GodotSharpBuilds::make_api_assembly(APIAssembly::API_CORE))
return false; return false;
if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_EDITOR)) if (!GodotSharpBuilds::make_api_assembly(APIAssembly::API_EDITOR))
return false; return false;
EditorProgress pr("mono_project_debug_build", "Building project solution...", 1); EditorProgress pr("mono_project_debug_build", "Building project solution...", 1);
@ -403,11 +387,13 @@ bool GodotSharpBuilds::editor_build_callback() {
Error metadata_err = CSharpProject::generate_scripts_metadata(GodotSharpDirs::get_project_csproj_path(), scripts_metadata_path_editor); Error metadata_err = CSharpProject::generate_scripts_metadata(GodotSharpDirs::get_project_csproj_path(), scripts_metadata_path_editor);
ERR_FAIL_COND_V(metadata_err != OK, false); ERR_FAIL_COND_V(metadata_err != OK, false);
DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); if (FileAccess::exists(scripts_metadata_path_editor)) {
Error copy_err = da->copy(scripts_metadata_path_editor, scripts_metadata_path_player); 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_EXPLAIN("Failed to copy scripts metadata file");
ERR_FAIL_COND_V(copy_err != OK, false); ERR_FAIL_COND_V(copy_err != OK, false);
}
return build_project_blocking("Tools"); return build_project_blocking("Tools");
} }

View file

@ -84,10 +84,10 @@ public:
bool build(const MonoBuildInfo &p_build_info); bool build(const MonoBuildInfo &p_build_info);
bool build_async(const MonoBuildInfo &p_build_info, GodotSharpBuild_ExitCallback p_callback = NULL); bool build_async(const MonoBuildInfo &p_build_info, GodotSharpBuild_ExitCallback p_callback = NULL);
static bool build_api_sln(const String &p_name, const String &p_api_sln_dir, const String &p_config); static bool build_api_sln(const String &p_api_sln_dir, const String &p_config);
static bool copy_api_assembly(const String &p_src_dir, const String &p_dst_dir, const String &p_assembly_name, APIAssembly::Type p_api_type); static bool copy_api_assembly(const String &p_src_dir, const String &p_dst_dir, const String &p_assembly_name, APIAssembly::Type p_api_type);
static bool make_api_sln(APIAssembly::Type p_api_type); static bool make_api_assembly(APIAssembly::Type p_api_type);
static bool build_project_blocking(const String &p_config); static bool build_project_blocking(const String &p_config);

View file

@ -42,8 +42,8 @@
#include "../utils/path_utils.h" #include "../utils/path_utils.h"
#include "bindings_generator.h" #include "bindings_generator.h"
#include "csharp_project.h" #include "csharp_project.h"
#include "dotnet_solution.h"
#include "godotsharp_export.h" #include "godotsharp_export.h"
#include "net_solution.h"
#ifdef OSX_ENABLED #ifdef OSX_ENABLED
#include "../utils/osx_utils.h" #include "../utils/osx_utils.h"
@ -71,17 +71,21 @@ bool GodotSharpEditor::_create_project_solution() {
if (guid.length()) { if (guid.length()) {
NETSolution solution(name); DotNetSolution solution(name);
if (!solution.set_path(path)) { if (!solution.set_path(path)) {
show_error_dialog(TTR("Failed to create solution.")); show_error_dialog(TTR("Failed to create solution."));
return false; return false;
} }
Vector<String> extra_configs; DotNetSolution::ProjectInfo proj_info;
extra_configs.push_back("Tools"); proj_info.guid = guid;
proj_info.relpath = name + ".csproj";
proj_info.configs.push_back("Debug");
proj_info.configs.push_back("Release");
proj_info.configs.push_back("Tools");
solution.add_new_project(name, guid, extra_configs); solution.add_new_project(name, proj_info);
Error sln_error = solution.save(); Error sln_error = solution.save();
@ -90,10 +94,10 @@ bool GodotSharpEditor::_create_project_solution() {
return false; return false;
} }
if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_CORE)) if (!GodotSharpBuilds::make_api_assembly(APIAssembly::API_CORE))
return false; return false;
if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_EDITOR)) if (!GodotSharpBuilds::make_api_assembly(APIAssembly::API_EDITOR))
return false; return false;
pr.step(TTR("Done")); pr.step(TTR("Done"));
@ -122,15 +126,15 @@ void GodotSharpEditor::_make_api_solutions_if_needed_impl() {
// If the project has a solution and C# project make sure the API assemblies are present and up to date // If the project has a solution and C# project make sure the API assemblies are present and up to date
String res_assemblies_dir = GodotSharpDirs::get_res_assemblies_dir(); String res_assemblies_dir = GodotSharpDirs::get_res_assemblies_dir();
if (!FileAccess::exists(res_assemblies_dir.plus_file(API_ASSEMBLY_NAME ".dll")) || if (!FileAccess::exists(res_assemblies_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll")) ||
GDMono::get_singleton()->metadata_is_api_assembly_invalidated(APIAssembly::API_CORE)) { GDMono::get_singleton()->metadata_is_api_assembly_invalidated(APIAssembly::API_CORE)) {
if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_CORE)) if (!GodotSharpBuilds::make_api_assembly(APIAssembly::API_CORE))
return; return;
} }
if (!FileAccess::exists(res_assemblies_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll")) || if (!FileAccess::exists(res_assemblies_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll")) ||
GDMono::get_singleton()->metadata_is_api_assembly_invalidated(APIAssembly::API_EDITOR)) { GDMono::get_singleton()->metadata_is_api_assembly_invalidated(APIAssembly::API_EDITOR)) {
if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_EDITOR)) if (!GodotSharpBuilds::make_api_assembly(APIAssembly::API_EDITOR))
return; // Redundant? I don't think so return; // Redundant? I don't think so
} }
} }

View file

@ -36,7 +36,8 @@
#define BINDINGS_GLOBAL_SCOPE_CLASS "GD" #define BINDINGS_GLOBAL_SCOPE_CLASS "GD"
#define BINDINGS_PTR_FIELD "ptr" #define BINDINGS_PTR_FIELD "ptr"
#define BINDINGS_NATIVE_NAME_FIELD "nativeName" #define BINDINGS_NATIVE_NAME_FIELD "nativeName"
#define API_ASSEMBLY_NAME "GodotSharp" #define API_SOLUTION_NAME "GodotSharp"
#define CORE_API_ASSEMBLY_NAME "GodotSharp"
#define EDITOR_API_ASSEMBLY_NAME "GodotSharpEditor" #define EDITOR_API_ASSEMBLY_NAME "GodotSharpEditor"
#define EDITOR_TOOLS_ASSEMBLY_NAME "GodotSharpTools" #define EDITOR_TOOLS_ASSEMBLY_NAME "GodotSharpTools"

View file

@ -496,12 +496,12 @@ bool GDMono::_load_core_api_assembly() {
} }
#endif #endif
String assembly_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(API_ASSEMBLY_NAME ".dll"); String assembly_path = GodotSharpDirs::get_res_assemblies_dir().plus_file(CORE_API_ASSEMBLY_NAME ".dll");
if (!FileAccess::exists(assembly_path)) if (!FileAccess::exists(assembly_path))
return false; return false;
bool success = load_assembly_from(API_ASSEMBLY_NAME, bool success = load_assembly_from(CORE_API_ASSEMBLY_NAME,
assembly_path, assembly_path,
&core_api_assembly); &core_api_assembly);
@ -635,7 +635,7 @@ void GDMono::metadata_set_api_assembly_invalidated(APIAssembly::Type p_api_type,
String assembly_path = GodotSharpDirs::get_res_assemblies_dir() String assembly_path = GodotSharpDirs::get_res_assemblies_dir()
.plus_file(p_api_type == APIAssembly::API_CORE ? .plus_file(p_api_type == APIAssembly::API_CORE ?
API_ASSEMBLY_NAME ".dll" : CORE_API_ASSEMBLY_NAME ".dll" :
EDITOR_API_ASSEMBLY_NAME ".dll"); EDITOR_API_ASSEMBLY_NAME ".dll");
ERR_FAIL_COND(!FileAccess::exists(assembly_path)); ERR_FAIL_COND(!FileAccess::exists(assembly_path));
@ -666,7 +666,7 @@ bool GDMono::metadata_is_api_assembly_invalidated(APIAssembly::Type p_api_type)
String assembly_path = GodotSharpDirs::get_res_assemblies_dir() String assembly_path = GodotSharpDirs::get_res_assemblies_dir()
.plus_file(p_api_type == APIAssembly::API_CORE ? .plus_file(p_api_type == APIAssembly::API_CORE ?
API_ASSEMBLY_NAME ".dll" : CORE_API_ASSEMBLY_NAME ".dll" :
EDITOR_API_ASSEMBLY_NAME ".dll"); EDITOR_API_ASSEMBLY_NAME ".dll");
if (!FileAccess::exists(assembly_path)) if (!FileAccess::exists(assembly_path))

View file

@ -631,36 +631,36 @@ void set_pending_exception(MonoException *p_exc) {
_THREAD_LOCAL_(int) _THREAD_LOCAL_(int)
current_invoke_count = 0; current_invoke_count = 0;
MonoObject *runtime_invoke(MonoMethod *p_method, void *p_obj, void **p_params, MonoException **p_exc) { MonoObject *runtime_invoke(MonoMethod *p_method, void *p_obj, void **p_params, MonoException **r_exc) {
GD_MONO_BEGIN_RUNTIME_INVOKE; GD_MONO_BEGIN_RUNTIME_INVOKE;
MonoObject *ret = mono_runtime_invoke(p_method, p_obj, p_params, (MonoObject **)p_exc); MonoObject *ret = mono_runtime_invoke(p_method, p_obj, p_params, (MonoObject **)r_exc);
GD_MONO_END_RUNTIME_INVOKE; GD_MONO_END_RUNTIME_INVOKE;
return ret; return ret;
} }
MonoObject *runtime_invoke_array(MonoMethod *p_method, void *p_obj, MonoArray *p_params, MonoException **p_exc) { MonoObject *runtime_invoke_array(MonoMethod *p_method, void *p_obj, MonoArray *p_params, MonoException **r_exc) {
GD_MONO_BEGIN_RUNTIME_INVOKE; GD_MONO_BEGIN_RUNTIME_INVOKE;
MonoObject *ret = mono_runtime_invoke_array(p_method, p_obj, p_params, (MonoObject **)p_exc); MonoObject *ret = mono_runtime_invoke_array(p_method, p_obj, p_params, (MonoObject **)r_exc);
GD_MONO_END_RUNTIME_INVOKE; GD_MONO_END_RUNTIME_INVOKE;
return ret; return ret;
} }
MonoString *object_to_string(MonoObject *p_obj, MonoException **p_exc) { MonoString *object_to_string(MonoObject *p_obj, MonoException **r_exc) {
GD_MONO_BEGIN_RUNTIME_INVOKE; GD_MONO_BEGIN_RUNTIME_INVOKE;
MonoString *ret = mono_object_to_string(p_obj, (MonoObject **)p_exc); MonoString *ret = mono_object_to_string(p_obj, (MonoObject **)r_exc);
GD_MONO_END_RUNTIME_INVOKE; GD_MONO_END_RUNTIME_INVOKE;
return ret; return ret;
} }
void property_set_value(MonoProperty *p_prop, void *p_obj, void **p_params, MonoException **p_exc) { void property_set_value(MonoProperty *p_prop, void *p_obj, void **p_params, MonoException **r_exc) {
GD_MONO_BEGIN_RUNTIME_INVOKE; GD_MONO_BEGIN_RUNTIME_INVOKE;
mono_property_set_value(p_prop, p_obj, p_params, (MonoObject **)p_exc); mono_property_set_value(p_prop, p_obj, p_params, (MonoObject **)r_exc);
GD_MONO_END_RUNTIME_INVOKE; GD_MONO_END_RUNTIME_INVOKE;
} }
MonoObject *property_get_value(MonoProperty *p_prop, void *p_obj, void **p_params, MonoException **p_exc) { MonoObject *property_get_value(MonoProperty *p_prop, void *p_obj, void **p_params, MonoException **r_exc) {
GD_MONO_BEGIN_RUNTIME_INVOKE; GD_MONO_BEGIN_RUNTIME_INVOKE;
MonoObject *ret = mono_property_get_value(p_prop, p_obj, p_params, (MonoObject **)p_exc); MonoObject *ret = mono_property_get_value(p_prop, p_obj, p_params, (MonoObject **)r_exc);
GD_MONO_END_RUNTIME_INVOKE; GD_MONO_END_RUNTIME_INVOKE;
return ret; return ret;
} }

View file

@ -233,13 +233,13 @@ _FORCE_INLINE_ int &get_runtime_invoke_count_ref() {
return current_invoke_count; return current_invoke_count;
} }
MonoObject *runtime_invoke(MonoMethod *p_method, void *p_obj, void **p_params, MonoException **p_exc); MonoObject *runtime_invoke(MonoMethod *p_method, void *p_obj, void **p_params, MonoException **r_exc);
MonoObject *runtime_invoke_array(MonoMethod *p_method, void *p_obj, MonoArray *p_params, MonoException **p_exc); MonoObject *runtime_invoke_array(MonoMethod *p_method, void *p_obj, MonoArray *p_params, MonoException **r_exc);
MonoString *object_to_string(MonoObject *p_obj, MonoException **p_exc); MonoString *object_to_string(MonoObject *p_obj, MonoException **r_exc);
void property_set_value(MonoProperty *p_prop, void *p_obj, void **p_params, MonoException **p_exc); void property_set_value(MonoProperty *p_prop, void *p_obj, void **p_params, MonoException **r_exc);
MonoObject *property_get_value(MonoProperty *p_prop, void *p_obj, void **p_params, MonoException **p_exc); MonoObject *property_get_value(MonoProperty *p_prop, void *p_obj, void **p_params, MonoException **r_exc);
uint64_t unbox_enum_value(MonoObject *p_boxed, MonoType *p_enum_basetype, bool &r_error); uint64_t unbox_enum_value(MonoObject *p_boxed, MonoType *p_enum_basetype, bool &r_error);

View file

@ -88,7 +88,7 @@ void fix_path(const String &p_path, String &r_out) {
bool rel_path_to_abs(const String &p_existing_path, String &r_abs_path) { bool rel_path_to_abs(const String &p_existing_path, String &r_abs_path) {
#ifdef WINDOWS_ENABLED #ifdef WINDOWS_ENABLED
CharType ret[_MAX_PATH]; CharType ret[_MAX_PATH];
if (_wfullpath(ret, p_existing_path.c_str(), _MAX_PATH)) { if (::_wfullpath(ret, p_existing_path.c_str(), _MAX_PATH)) {
String abspath = String(ret).replace("\\", "/"); String abspath = String(ret).replace("\\", "/");
int pos = abspath.find(":/"); int pos = abspath.find(":/");
if (pos != -1) { if (pos != -1) {
@ -99,10 +99,12 @@ bool rel_path_to_abs(const String &p_existing_path, String &r_abs_path) {
return true; return true;
} }
#else #else
char ret[PATH_MAX]; char *resolved_path = ::realpath(p_existing_path.utf8().get_data(), NULL);
if (realpath(p_existing_path.utf8().get_data(), ret)) { if (resolved_path) {
String retstr; String retstr;
if (!retstr.parse_utf8(ret)) { bool success = !retstr.parse_utf8(resolved_path);
::free(resolved_path);
if (success) {
r_abs_path = retstr; r_abs_path = retstr;
return true; return true;
} }