Does ld64 warn or fail when an upgraded Xcode links mixed-ABI Objective-C objects?
0 reputation · 15 Oct 2020, 15:15 UTC
0 reputation · 15 Oct 2020, 15:15 UTC
An Objective-C project that breaks right after an Xcode upgrade is often recovered by clearing DerivedData and rebuilding. The open question is what happens when that rebuild links object files from two toolchains — stale objects from the old configuration, or a prebuilt static library compiled against an earlier SDK.
The Objective-C non-fragile ABI and the linker's handling of duplicate class symbols are documented, but the mixed-ABI case is not clearly specified. Depending on the ld64 version, a collision in _OBJC_CLASS_$_ symbols may surface as a hard error, a warning, or apparently clean output — and a binary that links could still misbehave at runtime during class or method lookup.
Assume recent Xcode 15/16 toolchains with default ABI settings; a minimal check would link a small app against a library built with an older toolchain and watch the link log plus runtime behavior.
In recent Xcode toolchains (Xcode 15/16), ld64 treats duplicate _OBJC_CLASS_$_ symbols resulting from mixed-ABI object files as a hard link-time error. It does not typically emit a warning or silently merge them; instead, it triggers a "duplicate symbol" error that halts the build process.
This occurs because the Objective-C runtime relies on specific metadata structures. When the linker encounters two definitions of the same class symbol—one from a stale object file and one from a newly compiled one—it cannot safely determine which metadata layout to prioritize, resulting in a collision.
While the default behavior is to fail, certain configurations can alter this outcome:
-allow-duplicate-symbols (or LD_ALLOW_DUPLICATE_SYMBOLS=YES) is enabled, the linker will suppress the error and silently pick the first definition it encounters. This is dangerous, as it may produce a binary that links successfully but crashes at runtime during class or method lookup.Objective-C Runtime ABI Version (CLANG_ENABLE_OBJC_ABI_VERSION) forces newly compiled source files to adhere to a specific ABI. However, this only affects current compilation; it does not retroactively change the ABI of prebuilt objects.A DerivedData wipe is sufficient to resolve issues caused by stale intermediate .o files generated by a previous Xcode version. However, it cannot fix mismatches introduced by prebuilt static libraries (.a) or framework slices.
Because static libraries carry their own ABI metadata, a library built with an older toolchain will still present the old ABI to the linker, even after a full clean of the main project. To resolve this, the static library itself must be recompiled using the current toolchain.
To verify if a binary is suffering from an ABI mismatch, you can use the following scoped approach:
duplicate symbol _OBJC_CLASS_$_. If this appears, you have a mixed-ABI conflict.NSClassFromString("YourClassName") in a debug session. If it returns nil or crashes during initialization, an ABI mismatch is likely.Note: Older ld64 versions (pre-Xcode 9) may have permitted duplicate symbols with only a warning, so behavior is version-dependent. Verify against your specific toolchain before relying on this guidance.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.