2
0
Эх сурвалжийг харах

Merge pull request #46860 from bruvzg/symlinks_and_macos_gdn_framework_export

Rémi Verschelde 4 жил өмнө
parent
commit
b94b09cd19

+ 4 - 0
core/io/file_access_pack.h

@@ -235,6 +235,10 @@ public:
 	virtual Error rename(String p_from, String p_to);
 	virtual Error remove(String p_name);
 
+	virtual bool is_link(String p_file) { return false; }
+	virtual String read_link(String p_file) { return p_file; }
+	virtual Error create_link(String p_source, String p_target) { return FAILED; }
+
 	uint64_t get_space_left();
 
 	virtual String get_filesystem_type() const;

+ 7 - 5
core/os/dir_access.cpp

@@ -334,7 +334,7 @@ public:
 	}
 };
 
-Error DirAccess::_copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flags) {
+Error DirAccess::_copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flags, bool p_copy_links) {
 	List<String> dirs;
 
 	String curdir = get_current_dir();
@@ -342,7 +342,9 @@ Error DirAccess::_copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flag
 	String n = get_next();
 	while (n != String()) {
 		if (n != "." && n != "..") {
-			if (current_is_dir()) {
+			if (p_copy_links && is_link(get_current_dir().plus_file(n))) {
+				create_link(read_link(get_current_dir().plus_file(n)), p_to + n);
+			} else if (current_is_dir()) {
 				dirs.push_back(n);
 			} else {
 				const String &rel_path = n;
@@ -374,7 +376,7 @@ Error DirAccess::_copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flag
 		Error err = change_dir(E->get());
 		ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot change current directory to '" + E->get() + "'.");
 
-		err = _copy_dir(p_target_da, p_to + rel_path + "/", p_chmod_flags);
+		err = _copy_dir(p_target_da, p_to + rel_path + "/", p_chmod_flags, p_copy_links);
 		if (err) {
 			change_dir("..");
 			ERR_FAIL_V_MSG(err, "Failed to copy recursively.");
@@ -386,7 +388,7 @@ Error DirAccess::_copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flag
 	return OK;
 }
 
-Error DirAccess::copy_dir(String p_from, String p_to, int p_chmod_flags) {
+Error DirAccess::copy_dir(String p_from, String p_to, int p_chmod_flags, bool p_copy_links) {
 	ERR_FAIL_COND_V_MSG(!dir_exists(p_from), ERR_FILE_NOT_FOUND, "Source directory doesn't exist.");
 
 	DirAccess *target_da = DirAccess::create_for_path(p_to);
@@ -405,7 +407,7 @@ Error DirAccess::copy_dir(String p_from, String p_to, int p_chmod_flags) {
 	}
 
 	DirChanger dir_changer(this, p_from);
-	Error err = _copy_dir(target_da, p_to, p_chmod_flags);
+	Error err = _copy_dir(target_da, p_to, p_chmod_flags, p_copy_links);
 	memdelete(target_da);
 
 	return err;

+ 6 - 2
core/os/dir_access.h

@@ -50,7 +50,7 @@ private:
 	AccessType _access_type;
 	static CreateFunc create_func[ACCESS_MAX]; ///< set this to instance a filesystem object
 
-	Error _copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flags);
+	Error _copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flags, bool p_copy_links);
 
 protected:
 	String _get_root_path() const;
@@ -89,11 +89,15 @@ public:
 	static bool exists(String p_dir);
 	virtual uint64_t get_space_left() = 0;
 
-	Error copy_dir(String p_from, String p_to, int p_chmod_flags = -1);
+	Error copy_dir(String p_from, String p_to, int p_chmod_flags = -1, bool p_copy_links = false);
 	virtual Error copy(String p_from, String p_to, int p_chmod_flags = -1);
 	virtual Error rename(String p_from, String p_to) = 0;
 	virtual Error remove(String p_name) = 0;
 
+	virtual bool is_link(String p_file) = 0;
+	virtual String read_link(String p_file) = 0;
+	virtual Error create_link(String p_source, String p_target) = 0;
+
 	// Meant for editor code when we want to quickly remove a file without custom
 	// handling (e.g. removing a cache file).
 	static void remove_file_or_error(String p_path) {

+ 43 - 0
drivers/unix/dir_access_unix.cpp

@@ -382,6 +382,49 @@ Error DirAccessUnix::remove(String p_path) {
 	}
 }
 
+bool DirAccessUnix::is_link(String p_file) {
+	if (p_file.is_rel_path())
+		p_file = get_current_dir().plus_file(p_file);
+
+	p_file = fix_path(p_file);
+
+	struct stat flags;
+	if ((lstat(p_file.utf8().get_data(), &flags) != 0))
+		return FAILED;
+
+	return S_ISLNK(flags.st_mode);
+}
+
+String DirAccessUnix::read_link(String p_file) {
+	if (p_file.is_rel_path())
+		p_file = get_current_dir().plus_file(p_file);
+
+	p_file = fix_path(p_file);
+
+	char buf[256];
+	memset(buf, 0, 256);
+	ssize_t len = readlink(p_file.utf8().get_data(), buf, sizeof(buf));
+	String link;
+	if (len > 0) {
+		link.parse_utf8(buf, len);
+	}
+	return link;
+}
+
+Error DirAccessUnix::create_link(String p_source, String p_target) {
+	if (p_target.is_rel_path())
+		p_target = get_current_dir().plus_file(p_target);
+
+	p_source = fix_path(p_source);
+	p_target = fix_path(p_target);
+
+	if (symlink(p_source.utf8().get_data(), p_target.utf8().get_data()) == 0) {
+		return OK;
+	} else {
+		return FAILED;
+	}
+}
+
 uint64_t DirAccessUnix::get_space_left() {
 #ifndef NO_STATVFS
 	struct statvfs vfs;

+ 4 - 0
drivers/unix/dir_access_unix.h

@@ -77,6 +77,10 @@ public:
 	virtual Error rename(String p_path, String p_new_path);
 	virtual Error remove(String p_path);
 
+	virtual bool is_link(String p_file);
+	virtual String read_link(String p_file);
+	virtual Error create_link(String p_source, String p_target);
+
 	virtual uint64_t get_space_left();
 
 	virtual String get_filesystem_type() const;

+ 4 - 0
drivers/windows/dir_access_windows.h

@@ -79,6 +79,10 @@ public:
 	virtual Error rename(String p_path, String p_new_path);
 	virtual Error remove(String p_path);
 
+	virtual bool is_link(String p_file) { return false; };
+	virtual String read_link(String p_file) { return p_file; };
+	virtual Error create_link(String p_source, String p_target) { return FAILED; };
+
 	uint64_t get_space_left();
 
 	virtual String get_filesystem_type() const;

+ 11 - 1
modules/gdnative/gdnative.cpp

@@ -32,6 +32,7 @@
 
 #include "core/global_constants.h"
 #include "core/io/file_access_encrypted.h"
+#include "core/os/dir_access.h"
 #include "core/os/file_access.h"
 #include "core/os/os.h"
 #include "core/project_settings.h"
@@ -325,9 +326,18 @@ bool GDNative::initialize() {
 	// On OSX the exported libraries are located under the Frameworks directory.
 	// So we need to replace the library path.
 	String path = ProjectSettings::get_singleton()->globalize_path(lib_path);
-	if (!FileAccess::exists(path)) {
+	DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+
+	if (!da->file_exists(path) && !da->dir_exists(path)) {
 		path = OS::get_singleton()->get_executable_path().get_base_dir().plus_file("../Frameworks").plus_file(lib_path.get_file());
 	}
+
+	if (da->dir_exists(path)) { // Target library is a ".framework", add library base name to the path.
+		path = path.plus_file(path.get_file().get_basename());
+	}
+
+	memdelete(da);
+
 #else
 	String path = ProjectSettings::get_singleton()->globalize_path(lib_path);
 #endif

+ 3 - 4
modules/gdnative/gdnative_library_editor_plugin.cpp

@@ -139,7 +139,7 @@ void GDNativeLibraryEditor::_on_item_button(Object *item, int column, int id) {
 
 		if (id == BUTTON_SELECT_DEPENDENCES) {
 			mode = EditorFileDialog::MODE_OPEN_FILES;
-		} else if (treeItem->get_text(0) == "iOS") {
+		} else if (treeItem->get_text(0) == "iOS" || treeItem->get_text(0) == "macOS") {
 			mode = EditorFileDialog::MODE_OPEN_ANY;
 		}
 
@@ -286,10 +286,9 @@ GDNativeLibraryEditor::GDNativeLibraryEditor() {
 		platforms["X11"] = platform_linux;
 
 		NativePlatformConfig platform_osx;
-		platform_osx.name = "Mac OSX";
+		platform_osx.name = "macOS";
 		platform_osx.entries.push_back("64");
-		platform_osx.entries.push_back("32");
-		platform_osx.library_extension = "*.dylib";
+		platform_osx.library_extension = "*.framework; Framework, *.dylib; Dynamic Library";
 		platforms["OSX"] = platform_osx;
 
 		NativePlatformConfig platform_haiku;

+ 4 - 0
platform/android/dir_access_jandroid.h

@@ -74,6 +74,10 @@ public:
 	virtual Error rename(String p_from, String p_to);
 	virtual Error remove(String p_name);
 
+	virtual bool is_link(String p_file) { return false; }
+	virtual String read_link(String p_file) { return p_file; }
+	virtual Error create_link(String p_source, String p_target) { return FAILED; }
+
 	virtual String get_filesystem_type() const;
 
 	uint64_t get_space_left();

+ 57 - 3
platform/osx/export/export.cpp

@@ -820,9 +820,22 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
 		if (err == OK) {
 			DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
 			for (int i = 0; i < shared_objects.size(); i++) {
-				err = da->copy(shared_objects[i].path, tmp_app_path_name + "/Contents/Frameworks/" + shared_objects[i].path.get_file());
+				String src_path = ProjectSettings::get_singleton()->globalize_path(shared_objects[i].path);
+				if (da->dir_exists(src_path)) {
+#ifndef UNIX_ENABLED
+					WARN_PRINT("Relative symlinks are not supported, exported " + src_path.get_file() + " might be broken!");
+#endif
+					print_verbose("export framework: " + src_path + " -> " + tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file());
+					err = da->make_dir_recursive(tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file());
+					if (err == OK) {
+						err = da->copy_dir(src_path, tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file(), -1, true);
+					}
+				} else {
+					print_verbose("export dylib: " + src_path + " -> " + tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file());
+					err = da->copy(src_path, tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file());
+				}
 				if (err == OK && sign_enabled) {
-					err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Frameworks/" + shared_objects[i].path.get_file(), ent_path);
+					err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file(), ent_path);
 				}
 			}
 			memdelete(da);
@@ -898,7 +911,48 @@ void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String
 		if (f == "." || f == "..") {
 			continue;
 		}
-		if (da->current_is_dir()) {
+		if (da->is_link(f)) {
+			OS::Time time = OS::get_singleton()->get_time();
+			OS::Date date = OS::get_singleton()->get_date();
+
+			zip_fileinfo zipfi;
+			zipfi.tmz_date.tm_hour = time.hour;
+			zipfi.tmz_date.tm_mday = date.day;
+			zipfi.tmz_date.tm_min = time.min;
+			zipfi.tmz_date.tm_mon = date.month - 1; // Note: "tm" month range - 0..11, Godot month range - 1..12, http://www.cplusplus.com/reference/ctime/tm/
+			zipfi.tmz_date.tm_sec = time.sec;
+			zipfi.tmz_date.tm_year = date.year;
+			zipfi.dosDate = 0;
+			// 0120000: symbolic link type
+			// 0000755: permissions rwxr-xr-x
+			// 0000644: permissions rw-r--r--
+			uint32_t _mode = 0120644;
+			zipfi.external_fa = (_mode << 16L) | !(_mode & 0200);
+			zipfi.internal_fa = 0;
+
+			zipOpenNewFileInZip4(p_zip,
+					p_folder.plus_file(f).utf8().get_data(),
+					&zipfi,
+					nullptr,
+					0,
+					nullptr,
+					0,
+					nullptr,
+					Z_DEFLATED,
+					Z_DEFAULT_COMPRESSION,
+					0,
+					-MAX_WBITS,
+					DEF_MEM_LEVEL,
+					Z_DEFAULT_STRATEGY,
+					nullptr,
+					0,
+					0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions
+					0);
+
+			String target = da->read_link(f);
+			zipWriteInFileInZip(p_zip, target.utf8().get_data(), target.utf8().size());
+			zipCloseFileInZip(p_zip);
+		} else if (da->current_is_dir()) {
 			_zip_folder_recursive(p_zip, p_root_path, p_folder.plus_file(f), p_pkg_name);
 		} else {
 			bool is_executable = (p_folder.ends_with("MacOS") && (f == p_pkg_name));