Browse Source

Fix --generate-mono-glue bug when directory doesn't exist

DirAccess::get_full_path(path) only works if the path exists. Implement our own abspath function.
Ignacio Etcheverry 6 năm trước cách đây
mục cha
commit
5ed3d34cd9

+ 12 - 12
modules/mono/editor/bindings_generator.cpp

@@ -875,14 +875,14 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir, Vect
 	da->make_dir("Core");
 	da->make_dir("ObjectType");
 
-	String core_dir = path_join(p_proj_dir, "Core");
-	String obj_type_dir = path_join(p_proj_dir, "ObjectType");
+	String core_dir = path::join(p_proj_dir, "Core");
+	String obj_type_dir = path::join(p_proj_dir, "ObjectType");
 
 	// Generate source file for global scope constants and enums
 	{
 		StringBuilder constants_source;
 		_generate_global_constants(constants_source);
-		String output_file = path_join(core_dir, BINDINGS_GLOBAL_SCOPE_CLASS "_constants.cs");
+		String output_file = path::join(core_dir, BINDINGS_GLOBAL_SCOPE_CLASS "_constants.cs");
 		Error save_err = _save_file(output_file, constants_source);
 		if (save_err != OK)
 			return save_err;
@@ -896,7 +896,7 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir, Vect
 		if (itype.api_type == ClassDB::API_EDITOR)
 			continue;
 
-		String output_file = path_join(obj_type_dir, itype.proxy_name + ".cs");
+		String output_file = path::join(obj_type_dir, itype.proxy_name + ".cs");
 		Error err = _generate_cs_type(itype, output_file);
 
 		if (err == ERR_SKIP)
@@ -917,7 +917,7 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir, Vect
 		const String &file_name = E->key();
 		const GodotCsCompressedFile &file_data = E->value();
 
-		String output_file = path_join(core_dir, file_name);
+		String output_file = path::join(core_dir, file_name);
 
 		Vector<uint8_t> data;
 		data.resize(file_data.uncompressed_size);
@@ -971,7 +971,7 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir, Vect
 
 	cs_icalls_content.append(INDENT1 CLOSE_BLOCK CLOSE_BLOCK);
 
-	String internal_methods_file = path_join(core_dir, BINDINGS_CLASS_NATIVECALLS ".cs");
+	String internal_methods_file = path::join(core_dir, BINDINGS_CLASS_NATIVECALLS ".cs");
 
 	Error err = _save_file(internal_methods_file, cs_icalls_content);
 	if (err != OK)
@@ -996,8 +996,8 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir, Ve
 	da->make_dir("Core");
 	da->make_dir("ObjectType");
 
-	String core_dir = path_join(p_proj_dir, "Core");
-	String obj_type_dir = path_join(p_proj_dir, "ObjectType");
+	String core_dir = path::join(p_proj_dir, "Core");
+	String obj_type_dir = path::join(p_proj_dir, "ObjectType");
 
 	for (OrderedHashMap<StringName, TypeInterface>::Element E = obj_types.front(); E; E = E.next()) {
 		const TypeInterface &itype = E.get();
@@ -1005,7 +1005,7 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir, Ve
 		if (itype.api_type != ClassDB::API_EDITOR)
 			continue;
 
-		String output_file = path_join(obj_type_dir, itype.proxy_name + ".cs");
+		String output_file = path::join(obj_type_dir, itype.proxy_name + ".cs");
 		Error err = _generate_cs_type(itype, output_file);
 
 		if (err == ERR_SKIP)
@@ -1051,7 +1051,7 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir, Ve
 
 	cs_icalls_content.append(INDENT1 CLOSE_BLOCK CLOSE_BLOCK);
 
-	String internal_methods_file = path_join(core_dir, BINDINGS_CLASS_NATIVECALLS_EDITOR ".cs");
+	String internal_methods_file = path::join(core_dir, BINDINGS_CLASS_NATIVECALLS_EDITOR ".cs");
 
 	Error err = _save_file(internal_methods_file, cs_icalls_content);
 	if (err != OK)
@@ -1064,7 +1064,7 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir, Ve
 
 Error BindingsGenerator::generate_cs_api(const String &p_output_dir) {
 
-	String output_dir = DirAccess::get_full_path(p_output_dir, DirAccess::ACCESS_FILESYSTEM);
+	String output_dir = path::abspath(path::realpath(p_output_dir));
 
 	DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
 	ERR_FAIL_COND_V(!da, ERR_CANT_CREATE);
@@ -1862,7 +1862,7 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) {
 
 	output.append("\n#endif // MONO_GLUE_ENABLED\n");
 
-	Error save_err = _save_file(path_join(p_output_dir, "mono_glue.gen.cpp"), output);
+	Error save_err = _save_file(path::join(p_output_dir, "mono_glue.gen.cpp"), output);
 	if (save_err != OK)
 		return save_err;
 

+ 3 - 3
modules/mono/mono_gd/gd_mono.cpp

@@ -241,9 +241,9 @@ void GDMono::initialize() {
 		locations.push_back("/usr/local/var/homebrew/linked/mono/");
 
 		for (int i = 0; i < locations.size(); i++) {
-			String hint_assembly_rootdir = path_join(locations[i], "lib");
-			String hint_mscorlib_path = path_join(hint_assembly_rootdir, "mono", "4.5", "mscorlib.dll");
-			String hint_config_dir = path_join(locations[i], "etc");
+			String hint_assembly_rootdir = path::join(locations[i], "lib");
+			String hint_mscorlib_path = path::join(hint_assembly_rootdir, "mono", "4.5", "mscorlib.dll");
+			String hint_config_dir = path::join(locations[i], "etc");
 
 			if (FileAccess::exists(hint_mscorlib_path) && DirAccess::exists(hint_config_dir)) {
 				assembly_rootdir = hint_assembly_rootdir;

+ 93 - 34
modules/mono/utils/path_utils.cpp

@@ -36,16 +36,21 @@
 #include "core/project_settings.h"
 
 #ifdef WINDOWS_ENABLED
+#include <windows.h>
+
 #define ENV_PATH_SEP ";"
 #else
-#define ENV_PATH_SEP ":"
 #include <limits.h>
+#include <unistd.h>
+
+#define ENV_PATH_SEP ":"
 #endif
 
 #include <stdlib.h>
 
-String path_which(const String &p_name) {
+namespace path {
 
+String find_executable(const String &p_name) {
 #ifdef WINDOWS_ENABLED
 	Vector<String> exts = OS::get_singleton()->get_environment("PATHEXT").split(ENV_PATH_SEP, false);
 #endif
@@ -55,7 +60,7 @@ String path_which(const String &p_name) {
 		return String();
 
 	for (int i = 0; i < env_path.size(); i++) {
-		String p = path_join(env_path[i], p_name);
+		String p = path::join(env_path[i], p_name);
 
 #ifdef WINDOWS_ENABLED
 		for (int j = 0; j < exts.size(); j++) {
@@ -73,42 +78,96 @@ String path_which(const String &p_name) {
 	return String();
 }
 
-void fix_path(const String &p_path, String &r_out) {
-	r_out = p_path.replace("\\", "/");
+String cwd() {
+#ifdef WINDOWS_ENABLED
+	const DWORD expected_size = ::GetCurrentDirectoryW(0, NULL);
+
+	String buffer;
+	buffer.resize((int)expected_size);
+	if (::GetCurrentDirectoryW(expected_size, buffer.ptrw()) == 0)
+		return ".";
+
+	return buffer.simplify_path();
+#else
+	char buffer[PATH_MAX];
+	if (::getcwd(buffer, sizeof(buffer)) == NULL)
+		return ".";
+
+	String result;
+	if (result.parse_utf8(buffer))
+		return ".";
 
-	while (true) { // in case of using 2 or more slash
-		String compare = r_out.replace("//", "/");
-		if (r_out == compare)
-			break;
-		else
-			r_out = compare;
+	return result.simplify_path();
+#endif
+}
+
+String abspath(const String &p_path) {
+	if (p_path.is_abs_path()) {
+		return p_path.simplify_path();
+	} else {
+		return path::join(path::cwd(), p_path).simplify_path();
 	}
 }
 
-bool rel_path_to_abs(const String &p_existing_path, String &r_abs_path) {
+String realpath(const String &p_path) {
 #ifdef WINDOWS_ENABLED
-	CharType ret[_MAX_PATH];
-	if (::_wfullpath(ret, p_existing_path.c_str(), _MAX_PATH)) {
-		String abspath = String(ret).replace("\\", "/");
-		int pos = abspath.find(":/");
-		if (pos != -1) {
-			r_abs_path = abspath.substr(pos - 1, abspath.length());
-		} else {
-			r_abs_path = abspath;
-		}
-		return true;
-	}
-#else
-	char *resolved_path = ::realpath(p_existing_path.utf8().get_data(), NULL);
-	if (resolved_path) {
-		String retstr;
-		bool success = !retstr.parse_utf8(resolved_path);
-		::free(resolved_path);
-		if (success) {
-			r_abs_path = retstr;
-			return true;
-		}
+	// Open file without read/write access
+	HANDLE hFile = ::CreateFileW(p_path.c_str(), 0,
+			FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+			NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+	if (hFile == INVALID_HANDLE_VALUE)
+		return p_path;
+
+	const DWORD expected_size = ::GetFinalPathNameByHandleW(hFile, NULL, 0, FILE_NAME_NORMALIZED);
+
+	if (expected_size == 0) {
+		::CloseHandle(hFile);
+		return p_path;
 	}
+
+	String buffer;
+	buffer.resize((int)expected_size);
+	::GetFinalPathNameByHandleW(hFile, buffer.ptrw(), expected_size, FILE_NAME_NORMALIZED);
+
+	::CloseHandle(hFile);
+	return buffer.simplify_path();
+#elif UNIX_ENABLED
+	char *resolved_path = ::realpath(p_path.utf8().get_data(), NULL);
+
+	if (!resolved_path)
+		return p_path;
+
+	String result;
+	bool parse_ok = result.parse_utf8(resolved_path);
+	::free(resolved_path);
+
+	if (parse_ok)
+		return p_path;
+
+	return result.simplify_path();
 #endif
-	return false;
 }
+
+String join(const String &p_a, const String &p_b) {
+	if (p_a.empty())
+		return p_b;
+
+	const CharType a_last = p_a[p_a.length() - 1];
+	if ((a_last == '/' || a_last == '\\') ||
+			(p_b.size() > 0 && (p_b[0] == '/' || p_b[0] == '\\'))) {
+		return p_a + p_b;
+	}
+
+	return p_a + "/" + p_b;
+}
+
+String join(const String &p_a, const String &p_b, const String &p_c) {
+	return path::join(path::join(p_a, p_b), p_c);
+}
+
+String join(const String &p_a, const String &p_b, const String &p_c, const String &p_d) {
+	return path::join(path::join(path::join(p_a, p_b), p_c), p_d);
+}
+
+} // namespace path

+ 20 - 12
modules/mono/utils/path_utils.h

@@ -31,24 +31,32 @@
 #ifndef PATH_UTILS_H
 #define PATH_UTILS_H
 
+#include "core/string_builder.h"
 #include "core/ustring.h"
 
-_FORCE_INLINE_ String path_join(const String &e1, const String &e2) {
-	return e1.plus_file(e2);
-}
+namespace path {
 
-_FORCE_INLINE_ String path_join(const String &e1, const String &e2, const String &e3) {
-	return e1.plus_file(e2).plus_file(e3);
-}
+String join(const String &p_a, const String &p_b);
+String join(const String &p_a, const String &p_b, const String &p_c);
+String join(const String &p_a, const String &p_b, const String &p_c, const String &p_d);
 
-_FORCE_INLINE_ String path_join(const String &e1, const String &e2, const String &e3, const String &e4) {
-	return e1.plus_file(e2).plus_file(e3).plus_file(e4);
-}
+String find_executable(const String &p_name);
 
-String path_which(const String &p_name);
+/// Returns a normalized absolute path to the current working directory
+String cwd();
 
-void fix_path(const String &p_path, String &r_out);
+/**
+ * Obtains a normalized absolute path to p_path. Symbolic links are
+ * not resolved. The path p_path might not exist in the file system.
+ */
+String abspath(const String &p_path);
 
-bool rel_path_to_abs(const String &p_existing_path, String &r_abs_path);
+/**
+ * Obtains a normalized path to p_path with symbolic links resolved.
+ * The resulting path might be either a relative or an absolute path.
+ */
+String realpath(const String &p_path);
+
+} // namespace path
 
 #endif // PATH_UTILS_H