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",
ProjectSettings::get_singleton()->globalize_path(p_path));
} 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

View file

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

View file

@ -47,7 +47,6 @@
#include "../utils/path_utils.h"
#include "../utils/string_utils.h"
#include "csharp_project.h"
#include "net_solution.h"
#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
}
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;
String proj_dir = p_solution_dir.plus_file(CORE_API_ASSEMBLY_NAME);
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);
if (!DirAccess::exists(proj_dir)) {
Error err = da->make_dir_recursive(proj_dir);
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("ObjectType");
String core_dir = path_join(p_output_dir, "Core");
String obj_type_dir = path_join(p_output_dir, "ObjectType");
String core_dir = path_join(proj_dir, "Core");
String obj_type_dir = path_join(proj_dir, "ObjectType");
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
{
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);
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();
if (sln_error != OK) {
ERR_PRINT("Could not to save .NET solution.");
return sln_error;
}
r_solution.add_new_project(CORE_API_ASSEMBLY_NAME, proj_info);
if (verbose_output)
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;
}
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;
String proj_dir = p_solution_dir.plus_file(EDITOR_API_ASSEMBLY_NAME);
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);
if (!DirAccess::exists(proj_dir)) {
Error err = da->make_dir_recursive(proj_dir);
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("ObjectType");
String core_dir = path_join(p_output_dir, "Core");
String obj_type_dir = path_join(p_output_dir, "ObjectType");
String core_dir = path_join(proj_dir, "Core");
String obj_type_dir = path_join(proj_dir, "ObjectType");
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()) {
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);
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();
if (sln_error != OK) {
ERR_PRINT("Could not to save .NET solution.");
return sln_error;
}
r_solution.add_new_project(EDITOR_API_ASSEMBLY_NAME, proj_info);
if (verbose_output)
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;
}
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.
// - 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).
@ -2368,12 +2399,11 @@ void BindingsGenerator::initialize() {
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;
String mono_glue_option = "--generate-mono-glue";
String cs_core_api_option = "--generate-cs-core-api";
String cs_editor_api_option = "--generate-cs-editor-api";
String cs_api_option = "--generate-cs-api";
verbose_output = true;
@ -2387,42 +2417,24 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args)
if (path_elem) {
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();
} else {
ERR_PRINTS("--generate-mono-glue: No output directory specified");
ERR_PRINTS(mono_glue_option + ": No output directory specified");
}
--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();
if (path_elem) {
if (get_singleton()->generate_cs_core_project(path_elem->get()) != OK)
ERR_PRINT("Generation of solution and C# project for the Core API failed");
if (get_singleton()->generate_cs_api(path_elem->get()) != OK)
ERR_PRINTS(cs_api_option + ": Failed to generate the C# API");
elem = elem->next();
} else {
ERR_PRINTS(cs_core_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");
ERR_PRINTS(cs_api_option + ": No output directory specified");
}
--options_left;
@ -2434,7 +2446,7 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args)
verbose_output = false;
if (options_left != NUM_OPTIONS)
exit(0);
::exit(0);
}
#endif

View file

