Merge pull request #56047 from piiertho/feature/osx-sign-directory

This commit is contained in:
Rémi Verschelde 2022-01-05 14:38:17 +01:00 committed by GitHub
commit 63d9308b4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 138 additions and 16 deletions

View File

@ -96,12 +96,22 @@
Adds a static lib from the given [code]path[/code] to the iOS project. Adds a static lib from the given [code]path[/code] to the iOS project.
</description> </description>
</method> </method>
<method name="add_osx_plugin_file">
<return type="void" />
<argument index="0" name="path" type="String" />
<description>
Adds file or directory matching [code]path[/code] to [code]PlugIns[/code] directory of macOS app bundle.
[b]Note:[/b] This is useful only for macOS exports.
</description>
</method>
<method name="add_shared_object"> <method name="add_shared_object">
<return type="void" /> <return type="void" />
<argument index="0" name="path" type="String" /> <argument index="0" name="path" type="String" />
<argument index="1" name="tags" type="PackedStringArray" /> <argument index="1" name="tags" type="PackedStringArray" />
<description> <description>
Adds a shared object with the given [code]tags[/code] and destination [code]path[/code]. Adds a shared object or a directory containing only shared objects with the given [code]tags[/code] and destination [code]path[/code].
[b]Note:[/b] In case of macOS exports, those shared objects will be added to [code]Frameworks[/code] directory of app bundle.
In case of a directory code-sign will error if you place non code object in directory.
</description> </description>
</method> </method>
<method name="skip"> <method name="skip">

View File

@ -620,6 +620,14 @@ String EditorExportPlugin::get_ios_cpp_code() const {
return ios_cpp_code; return ios_cpp_code;
} }
void EditorExportPlugin::add_osx_plugin_file(const String &p_path) {
osx_plugin_files.push_back(p_path);
}
const Vector<String> &EditorExportPlugin::get_osx_plugin_files() const {
return osx_plugin_files;
}
void EditorExportPlugin::add_ios_project_static_lib(const String &p_path) { void EditorExportPlugin::add_ios_project_static_lib(const String &p_path) {
ios_project_static_libs.push_back(p_path); ios_project_static_libs.push_back(p_path);
} }
@ -660,6 +668,7 @@ void EditorExportPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_ios_linker_flags", "flags"), &EditorExportPlugin::add_ios_linker_flags); ClassDB::bind_method(D_METHOD("add_ios_linker_flags", "flags"), &EditorExportPlugin::add_ios_linker_flags);
ClassDB::bind_method(D_METHOD("add_ios_bundle_file", "path"), &EditorExportPlugin::add_ios_bundle_file); ClassDB::bind_method(D_METHOD("add_ios_bundle_file", "path"), &EditorExportPlugin::add_ios_bundle_file);
ClassDB::bind_method(D_METHOD("add_ios_cpp_code", "code"), &EditorExportPlugin::add_ios_cpp_code); ClassDB::bind_method(D_METHOD("add_ios_cpp_code", "code"), &EditorExportPlugin::add_ios_cpp_code);
ClassDB::bind_method(D_METHOD("add_osx_plugin_file", "path"), &EditorExportPlugin::add_osx_plugin_file);
ClassDB::bind_method(D_METHOD("skip"), &EditorExportPlugin::skip); ClassDB::bind_method(D_METHOD("skip"), &EditorExportPlugin::skip);
GDVIRTUAL_BIND(_export_file, "path", "type", "features"); GDVIRTUAL_BIND(_export_file, "path", "type", "features");

View File

