summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/io/file_access_pack.h4
-rw-r--r--core/os/dir_access.cpp12
-rw-r--r--core/os/dir_access.h8
-rw-r--r--drivers/unix/dir_access_unix.cpp47
-rw-r--r--drivers/unix/dir_access_unix.h4
-rw-r--r--drivers/windows/dir_access_windows.h4
-rw-r--r--modules/gdnative/gdnative.cpp12
-rw-r--r--modules/gdnative/gdnative_library_editor_plugin.cpp9
-rw-r--r--platform/android/dir_access_jandroid.h4
-rw-r--r--platform/osx/export/export.cpp60
10 files changed, 148 insertions, 16 deletions
diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h
index e47c9ea543..763c0fb327 100644
--- a/core/io/file_access_pack.h
+++ b/core/io/file_access_pack.h
@@ -245,6 +245,10 @@ public:
uint64_t get_space_left();
+ 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;
DirAccessPack();
diff --git a/core/os/dir_access.cpp b/core/os/dir_access.cpp
index b7c3a17ba9..39ae475c12 100644
--- a/core/os/dir_access.cpp
+++ b/core/os/dir_access.cpp
@@ -331,7 +331,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();
@@ -339,7 +339,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;
@@ -371,7 +373,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.");
@@ -383,7 +385,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);
@@ -402,7 +404,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;
diff --git a/core/os/dir_access.h b/core/os/dir_access.h
index ec738d30d5..16154a4850 100644
--- a/core/os/dir_access.h
+++ b/core/os/dir_access.h
@@ -50,7 +50,7 @@ private:
AccessType _access_type = ACCESS_FILESYSTEM;
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) {
diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp
index 3323da5db4..5abe5d2c87 100644
--- a/drivers/unix/dir_access_unix.cpp
+++ b/drivers/unix/dir_access_unix.cpp
@@ -406,6 +406,53 @@ 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;
diff --git a/drivers/unix/dir_access_unix.h b/drivers/unix/dir_access_unix.h
index 12994a6b76..28a7053d25 100644
--- a/drivers/unix/dir_access_unix.h
+++ b/drivers/unix/dir_access_unix.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);
+ 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;
diff --git a/drivers/windows/dir_access_windows.h b/drivers/windows/dir_access_windows.h
index 553d5c4701..b151b631e9 100644
--- a/drivers/windows/dir_access_windows.h
+++ b/drivers/windows/dir_access_windows.h
@@ -78,6 +78,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;
diff --git a/modules/gdnative/gdnative.cpp b/modules/gdnative/gdnative.cpp
index 0de6b27d27..7c3b76e4d7 100644
--- a/modules/gdnative/gdnative.cpp
+++ b/modules/gdnative/gdnative.cpp
@@ -33,6 +33,7 @@
#include "core/config/project_settings.h"
#include "core/core_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"
@@ -335,9 +336,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
diff --git a/modules/gdnative/gdnative_library_editor_plugin.cpp b/modules/gdnative/gdnative_library_editor_plugin.cpp
index dfb26c13e3..b4ac0d886e 100644
--- a/modules/gdnative/gdnative_library_editor_plugin.cpp
+++ b/modules/gdnative/gdnative_library_editor_plugin.cpp
@@ -131,7 +131,7 @@ void GDNativeLibraryEditor::_on_item_button(Object *item, int column, int id) {
EditorFileDialog::FileMode mode = EditorFileDialog::FILE_MODE_OPEN_FILE;
if (id == BUTTON_SELECT_DEPENDENCES) {
mode = EditorFileDialog::FILE_MODE_OPEN_FILES;
- } else if (treeItem->get_text(0) == "iOS") {
+ } else if (treeItem->get_text(0) == "iOS" || treeItem->get_text(0) == "macOS") {
mode = EditorFileDialog::FILE_MODE_OPEN_ANY;
}
@@ -278,11 +278,10 @@ 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";
- platforms["OSX"] = platform_osx;
+ platform_osx.library_extension = "*.framework; Framework, *.dylib; Dynamic Library";
+ platforms["macOS"] = platform_osx;
NativePlatformConfig platform_haiku;
platform_haiku.name = "Haiku";
diff --git a/platform/android/dir_access_jandroid.h b/platform/android/dir_access_jandroid.h
index fe87644fe2..7b9cbeea47 100644
--- a/platform/android/dir_access_jandroid.h
+++ b/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();
diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp
index a7868efaa8..b2f881a8a8 100644
--- a/platform/osx/export/export.cpp
+++ b/platform/osx/export/export.cpp
@@ -894,9 +894,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);
@@ -980,7 +993,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));