Merge pull request #39996 from naithar/feature/ios-gdnative
[3.2] Add support of iOS's dynamic libraries to GDNative
This commit is contained in:
commit
24f527b561
|
@ -16,6 +16,20 @@
|
||||||
D0BCFE7818AEBFEB004A7AAE /* $binary.pck in Resources */ = {isa = PBXBuildFile; fileRef = D0BCFE7718AEBFEB004A7AAE /* $binary.pck */; };
|
D0BCFE7818AEBFEB004A7AAE /* $binary.pck in Resources */ = {isa = PBXBuildFile; fileRef = D0BCFE7718AEBFEB004A7AAE /* $binary.pck */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
/* Begin PBXCopyFilesBuildPhase section */
|
||||||
|
90A13CD024AA68E500E8464F /* Embed Frameworks */ = {
|
||||||
|
isa = PBXCopyFilesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
dstPath = "";
|
||||||
|
dstSubfolderSpec = 10;
|
||||||
|
files = (
|
||||||
|
$pbx_embeded_frameworks
|
||||||
|
);
|
||||||
|
name = "Embed Frameworks";
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
1F1575711F582BE20003B888 /* dylibs */ = {isa = PBXFileReference; lastKnownFileType = folder; name = dylibs; path = "$binary/dylibs"; sourceTree = "<group>"; };
|
1F1575711F582BE20003B888 /* dylibs */ = {isa = PBXFileReference; lastKnownFileType = folder; name = dylibs; path = "$binary/dylibs"; sourceTree = "<group>"; };
|
||||||
DEADBEEF1F582BE20003B888 /* $binary.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = godot; path = "$binary.a"; sourceTree = "<group>"; };
|
DEADBEEF1F582BE20003B888 /* $binary.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = godot; path = "$binary.a"; sourceTree = "<group>"; };
|
||||||
|
@ -105,6 +119,7 @@
|
||||||
D0BCFE3018AEBDA2004A7AAE /* Sources */,
|
D0BCFE3018AEBDA2004A7AAE /* Sources */,
|
||||||
D0BCFE3118AEBDA2004A7AAE /* Frameworks */,
|
D0BCFE3118AEBDA2004A7AAE /* Frameworks */,
|
||||||
D0BCFE3218AEBDA2004A7AAE /* Resources */,
|
D0BCFE3218AEBDA2004A7AAE /* Resources */,
|
||||||
|
90A13CD024AA68E500E8464F /* Embed Frameworks */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
|
@ -230,7 +245,6 @@
|
||||||
isa = PBXResourcesBuildPhase;
|
isa = PBXResourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
1F1575721F582BE20003B888 /* dylibs in Resources */,
|
|
||||||
D07CD44E1C5D589C00B7FB28 /* Images.xcassets in Resources */,
|
D07CD44E1C5D589C00B7FB28 /* Images.xcassets in Resources */,
|
||||||
D0BCFE7818AEBFEB004A7AAE /* $binary.pck in Resources */,
|
D0BCFE7818AEBFEB004A7AAE /* $binary.pck in Resources */,
|
||||||
D0BCFE4618AEBDA2004A7AAE /* InfoPlist.strings in Resources */,
|
D0BCFE4618AEBDA2004A7AAE /* InfoPlist.strings in Resources */,
|
||||||
|
@ -284,7 +298,9 @@
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "$code_sign_identity_debug";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "$code_sign_identity_debug";
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
"FRAMEWORK_SEARCH_PATHS[arch=*]" = "$binary/**";
|
"FRAMEWORK_SEARCH_PATHS[arch=*]" = (
|
||||||
|
"$(PROJECT_DIR)/**",
|
||||||
|
);
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
GCC_DYNAMIC_NO_PIC = NO;
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
GCC_OPTIMIZATION_LEVEL = 0;
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
|
@ -327,7 +343,9 @@
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "$code_sign_identity_release";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "$code_sign_identity_release";
|
||||||
COPY_PHASE_STRIP = YES;
|
COPY_PHASE_STRIP = YES;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
"FRAMEWORK_SEARCH_PATHS[arch=*]" = "$binary/**";
|
"FRAMEWORK_SEARCH_PATHS[arch=*]" = (
|
||||||
|
"$(PROJECT_DIR)/**",
|
||||||
|
);
|
||||||
ENABLE_NS_ASSERTIONS = NO;
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
@ -357,6 +375,10 @@
|
||||||
DEVELOPMENT_TEAM = $team_id;
|
DEVELOPMENT_TEAM = $team_id;
|
||||||
INFOPLIST_FILE = "$binary/$binary-Info.plist";
|
INFOPLIST_FILE = "$binary/$binary-Info.plist";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
);
|
||||||
LIBRARY_SEARCH_PATHS = (
|
LIBRARY_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)",
|
"$(PROJECT_DIR)",
|
||||||
|
@ -383,6 +405,10 @@
|
||||||
DEVELOPMENT_TEAM = $team_id;
|
DEVELOPMENT_TEAM = $team_id;
|
||||||
INFOPLIST_FILE = "$binary/$binary-Info.plist";
|
INFOPLIST_FILE = "$binary/$binary-Info.plist";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
);
|
||||||
LIBRARY_SEARCH_PATHS = (
|
LIBRARY_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)",
|
"$(PROJECT_DIR)",
|
||||||
|
|
|
@ -26,6 +26,8 @@
|
||||||
<string>$signature</string>
|
<string>$signature</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>$version</string>
|
<string>$version</string>
|
||||||
|
<key>ITSAppUsesNonExemptEncryption</key>
|
||||||
|
<false />
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>LSSupportsOpeningDocumentsInPlace</key>
|
<key>LSSupportsOpeningDocumentsInPlace</key>
|
||||||
|
|
|
@ -291,8 +291,26 @@ bool GDNative::initialize() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#ifdef IPHONE_ENABLED
|
#ifdef IPHONE_ENABLED
|
||||||
// on iOS we use static linking
|
// On iOS we use static linking by default.
|
||||||
String path = "";
|
String path = "";
|
||||||
|
|
||||||
|
// On iOS dylibs is not allowed, but can be replaced with .framework or .xcframework.
|
||||||
|
// If they are used, we can run dlopen on them.
|
||||||
|
// They should be located under Frameworks directory, so we need to replace library path.
|
||||||
|
if (!lib_path.ends_with(".a")) {
|
||||||
|
path = ProjectSettings::get_singleton()->globalize_path(lib_path);
|
||||||
|
|
||||||
|
if (!FileAccess::exists(path)) {
|
||||||
|
String lib_name = lib_path.get_basename().get_file();
|
||||||
|
String framework_path_format = "Frameworks/$name.framework/$name";
|
||||||
|
|
||||||
|
Dictionary format_dict;
|
||||||
|
format_dict["name"] = lib_name;
|
||||||
|
String framework_path = framework_path_format.format(format_dict, "$_");
|
||||||
|
|
||||||
|
path = OS::get_singleton()->get_executable_path().get_base_dir().plus_file(framework_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
#elif defined(ANDROID_ENABLED)
|
#elif defined(ANDROID_ENABLED)
|
||||||
// On Android dynamic libraries are located separately from resource assets,
|
// On Android dynamic libraries are located separately from resource assets,
|
||||||
// we should pass library name to dlopen(). The library name is flattened
|
// we should pass library name to dlopen(). The library name is flattened
|
||||||
|
|
|
@ -141,14 +141,25 @@ void GDNativeLibraryEditor::_on_item_button(Object *item, int column, int id) {
|
||||||
|
|
||||||
if (id == BUTTON_SELECT_LIBRARY || id == BUTTON_SELECT_DEPENDENCES) {
|
if (id == BUTTON_SELECT_LIBRARY || id == BUTTON_SELECT_DEPENDENCES) {
|
||||||
|
|
||||||
|
TreeItem *treeItem = Object::cast_to<TreeItem>(item)->get_parent();
|
||||||
EditorFileDialog::Mode mode = EditorFileDialog::MODE_OPEN_FILE;
|
EditorFileDialog::Mode mode = EditorFileDialog::MODE_OPEN_FILE;
|
||||||
if (id == BUTTON_SELECT_DEPENDENCES)
|
|
||||||
|
if (id == BUTTON_SELECT_DEPENDENCES) {
|
||||||
mode = EditorFileDialog::MODE_OPEN_FILES;
|
mode = EditorFileDialog::MODE_OPEN_FILES;
|
||||||
|
} else if (treeItem->get_text(0) == "iOS") {
|
||||||
|
mode = EditorFileDialog::MODE_OPEN_ANY;
|
||||||
|
}
|
||||||
|
|
||||||
file_dialog->set_meta("target", target);
|
file_dialog->set_meta("target", target);
|
||||||
file_dialog->set_meta("section", section);
|
file_dialog->set_meta("section", section);
|
||||||
file_dialog->clear_filters();
|
file_dialog->clear_filters();
|
||||||
file_dialog->add_filter(Object::cast_to<TreeItem>(item)->get_parent()->get_metadata(0));
|
|
||||||
|
String filter_string = treeItem->get_metadata(0);
|
||||||
|
Vector<String> filters = filter_string.split(",", false, 0);
|
||||||
|
for (int i = 0; i < filters.size(); i++) {
|
||||||
|
file_dialog->add_filter(filters[i]);
|
||||||
|
}
|
||||||
|
|
||||||
file_dialog->set_mode(mode);
|
file_dialog->set_mode(mode);
|
||||||
file_dialog->popup_centered_ratio();
|
file_dialog->popup_centered_ratio();
|
||||||
|
|
||||||
|
@ -332,7 +343,9 @@ GDNativeLibraryEditor::GDNativeLibraryEditor() {
|
||||||
platform_ios.name = "iOS";
|
platform_ios.name = "iOS";
|
||||||
platform_ios.entries.push_back("armv7");
|
platform_ios.entries.push_back("armv7");
|
||||||
platform_ios.entries.push_back("arm64");
|
platform_ios.entries.push_back("arm64");
|
||||||
platform_ios.library_extension = "*.dylib";
|
// iOS can use both Static and Dynamic libraries.
|
||||||
|
// Frameworks is actually a folder with files.
|
||||||
|
platform_ios.library_extension = "*.framework; Framework, *.xcframework; Binary Framework, *.a; Static Library, *.dylib; Dynamic Library";
|
||||||
platforms["iOS"] = platform_ios;
|
platforms["iOS"] = platform_ios;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -383,6 +396,7 @@ GDNativeLibraryEditor::GDNativeLibraryEditor() {
|
||||||
file_dialog->set_resizable(true);
|
file_dialog->set_resizable(true);
|
||||||
add_child(file_dialog);
|
add_child(file_dialog);
|
||||||
file_dialog->connect("file_selected", this, "_on_library_selected");
|
file_dialog->connect("file_selected", this, "_on_library_selected");
|
||||||
|
file_dialog->connect("dir_selected", this, "_on_library_selected");
|
||||||
file_dialog->connect("files_selected", this, "_on_dependencies_selected");
|
file_dialog->connect("files_selected", this, "_on_dependencies_selected");
|
||||||
|
|
||||||
new_architecture_dialog = memnew(ConfirmationDialog);
|
new_architecture_dialog = memnew(ConfirmationDialog);
|
||||||
|
|
|
@ -144,47 +144,86 @@ void GDNativeExportPlugin::_export_file(const String &p_path, const String &p_ty
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add symbols for staticaly linked libraries on iOS
|
||||||
if (p_features.has("iOS")) {
|
if (p_features.has("iOS")) {
|
||||||
// Register symbols in the "fake" dynamic lookup table, because dlsym does not work well on iOS.
|
|
||||||
LibrarySymbol expected_symbols[] = {
|
|
||||||
{ "gdnative_init", true },
|
|
||||||
{ "gdnative_terminate", false },
|
|
||||||
{ "nativescript_init", false },
|
|
||||||
{ "nativescript_frame", false },
|
|
||||||
{ "nativescript_thread_enter", false },
|
|
||||||
{ "nativescript_thread_exit", false },
|
|
||||||
{ "gdnative_singleton", false }
|
|
||||||
};
|
|
||||||
String declare_pattern = "extern \"C\" void $name(void)$weak;\n";
|
|
||||||
String additional_code = "extern void register_dynamic_symbol(char *name, void *address);\n"
|
|
||||||
"extern void add_ios_init_callback(void (*cb)());\n";
|
|
||||||
String linker_flags = "";
|
|
||||||
for (unsigned long i = 0; i < sizeof(expected_symbols) / sizeof(expected_symbols[0]); ++i) {
|
|
||||||
String full_name = lib->get_symbol_prefix() + expected_symbols[i].name;
|
|
||||||
String code = declare_pattern.replace("$name", full_name);
|
|
||||||
code = code.replace("$weak", expected_symbols[i].is_required ? "" : " __attribute__((weak))");
|
|
||||||
additional_code += code;
|
|
||||||
|
|
||||||
if (!expected_symbols[i].is_required) {
|
bool should_fake_dynamic = false;
|
||||||
if (linker_flags.length() > 0) {
|
|
||||||
linker_flags += " ";
|
List<String> entry_keys;
|
||||||
|
config->get_section_keys("entry", &entry_keys);
|
||||||
|
|
||||||
|
for (List<String>::Element *E = entry_keys.front(); E; E = E->next()) {
|
||||||
|
String key = E->get();
|
||||||
|
|
||||||
|
Vector<String> tags = key.split(".");
|
||||||
|
|
||||||
|
bool skip = false;
|
||||||
|
for (int i = 0; i < tags.size(); i++) {
|
||||||
|
bool has_feature = p_features.has(tags[i]);
|
||||||
|
|
||||||
|
if (!has_feature) {
|
||||||
|
skip = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
linker_flags += "-Wl,-U,_" + full_name;
|
}
|
||||||
|
|
||||||
|
if (skip) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String entry_lib_path = config->get_value("entry", key);
|
||||||
|
if (entry_lib_path.begins_with("res://") && entry_lib_path.ends_with(".a")) {
|
||||||
|
// If we find static library that was used for export
|
||||||
|
// we should add a fake loopup table.
|
||||||
|
// In case of dynamic library being used,
|
||||||
|
// this symbols will not cause any issues with library loading.
|
||||||
|
should_fake_dynamic = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
additional_code += String("void $prefixinit() {\n").replace("$prefix", lib->get_symbol_prefix());
|
if (should_fake_dynamic) {
|
||||||
String register_pattern = " if (&$name) register_dynamic_symbol((char *)\"$name\", (void *)$name);\n";
|
// Register symbols in the "fake" dynamic lookup table, because dlsym does not work well on iOS.
|
||||||
for (unsigned long i = 0; i < sizeof(expected_symbols) / sizeof(expected_symbols[0]); ++i) {
|
LibrarySymbol expected_symbols[] = {
|
||||||
String full_name = lib->get_symbol_prefix() + expected_symbols[i].name;
|
{ "gdnative_init", true },
|
||||||
additional_code += register_pattern.replace("$name", full_name);
|
{ "gdnative_terminate", false },
|
||||||
}
|
{ "nativescript_init", false },
|
||||||
additional_code += "}\n";
|
{ "nativescript_frame", false },
|
||||||
additional_code += String("struct $prefixstruct {$prefixstruct() {add_ios_init_callback($prefixinit);}};\n").replace("$prefix", lib->get_symbol_prefix());
|
{ "nativescript_thread_enter", false },
|
||||||
additional_code += String("$prefixstruct $prefixstruct_instance;\n").replace("$prefix", lib->get_symbol_prefix());
|
{ "nativescript_thread_exit", false },
|
||||||
|
{ "gdnative_singleton", false }
|
||||||
|
};
|
||||||
|
String declare_pattern = "extern \"C\" void $name(void)$weak;\n";
|
||||||
|
String additional_code = "extern void register_dynamic_symbol(char *name, void *address);\n"
|
||||||
|
"extern void add_ios_init_callback(void (*cb)());\n";
|
||||||
|
String linker_flags = "";
|
||||||
|
for (unsigned long i = 0; i < sizeof(expected_symbols) / sizeof(expected_symbols[0]); ++i) {
|
||||||
|
String full_name = lib->get_symbol_prefix() + expected_symbols[i].name;
|
||||||
|
String code = declare_pattern.replace("$name", full_name);
|
||||||
|
code = code.replace("$weak", expected_symbols[i].is_required ? "" : " __attribute__((weak))");
|
||||||
|
additional_code += code;
|
||||||
|
|
||||||
add_ios_cpp_code(additional_code);
|
if (!expected_symbols[i].is_required) {
|
||||||
add_ios_linker_flags(linker_flags);
|
if (linker_flags.length() > 0) {
|
||||||
|
linker_flags += " ";
|
||||||
|
}
|
||||||
|
linker_flags += "-Wl,-U,_" + full_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
additional_code += String("void $prefixinit() {\n").replace("$prefix", lib->get_symbol_prefix());
|
||||||
|
String register_pattern = " if (&$name) register_dynamic_symbol((char *)\"$name\", (void *)$name);\n";
|
||||||
|
for (unsigned long i = 0; i < sizeof(expected_symbols) / sizeof(expected_symbols[0]); ++i) {
|
||||||
|
String full_name = lib->get_symbol_prefix() + expected_symbols[i].name;
|
||||||
|
additional_code += register_pattern.replace("$name", full_name);
|
||||||
|
}
|
||||||
|
additional_code += "}\n";
|
||||||
|
additional_code += String("struct $prefixstruct {$prefixstruct() {add_ios_init_callback($prefixinit);}};\n").replace("$prefix", lib->get_symbol_prefix());
|
||||||
|
additional_code += String("$prefixstruct $prefixstruct_instance;\n").replace("$prefix", lib->get_symbol_prefix());
|
||||||
|
|
||||||
|
add_ios_cpp_code(additional_code);
|
||||||
|
add_ios_linker_flags(linker_flags);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -663,17 +663,33 @@ void EditorExportPlatformIOS::_add_assets_to_project(const Ref<EditorExportPrese
|
||||||
String pbx_frameworks_refs;
|
String pbx_frameworks_refs;
|
||||||
String pbx_resources_build;
|
String pbx_resources_build;
|
||||||
String pbx_resources_refs;
|
String pbx_resources_refs;
|
||||||
|
String pbx_embeded_frameworks;
|
||||||
|
|
||||||
const String file_info_format = String("$build_id = {isa = PBXBuildFile; fileRef = $ref_id; };\n") +
|
const String file_info_format = String("$build_id = {isa = PBXBuildFile; fileRef = $ref_id; };\n") +
|
||||||
"$ref_id = {isa = PBXFileReference; lastKnownFileType = $file_type; name = \"$name\"; path = \"$file_path\"; sourceTree = \"<group>\"; };\n";
|
"$ref_id = {isa = PBXFileReference; lastKnownFileType = $file_type; name = \"$name\"; path = \"$file_path\"; sourceTree = \"<group>\"; };\n";
|
||||||
|
|
||||||
for (int i = 0; i < p_additional_assets.size(); ++i) {
|
for (int i = 0; i < p_additional_assets.size(); ++i) {
|
||||||
|
String additional_asset_info_format = file_info_format;
|
||||||
|
|
||||||
String build_id = (++current_id).str();
|
String build_id = (++current_id).str();
|
||||||
String ref_id = (++current_id).str();
|
String ref_id = (++current_id).str();
|
||||||
|
String framework_id = "";
|
||||||
|
|
||||||
const IOSExportAsset &asset = p_additional_assets[i];
|
const IOSExportAsset &asset = p_additional_assets[i];
|
||||||
|
|
||||||
String type;
|
String type;
|
||||||
if (asset.exported_path.ends_with(".framework")) {
|
if (asset.exported_path.ends_with(".framework")) {
|
||||||
|
additional_asset_info_format += "$framework_id = {isa = PBXBuildFile; fileRef = $ref_id; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };\n";
|
||||||
|
framework_id = (++current_id).str();
|
||||||
|
pbx_embeded_frameworks += framework_id + ",\n";
|
||||||
|
|
||||||
type = "wrapper.framework";
|
type = "wrapper.framework";
|
||||||
|
} else if (asset.exported_path.ends_with(".xcframework")) {
|
||||||
|
additional_asset_info_format += "$framework_id = {isa = PBXBuildFile; fileRef = $ref_id; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };\n";
|
||||||
|
framework_id = (++current_id).str();
|
||||||
|
pbx_embeded_frameworks += framework_id + ",\n";
|
||||||
|
|
||||||
|
type = "wrapper.xcframework";
|
||||||
} else if (asset.exported_path.ends_with(".dylib")) {
|
} else if (asset.exported_path.ends_with(".dylib")) {
|
||||||
type = "compiled.mach-o.dylib";
|
type = "compiled.mach-o.dylib";
|
||||||
} else if (asset.exported_path.ends_with(".a")) {
|
} else if (asset.exported_path.ends_with(".a")) {
|
||||||
|
@ -698,7 +714,10 @@ void EditorExportPlatformIOS::_add_assets_to_project(const Ref<EditorExportPrese
|
||||||
format_dict["name"] = asset.exported_path.get_file();
|
format_dict["name"] = asset.exported_path.get_file();
|
||||||
format_dict["file_path"] = asset.exported_path;
|
format_dict["file_path"] = asset.exported_path;
|
||||||
format_dict["file_type"] = type;
|
format_dict["file_type"] = type;
|
||||||
pbx_files += file_info_format.format(format_dict, "$_");
|
if (framework_id.length() > 0) {
|
||||||
|
format_dict["framework_id"] = framework_id;
|
||||||
|
}
|
||||||
|
pbx_files += additional_asset_info_format.format(format_dict, "$_");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note, frameworks like gamekit are always included in our project.pbxprof file
|
// Note, frameworks like gamekit are always included in our project.pbxprof file
|
||||||
|
@ -732,6 +751,7 @@ void EditorExportPlatformIOS::_add_assets_to_project(const Ref<EditorExportPrese
|
||||||
str = str.replace("$additional_pbx_frameworks_refs", pbx_frameworks_refs);
|
str = str.replace("$additional_pbx_frameworks_refs", pbx_frameworks_refs);
|
||||||
str = str.replace("$additional_pbx_resources_build", pbx_resources_build);
|
str = str.replace("$additional_pbx_resources_build", pbx_resources_build);
|
||||||
str = str.replace("$additional_pbx_resources_refs", pbx_resources_refs);
|
str = str.replace("$additional_pbx_resources_refs", pbx_resources_refs);
|
||||||
|
str = str.replace("$pbx_embeded_frameworks", pbx_embeded_frameworks);
|
||||||
|
|
||||||
CharString cs = str.utf8();
|
CharString cs = str.utf8();
|
||||||
p_project_data.resize(cs.size() - 1);
|
p_project_data.resize(cs.size() - 1);
|
||||||
|
@ -762,8 +782,39 @@ Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir
|
||||||
memdelete(filesystem_da);
|
memdelete(filesystem_da);
|
||||||
return ERR_FILE_NOT_FOUND;
|
return ERR_FILE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
String additional_dir = p_is_framework && asset.ends_with(".dylib") ? "/dylibs/" : "/";
|
|
||||||
String destination_dir = p_out_dir + additional_dir + asset.get_base_dir().replace("res://", "");
|
String base_dir = asset.get_base_dir().replace("res://", "");
|
||||||
|
String destination_dir;
|
||||||
|
String destination;
|
||||||
|
String asset_path;
|
||||||
|
bool create_framework = false;
|
||||||
|
|
||||||
|
if (p_is_framework && asset.ends_with(".dylib")) {
|
||||||
|
// For iOS we need to turn .dylib into .framework
|
||||||
|
// to be able to send application to AppStore
|
||||||
|
destination_dir = p_out_dir.plus_file("dylibs").plus_file(base_dir);
|
||||||
|
|
||||||
|
String file_name = asset.get_basename().get_file();
|
||||||
|
String framework_name = file_name + ".framework";
|
||||||
|
|
||||||
|
destination_dir = destination_dir.plus_file(framework_name);
|
||||||
|
destination = destination_dir.plus_file(file_name);
|
||||||
|
asset_path = destination_dir;
|
||||||
|
create_framework = true;
|
||||||
|
} else if (p_is_framework && (asset.ends_with(".framework") || asset.ends_with(".xcframework"))) {
|
||||||
|
destination_dir = p_out_dir.plus_file("dylibs").plus_file(base_dir);
|
||||||
|
|
||||||
|
String file_name = asset.get_file();
|
||||||
|
destination = destination_dir.plus_file(file_name);
|
||||||
|
asset_path = destination;
|
||||||
|
} else {
|
||||||
|
destination_dir = p_out_dir.plus_file(base_dir);
|
||||||
|
|
||||||
|
String file_name = asset.get_file();
|
||||||
|
destination = destination_dir.plus_file(file_name);
|
||||||
|
asset_path = destination;
|
||||||
|
}
|
||||||
|
|
||||||
if (!filesystem_da->dir_exists(destination_dir)) {
|
if (!filesystem_da->dir_exists(destination_dir)) {
|
||||||
Error make_dir_err = filesystem_da->make_dir_recursive(destination_dir);
|
Error make_dir_err = filesystem_da->make_dir_recursive(destination_dir);
|
||||||
if (make_dir_err) {
|
if (make_dir_err) {
|
||||||
|
@ -773,15 +824,66 @@ Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String destination = destination_dir.plus_file(asset.get_file());
|
|
||||||
Error err = dir_exists ? da->copy_dir(asset, destination) : da->copy(asset, destination);
|
Error err = dir_exists ? da->copy_dir(asset, destination) : da->copy(asset, destination);
|
||||||
memdelete(da);
|
memdelete(da);
|
||||||
if (err) {
|
if (err) {
|
||||||
memdelete(filesystem_da);
|
memdelete(filesystem_da);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
IOSExportAsset exported_asset = { destination, p_is_framework };
|
IOSExportAsset exported_asset = { asset_path, p_is_framework };
|
||||||
r_exported_assets.push_back(exported_asset);
|
r_exported_assets.push_back(exported_asset);
|
||||||
|
|
||||||
|
if (create_framework) {
|
||||||
|
String file_name = asset.get_basename().get_file();
|
||||||
|
String framework_name = file_name + ".framework";
|
||||||
|
|
||||||
|
// Performing `install_name_tool -id @rpath/{name}.framework/{name} ./{name}` on dylib
|
||||||
|
{
|
||||||
|
List<String> install_name_args;
|
||||||
|
install_name_args.push_back("-id");
|
||||||
|
install_name_args.push_back(String("@rpath").plus_file(framework_name).plus_file(file_name));
|
||||||
|
install_name_args.push_back(destination);
|
||||||
|
|
||||||
|
OS::get_singleton()->execute("install_name_tool", install_name_args, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creating Info.plist
|
||||||
|
{
|
||||||
|
String info_plist_format = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||||
|
"<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
|
||||||
|
"<plist version=\"1.0\">\n"
|
||||||
|
"<dict>\n"
|
||||||
|
"<key>CFBundleShortVersionString</key>\n"
|
||||||
|
"<string>1.0</string>\n"
|
||||||
|
"<key>CFBundleIdentifier</key>\n"
|
||||||
|
"<string>com.gdnative.framework.$name</string>\n"
|
||||||
|
"<key>CFBundleName</key>\n"
|
||||||
|
"<string>$name</string>\n"
|
||||||
|
"<key>CFBundleExecutable</key>\n"
|
||||||
|
"<string>$name</string>\n"
|
||||||
|
"<key>DTPlatformName</key>\n"
|
||||||
|
"<string>iphoneos</string>\n"
|
||||||
|
"<key>CFBundleInfoDictionaryVersion</key>\n"
|
||||||
|
"<string>6.0</string>\n"
|
||||||
|
"<key>CFBundleVersion</key>\n"
|
||||||
|
"<string>1</string>\n"
|
||||||
|
"<key>CFBundlePackageType</key>\n"
|
||||||
|
"<string>FMWK</string>\n"
|
||||||
|
"<key>MinimumOSVersion</key>\n"
|
||||||
|
"<string>10.0</string>\n"
|
||||||
|
"</dict>\n"
|
||||||
|
"</plist>";
|
||||||
|
|
||||||
|
String info_plist = info_plist_format.replace("$name", file_name);
|
||||||
|
|
||||||
|
FileAccess *f = FileAccess::open(asset_path.plus_file("Info.plist"), FileAccess::WRITE);
|
||||||
|
if (f) {
|
||||||
|
f->store_string(info_plist);
|
||||||
|
f->close();
|
||||||
|
memdelete(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
memdelete(filesystem_da);
|
memdelete(filesystem_da);
|
||||||
|
|
Loading…
Reference in New Issue