@ -32,6 +32,7 @@
#define BINDINGS_GENERATOR_H
#include "core/class_db.h"
#include "dotnet_solution.h"
#include "editor/doc/doc_data.h"
#include "editor/editor_help.h"
@ -556,8 +557,9 @@ class BindingsGenerator {
static BindingsGenerator *singleton;
public:
Error generate_cs_core_project(const String &p_output_dir, 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_core_project(const String &p_solution_dir, DotNetSolution &r_solution, 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);
static uint32_t get_version();

View file

@ -31,6 +31,8 @@
#include "csharp_project.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/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();
}
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)
GDMonoClass *klass = GDMono::get_singleton()->get_editor_tools_assembly()->get_class("GodotSharpTools.Project", "ProjectGenerator");
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;
const Variant *args[3] = { &dir, &core_dll_path, &compile_items };
const Variant *args[3] = { &dir, &core_proj_path, &compile_items };
MonoException *exc = NULL;
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)
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");
void *args[2] = {

View file

@ -1,5 +1,5 @@
/*************************************************************************/
/* net_solution.cpp */
/* dotnet_solution.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@ -28,7 +28,7 @@
/* 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/file_access.h"
@ -58,27 +58,26 @@
"\t\t{%0}.%1|Any CPU.ActiveCfg = %1|Any CPU\n" \
"\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) {
if (projects.has(p_name))
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;
void DotNetSolution::add_new_project(const String &p_name, const ProjectInfo &p_project_info) {
projects[p_name] = p_project_info;
}
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);
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 sln_platform_cfg;
@ -86,34 +85,40 @@ Error NETSolution::save() {
for (Map<String, ProjectInfo>::Element *E = projects.front(); E; E = E->next()) {
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++) {
const String &config = procinfo.configs[i];
if (!is_front)
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";
proj_platform_cfg += "\n";
}
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);
FileAccessRef file = FileAccess::open(path_join(path, name + ".sln"), FileAccess::WRITE);
ERR_FAIL_COND_V(!file, ERR_FILE_CANT_WRITE);
FileAccess *file = FileAccess::open(path_join(path, name + ".sln"), FileAccess::WRITE);
ERR_FAIL_NULL_V(file, ERR_FILE_CANT_WRITE);
file->store_string(content);
file->close();
memdelete(file);
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()) {
path = p_existing_path;
} else {
@ -126,6 +131,10 @@ bool NETSolution::set_path(const String &p_existing_path) {
return true;
}
NETSolution::NETSolution(const String &p_name) {
String DotNetSolution::get_path() {
return path;
}
DotNetSolution::DotNetSolution(const String &p_name) {
name = p_name;
}

View file

@ -1,5 +1,5 @@
/*************************************************************************/
/* net_solution.h */
/* dotnet_solution.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@ -34,23 +34,28 @@
#include "core/map.h"
#include "core/ustring.h"
struct NETSolution {
struct DotNetSolution {
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();
bool set_path(const String &p_existing_path);
String get_path();
NETSolution(const String &p_name);
DotNetSolution(const String &p_name);
private:
struct ProjectInfo {
String guid;
Vector<String> configs;
};
String path;
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();
}
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_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");
String api_sln_file = p_api_sln_dir.plus_file(API_SOLUTION_NAME ".sln");
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);
// TODO Replace this global NoWarn with '#pragma warning' directives on generated files,
// once we start to actively document manually maintained C# classes
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 " + p_name + " solution.");
show_build_error_dialog("Failed to build " API_SOLUTION_NAME " solution.");
return false;
}
}
@ -302,9 +306,9 @@ String GodotSharpBuilds::_api_folder_name(APIAssembly::Type p_api_type) {
"_" + 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 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";
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()
.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 = GodotSharpDirs::get_mono_solutions_dir()
.plus_file(_api_folder_name(APIAssembly::API_CORE));
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_name + ".sln");
String api_sln_file = api_sln_dir.plus_file(API_SOLUTION_NAME ".sln");
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();
bool gen_verbose = OS::get_singleton()->is_stdout_verbose();
Error err = p_api_type == APIAssembly::API_CORE ?
gen->generate_cs_core_project(api_sln_dir, gen_verbose) :
gen->generate_cs_editor_project(api_sln_dir, core_api_assembly, gen_verbose);
Error err = gen->generate_cs_api(api_sln_dir, gen_verbose);
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;
}
}
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;
pr.step("Copying " + api_name + " assembly", 2);
// 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))
return false;
@ -377,10 +361,10 @@ bool GodotSharpBuilds::build_project_blocking(const String &p_config) {
if (!FileAccess::exists(GodotSharpDirs::get_project_sln_path()))
return true; // No solution to build
if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_CORE))
if (!GodotSharpBuilds::make_api_assembly(APIAssembly::API_CORE))
return false;
if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_EDITOR))
if (!GodotSharpBuilds::make_api_assembly(APIAssembly::API_EDITOR))
return false;
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);
ERR_FAIL_COND_V(metadata_err != OK, false);
DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
Error copy_err = da->copy(scripts_metadata_path_editor, scripts_metadata_path_player);
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);
ERR_EXPLAIN("Failed to copy scripts metadata file");
ERR_FAIL_COND_V(copy_err != OK, false);
}
return build_project_blocking("Tools");
}

View file

@ -84,10 +84,10 @@ public:
bool build(const MonoBuildInfo &p_build_info);
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 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);

View file

@ -42,8 +42,8 @@
#include "../utils/path_utils.h"
#include "bindings_generator.h"
#include "csharp_project.h"
#include "dotnet_solution.h"
#include "godotsharp_export.h"
#include "net_solution.h"
#ifdef OSX_ENABLED
#include "../utils/osx_utils.h"
@ -71,17 +71,21 @@ bool GodotSharpEditor::_create_project_solution() {
if (guid.length()) {
NETSolution solution(name);
DotNetSolution solution(name);
if (!solution.set_path(path)) {
show_error_dialog(TTR("Failed to create solution."));
return false;
}
Vector<String> extra_configs;
extra_configs.push_back("Tools");
DotNetSolution::ProjectInfo proj_info;
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();
@ -90,10 +94,10 @@ bool GodotSharpEditor::_create_project_solution() {
return false;
}
if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_CORE))
if (!GodotSharpBuilds::make_api_assembly(APIAssembly::API_CORE))
return false;
if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_EDITOR))
if (!GodotSharpBuilds::make_api_assembly(APIAssembly::API_EDITOR))
return false;
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
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)) {
if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_CORE))
if (!GodotSharpBuilds::make_api_assembly(APIAssembly::API_CORE))
return;
}
if (!FileAccess::exists(res_assemblies_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll")) ||
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
}
}

View file

@ -36,7 +36,8 @@
#define BINDINGS_GLOBAL_SCOPE_CLASS "GD"
#define BINDINGS_PTR_FIELD "ptr"
#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_TOOLS_ASSEMBLY_NAME "GodotSharpTools"

View file

@ -496,12 +496,12 @@ bool GDMono::_load_core_api_assembly() {
}
#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))
return false;
bool success = load_assembly_from(API_ASSEMBLY_NAME,
bool success = load_assembly_from(CORE_API_ASSEMBLY_NAME,
assembly_path,
&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()
.plus_file(p_api_type == APIAssembly::API_CORE ?
API_ASSEMBLY_NAME ".dll" :
CORE_API_ASSEMBLY_NAME ".dll" :
EDITOR_API_ASSEMBLY_NAME ".dll");
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()
.plus_file(p_api_type == APIAssembly::API_CORE ?
API_ASSEMBLY_NAME ".dll" :
CORE_API_ASSEMBLY_NAME ".dll" :
EDITOR_API_ASSEMBLY_NAME ".dll");
if (!FileAccess::exists(assembly_path))

View file

@ -631,36 +631,36 @@ void set_pending_exception(MonoException *p_exc) {
_THREAD_LOCAL_(int)
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;
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;
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;
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;
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;
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;
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;
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;
}
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;
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;
return ret;
}

View file

@ -233,13 +233,13 @@ _FORCE_INLINE_ int &get_runtime_invoke_count_ref() {
return current_invoke_count;
}
MonoObject *runtime_invoke(MonoMethod *p_method, void *p_obj, void **p_params, MonoException **p_exc);
MonoObject *runtime_invoke_array(MonoMethod *p_method, void *p_obj, MonoArray *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 **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);
MonoObject *property_get_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 **r_exc);
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) {
#ifdef WINDOWS_ENABLED
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("\\", "/");
int pos = abspath.find(":/");
if (pos != -1) {
@ -99,10 +99,12 @@ bool rel_path_to_abs(const String &p_existing_path, String &r_abs_path) {
return true;
}
#else
char ret[PATH_MAX];
if (realpath(p_existing_path.utf8().get_data(), ret)) {
char *resolved_path = ::realpath(p_existing_path.utf8().get_data(), NULL);
if (resolved_path) {
String retstr;
if (!retstr.parse_utf8(ret)) {
bool success = !retstr.parse_utf8(resolved_path);
::free(resolved_path);
if (success) {
r_abs_path = retstr;
return true;
}