mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-05-30 02:28:26 +01:00
Build #8 confirmed BOTH iOS jobs (signed + unsigned) fail at the same step: the Streamyfin app-target link (`Ld ... Streamyfin`), not any pod framework. Under use_frameworks static + Xcode 26 the SwiftUI pods' object files carry a `-framework SwiftUICore` autolink directive that flows into the app link; ld rejects it with "cannot link directly with 'SwiftUICore' because product being built is not an allowed client of it". forceStaticLinking the SwiftUI pods was treating a symptom. The real fix is to weakly link SwiftUICore on the app target so the allowed-client check is bypassed and the symbols resolve via SwiftUI's re-export at runtime. New plugin withSwiftUICoreWeakLink scopes the flag to product-type application only, leaving the tvOS TopShelf app-extension untouched (a broad weak-link previously broke that target).
61 lines
2.6 KiB
JavaScript
61 lines
2.6 KiB
JavaScript
const { withXcodeProject } = require("@expo/config-plugins");
|
|
|
|
// Tokens written verbatim as OTHER_LDFLAGS array entries.
|
|
const LDFLAG_TOKENS = ['"-weak_framework"', '"SwiftUICore"'];
|
|
|
|
/**
|
|
* Xcode 26 + `use_frameworks! :linkage => :static` makes the main app target
|
|
* auto-link SwiftUICore directly (SwiftUI was split into SwiftUI + SwiftUICore on
|
|
* recent SDKs, and the SwiftUI pods' object files carry a `-framework SwiftUICore`
|
|
* autolink directive that flows into the app link). The linker then rejects it:
|
|
* ld: cannot link directly with 'SwiftUICore' because product being built is
|
|
* not an allowed client of it
|
|
* Weakly linking SwiftUICore on the app target bypasses the allowed-client check;
|
|
* the symbols still resolve at runtime via SwiftUI's re-export.
|
|
*
|
|
* Scoped to `com.apple.product-type.application` ONLY — it must not touch the
|
|
* tvOS TopShelf app-extension (which legitimately links SwiftUI); applying the
|
|
* flag there breaks that target.
|
|
*/
|
|
const withSwiftUICoreWeakLink = (config) =>
|
|
withXcodeProject(config, (config) => {
|
|
const project = config.modResults;
|
|
const nativeTargets = project.pbxNativeTargetSection();
|
|
const configLists = project.pbxXCConfigurationList();
|
|
const buildConfigs = project.pbxXCBuildConfigurationSection();
|
|
|
|
// Collect build-configuration UUIDs that belong to application targets only.
|
|
const appConfigIds = new Set();
|
|
for (const key of Object.keys(nativeTargets)) {
|
|
const target = nativeTargets[key];
|
|
if (!target || typeof target !== "object" || !target.productType)
|
|
continue;
|
|
const productType = String(target.productType).replace(/"/g, "");
|
|
if (productType !== "com.apple.product-type.application") continue;
|
|
const list = configLists[target.buildConfigurationList];
|
|
if (!list || !list.buildConfigurations) continue;
|
|
for (const bc of list.buildConfigurations) appConfigIds.add(bc.value);
|
|
}
|
|
|
|
for (const id of appConfigIds) {
|
|
const entry = buildConfigs[id];
|
|
if (!entry || typeof entry !== "object" || !entry.buildSettings) continue;
|
|
const settings = entry.buildSettings;
|
|
let flags = settings.OTHER_LDFLAGS;
|
|
if (flags == null || flags === '""' || flags === "") {
|
|
flags = ['"$(inherited)"'];
|
|
} else if (typeof flags === "string") {
|
|
flags = [flags];
|
|
}
|
|
const already = flags.some((f) => String(f).includes("SwiftUICore"));
|
|
if (!already) {
|
|
flags.push(...LDFLAG_TOKENS);
|
|
settings.OTHER_LDFLAGS = flags;
|
|
}
|
|
}
|
|
|
|
return config;
|
|
});
|
|
|
|
module.exports = withSwiftUICoreWeakLink;
|