@ -308,6 +308,8 @@ class EditorExportPlugin : public RefCounted {
Vector<String> ios_bundle_files; Vector<String> ios_bundle_files;
String ios_cpp_code; String ios_cpp_code;
Vector<String> osx_plugin_files;
_FORCE_INLINE_ void _clear() { _FORCE_INLINE_ void _clear() {
shared_objects.clear(); shared_objects.clear();
extra_files.clear(); extra_files.clear();
@ -321,6 +323,7 @@ class EditorExportPlugin : public RefCounted {
ios_plist_content = ""; ios_plist_content = "";
ios_linker_flags = ""; ios_linker_flags = "";
ios_cpp_code = ""; ios_cpp_code = "";
osx_plugin_files.clear();
} }
void _export_file_script(const String &p_path, const String &p_type, const Vector<String> &p_features); void _export_file_script(const String &p_path, const String &p_type, const Vector<String> &p_features);
@ -341,6 +344,7 @@ protected:
void add_ios_linker_flags(const String &p_flags); void add_ios_linker_flags(const String &p_flags);
void add_ios_bundle_file(const String &p_path); void add_ios_bundle_file(const String &p_path);
void add_ios_cpp_code(const String &p_code); void add_ios_cpp_code(const String &p_code);
void add_osx_plugin_file(const String &p_path);
void skip(); void skip();
@ -361,6 +365,7 @@ public:
String get_ios_linker_flags() const; String get_ios_linker_flags() const;
Vector<String> get_ios_bundle_files() const; Vector<String> get_ios_bundle_files() const;
String get_ios_cpp_code() const; String get_ios_cpp_code() const;
const Vector<String> &get_osx_plugin_files() const;
EditorExportPlugin(); EditorExportPlugin();
}; };

View File

