Linker flag -ObjC force loads Swift libraries

My apology if here is not the right place to ask a linker question.

I noticed that adding -ObjC linker flag will always force to load Swift libraries, even though no symbol is referenced. After digging into the source code of ld64, I found this was actually intentional. I understand that -ObjC is need to load Objective-C categories, but the behavior of loading Swift libraries isn't documented anywhere and surprised me. Along with Swift non-strippable public symbols, -ObjC could make binary size bigger than expected.

I'm curious to learn why Swift libraries are force loaded by -ObjC and if there is a way to disable it.


The sample code to verify this behavior:

echo "public struct Foo{}" > lib.swift
swiftc -c -o lib.o lib.swift
libtool -static lib.o -o lib.a

Link it with -ObjC and -why_load. We can see below message.

-ObjC forced load of lib.a(lib.o)

There's some context around this on [SR-6004] Static libraries don't automatically load extensions · Issue #48561 · apple/swift · GitHub

It was a short-term modification to keep ld64 from dropping dynamically-referenced Swift metadata from getting stripped. As Swift's own dead stripping gets better it should become unnecessary. In the meantime, I don't think there is a way to disable the behavior; you could leave out -ObjC and manually mark ObjC categories and Swift metadata symbols you need with -u instead, perhaps.

1 Like

Thank you for the link! I remember that problem but didn't realize the fix was in -ObjC.

From the ld64 source code, -ObjC just loads all Swift object files. It doesn't seem to be better than -all_load for Swift-dominant codebase :worried:

This will likely need to be tied to the "limit reflection" work, since a library might contain nothing but protocol conformances intended to be referenced dynamically (i.e. through as?).

1 Like

Definitely. We'd need to address that issue before returning the flag to its original behavior.

1 Like

Is there different behavior for this when using Swift Package Manager for integration? We're noticing that when linking various things via an xcodeproj integration itself the -ObjC flag is required to force load libraries, but the flag is not required if we link the package via SPM.

1 Like