Merge pull request #46860 from bruvzg/symlinks_and_macos_gdn_framework_export
This commit is contained in:
commit
b94b09cd19
10 changed files with 143 additions and 15 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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));
|
||||
|
|
Loading…
Reference in a new issue