@ -435,6 +435,101 @@ Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_prese
return OK; return OK;
} }
Error EditorExportPlatformOSX::_code_sign_directory(const Ref<EditorExportPreset> &p_preset, const String &p_path,
const String &p_ent_path, bool p_should_error_on_non_code) {
#ifdef OSX_ENABLED
static Vector<String> extensions_to_sign;
if (extensions_to_sign.is_empty()) {
extensions_to_sign.push_back("dylib");
extensions_to_sign.push_back("framework");
}
Error dir_access_error;
DirAccessRef dir_access{ DirAccess::open(p_path, &dir_access_error) };
if (dir_access_error != OK) {
return dir_access_error;
}
dir_access->list_dir_begin();
String current_file{ dir_access->get_next() };
while (!current_file.is_empty()) {
String current_file_path{ p_path.plus_file(current_file) };
if (current_file == ".." || current_file == ".") {
current_file = dir_access->get_next();
continue;
}
if (extensions_to_sign.find(current_file.get_extension()) > -1) {
Error code_sign_error{ _code_sign(p_preset, current_file_path, p_ent_path) };
if (code_sign_error != OK) {
return code_sign_error;
}
} else if (dir_access->current_is_dir()) {
Error code_sign_error{ _code_sign_directory(p_preset, current_file_path, p_ent_path, p_should_error_on_non_code) };
if (code_sign_error != OK) {
return code_sign_error;
}
} else if (p_should_error_on_non_code) {
ERR_PRINT(vformat("Cannot sign file %s.", current_file));
return Error::FAILED;
}
current_file = dir_access->get_next();
}
#endif
return OK;
}
Error EditorExportPlatformOSX::_copy_and_sign_files(DirAccessRef &dir_access, const String &p_src_path,
const String &p_in_app_path, bool p_sign_enabled,
const Ref<EditorExportPreset> &p_preset, const String &p_ent_path,
bool p_should_error_on_non_code_sign) {
Error err{ OK };
if (dir_access->dir_exists(p_src_path)) {
#ifndef UNIX_ENABLED
WARN_PRINT("Relative symlinks are not supported, exported " + p_src_path.get_file() + " might be broken!");
#endif
print_verbose("export framework: " + p_src_path + " -> " + p_in_app_path);
err = dir_access->make_dir_recursive(p_in_app_path);
if (err == OK) {
err = dir_access->copy_dir(p_src_path, p_in_app_path, -1, true);
}
} else {
print_verbose("export dylib: " + p_src_path + " -> " + p_in_app_path);
err = dir_access->copy(p_src_path, p_in_app_path);
}
if (err == OK && p_sign_enabled) {
if (dir_access->dir_exists(p_src_path) && p_src_path.get_extension().is_empty()) {
// If it is a directory, find and sign all dynamic libraries.
err = _code_sign_directory(p_preset, p_in_app_path, p_ent_path, p_should_error_on_non_code_sign);
} else {
err = _code_sign(p_preset, p_in_app_path, p_ent_path);
}
}
return err;
}
Error EditorExportPlatformOSX::_export_osx_plugins_for(Ref<EditorExportPlugin> p_editor_export_plugin,
const String &p_app_path_name, DirAccessRef &dir_access,
bool p_sign_enabled, const Ref<EditorExportPreset> &p_preset,
const String &p_ent_path) {
Error error{ OK };
const Vector<String> &osx_plugins{ p_editor_export_plugin->get_osx_plugin_files() };
for (int i = 0; i < osx_plugins.size(); ++i) {
String src_path{ ProjectSettings::get_singleton()->globalize_path(osx_plugins[i]) };
String path_in_app{ p_app_path_name + "/Contents/PlugIns/" + src_path.get_file() };
error = _copy_and_sign_files(dir_access, src_path, path_in_app, p_sign_enabled, p_preset, p_ent_path, false);
if (error != OK) {
break;
}
}
return error;
}
Error EditorExportPlatformOSX::_create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name) { Error EditorExportPlatformOSX::_create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name) {
List<String> args; List<String> args;
@ -860,26 +955,22 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
FileAccess::set_unix_permissions(tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file(), 0755); FileAccess::set_unix_permissions(tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file(), 0755);
} }
} }
if (err == OK) { if (err == OK) {
DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
for (int i = 0; i < shared_objects.size(); i++) { for (int i = 0; i < shared_objects.size(); i++) {
String src_path = ProjectSettings::get_singleton()->globalize_path(shared_objects[i].path); String src_path = ProjectSettings::get_singleton()->globalize_path(shared_objects[i].path);
if (da->dir_exists(src_path)) { String path_in_app{ tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file() };
#ifndef UNIX_ENABLED err = _copy_and_sign_files(da, src_path, path_in_app, sign_enabled, p_preset, ent_path, true);
WARN_PRINT("Relative symlinks are not supported, exported " + src_path.get_file() + " might be broken!"); if (err != OK) {
#endif break;
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/" + src_path.get_file(), ent_path);
Vector<Ref<EditorExportPlugin>> export_plugins{ EditorExport::get_singleton()->get_export_plugins() };
for (int i = 0; i < export_plugins.size(); ++i) {
err = _export_osx_plugins_for(export_plugins[i], tmp_app_path_name, da, sign_enabled, p_preset, ent_path);
if (err != OK) {
break;
} }
} }
} }

View File

@ -58,6 +58,13 @@ class EditorExportPlatformOSX : public EditorExportPlatform {
Error _notarize(const Ref<EditorExportPreset> &p_preset, const String &p_path); Error _notarize(const Ref<EditorExportPreset> &p_preset, const String &p_path);
Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path); Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path);
Error _code_sign_directory(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, bool p_should_error_on_non_code = true);
Error _copy_and_sign_files(DirAccessRef &dir_access, const String &p_src_path, const String &p_in_app_path,
bool p_sign_enabled, const Ref<EditorExportPreset> &p_preset, const String &p_ent_path,
bool p_should_error_on_non_code_sign);
Error _export_osx_plugins_for(Ref<EditorExportPlugin> p_editor_export_plugin, const String &p_app_path_name,
DirAccessRef &dir_access, bool p_sign_enabled, const Ref<EditorExportPreset> &p_preset,
const String &p_ent_path);
Error _create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name); Error _create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name);
void _zip_folder_recursive(zipFile &p_zip, const String &p_root_path, const String &p_folder, const String &p_pkg_name); void _zip_folder_recursive(zipFile &p_zip, const String &p_root_path, const String &p_folder, const String &p_pkg_name);