Add support for Swift Package Manager dependencies in Apple export plugins

This commit is contained in:
Gustavo Maciel
2026-04-26 21:43:31 -03:00
parent 6d6e822c68
commit f877b970a5
5 changed files with 109 additions and 5 deletions
@@ -416,6 +416,12 @@ String EditorExportPlatformAppleEmbedded::_process_config_file_line(const Ref<Ed
strnew += p_line.replace("$modules_buildphase", p_config.modules_buildphase) + "\n";
} else if (p_line.contains("$modules_buildgrp")) {
strnew += p_line.replace("$modules_buildgrp", p_config.modules_buildgrp) + "\n";
} else if (p_line.contains("$spm_packages")) {
strnew += p_line.replace("$spm_packages", p_config.spm_packages) + "\n";
} else if (p_line.contains("$spm_package_refs")) {
strnew += p_line.replace("$spm_package_refs", p_config.spm_package_refs) + "\n";
} else if (p_line.contains("$spm_package_products")) {
strnew += p_line.replace("$spm_package_products", p_config.spm_package_products) + "\n";
} else if (p_line.contains("$name")) {
strnew += p_line.replace("$name", p_config.pkg_name) + "\n";
} else if (p_line.contains("$bundle_identifier")) {
@@ -1645,6 +1651,67 @@ Error EditorExportPlatformAppleEmbedded::_export_apple_embedded_plugins(const Re
p_config_data.linker_flags += result_linker_flags;
}
// SPM Packages
{
PbxId pbx_id;
pbx_id.high_bits = 0xDEB00000;
pbx_id.mid_bits = 0;
pbx_id.low_bits = 0;
HashMap<String, PluginConfigAppleEmbedded::SPMPackage> unique_packages;
for (int i = 0; i < enabled_plugins.size(); i++) {
for (const PluginConfigAppleEmbedded::SPMPackage &package : enabled_plugins[i].spm_packages) {
if (!unique_packages.has(package.url)) {
unique_packages[package.url] = package;
} else {
for (const String &product : package.products) {
if (unique_packages[package.url].products.find(product) == -1) {
unique_packages[package.url].products.push_back(product);
}
}
}
}
}
Vector<String> sorted_package_urls;
for (const KeyValue<String, PluginConfigAppleEmbedded::SPMPackage> &E : unique_packages) {
sorted_package_urls.push_back(E.key);
}
sorted_package_urls.sort();
for (const String &url : sorted_package_urls) {
const PluginConfigAppleEmbedded::SPMPackage &package = unique_packages[url];
String package_id = (++pbx_id).str();
String package_name = package.url.get_file().get_basename();
p_config_data.spm_packages += vformat("\t\t\t\t%s /* %s */,\n", package_id, package_name);
p_config_data.spm_package_refs += vformat("\t\t%s /* %s */ = {\n", package_id, package_name);
p_config_data.spm_package_refs += "\t\t\tisa = XCRemoteSwiftPackageReference;\n";
p_config_data.spm_package_refs += vformat("\t\t\trepositoryURL = \"%s\";\n", package.url);
p_config_data.spm_package_refs += "\t\t\trequirement = {\n";
p_config_data.spm_package_refs += "\t\t\t\tkind = exactVersion;\n";
p_config_data.spm_package_refs += vformat("\t\t\t\tversion = %s;\n", package.version);
p_config_data.spm_package_refs += "\t\t\t};\n";
p_config_data.spm_package_refs += "\t\t};\n";
for (const String &product : package.products) {
String product_id = (++pbx_id).str();
String build_file_id = (++pbx_id).str();
p_config_data.spm_package_products += vformat("\t\t%s /* %s */ = {\n", product_id, product);
p_config_data.spm_package_products += "\t\t\tisa = XCSwiftPackageProductDependency;\n";
p_config_data.spm_package_products += vformat("\t\t\tpackage = %s /* %s */;\n", package_id, package_name);
p_config_data.spm_package_products += vformat("\t\t\tproductName = \"%s\";\n", product);
p_config_data.spm_package_products += "\t\t};\n";
p_config_data.modules_buildfile += vformat("\t\t%s /* %s in Frameworks */ = {isa = PBXBuildFile; productRef = %s /* %s */; };\n", build_file_id, product, product_id, product);
p_config_data.modules_buildphase += vformat("\t\t\t\t%s /* %s in Frameworks */,\n", build_file_id, product);
}
}
}
return OK;
}
@@ -1819,11 +1886,14 @@ Error EditorExportPlatformAppleEmbedded::_export_project_helper(const Ref<Editor
String(" ").join(_get_preset_architectures(p_preset)),
_get_linker_flags(),
_get_cpp_code(),
"",
"",
"",
"",
Vector<String>(),
"", // modules_buildfile
"", // modules_fileref
"", // modules_buildphase
"", // modules_buildgrp
"", // spm_packages
"", // spm_package_refs
"", // spm_package_products
Vector<String>(), // capabilities
};
config_data.plist_content += p_preset->get("application/additional_plist_content").operator String() + "\n";
@@ -143,6 +143,9 @@ protected:
String modules_fileref;
String modules_buildphase;
String modules_buildgrp;
String spm_packages;
String spm_package_refs;
String spm_package_products;
Vector<String> capabilities;
};
@@ -205,6 +205,20 @@ PluginConfigAppleEmbedded PluginConfigAppleEmbedded::load_plugin_config(Ref<Conf
plugin_config.capabilities = config_file->get_value(PluginConfigAppleEmbedded::DEPENDENCIES_SECTION, PluginConfigAppleEmbedded::DEPENDENCIES_CAPABILITIES_KEY, Vector<String>());
plugin_config.linker_flags = config_file->get_value(PluginConfigAppleEmbedded::DEPENDENCIES_SECTION, PluginConfigAppleEmbedded::DEPENDENCIES_LINKER_FLAGS, Vector<String>());
Array spm_packages = config_file->get_value(PluginConfigAppleEmbedded::DEPENDENCIES_SECTION, PluginConfigAppleEmbedded::DEPENDENCIES_SPM_PACKAGES_KEY, Array());
for (int i = 0; i < spm_packages.size(); i++) {
Dictionary package_config = spm_packages[i];
PluginConfigAppleEmbedded::SPMPackage package;
package.url = package_config.get("url", String());
package.version = package_config.get("version", String());
Array products = package_config.get("products", Array());
for (int j = 0; j < products.size(); j++) {
package.products.push_back(products[j]);
}
plugin_config.spm_packages.push_back(package);
}
}
if (config_file->has_section(PluginConfigAppleEmbedded::PLIST_SECTION)) {
@@ -44,6 +44,7 @@ The `dependencies` and fields are optional.
- **system**: system dependencies that should be linked.
- **capabilities**: capabilities that would be used for `UIRequiredDeviceCapabilities` options in Info.plist file.
- **files**: files that would be copied into application
- **spm_packages**: array of Swift Package Manager dependencies (url, version, products).
The `plist` section are optional.
- **key**: key and value that would be added in Info.plist file.
@@ -65,6 +66,7 @@ struct PluginConfigAppleEmbedded {
inline static const char *DEPENDENCIES_CAPABILITIES_KEY = "capabilities";
inline static const char *DEPENDENCIES_FILES_KEY = "files";
inline static const char *DEPENDENCIES_LINKER_FLAGS = "linker_flags";
inline static const char *DEPENDENCIES_SPM_PACKAGES_KEY = "spm_packages";
inline static const char *PLIST_SECTION = "plist";
@@ -82,6 +84,12 @@ struct PluginConfigAppleEmbedded {
String value;
};
struct SPMPackage {
String url;
String version;
Vector<String> products;
};
// Set to true when the config file is properly loaded.
bool valid_config = false;
bool supports_targets = false;
@@ -104,6 +112,9 @@ struct PluginConfigAppleEmbedded {
Vector<String> linker_flags;
// Optional spm_dependencies section.
Vector<SPMPackage> spm_packages;
// Optional plist section
// String value is default value.
// Currently supports `string`, `boolean`, `integer`, `raw`, `string_input` types
@@ -176,6 +176,9 @@
productRefGroup = D0BCFE3518AEBDA2004A7AAE /* Products */;
projectDirPath = "";
projectRoot = "";
packageReferences = (
$spm_packages
);
targets = (
D0BCFE3318AEBDA2004A7AAE /* $binary */,
);
@@ -407,6 +410,9 @@
defaultConfigurationName = Debug;
};
/* End XCConfigurationList section */
$spm_package_refs
$spm_package_products
};
rootObject = D0BCFE2C18AEBDA2004A7AAE /* Project object */;
}