Can the Xcode linker deduplicate symbols in a merged binary?

Intro

I'm trying to determine whether Xcode's new Mergeable Libraries feature can remove duplicated symbols in a scenario where an app links to two dynamic frameworks which both link to the same static library, as follows:

|--App
  |--DynamicFramework1      
    |--StaticLibrary   
  |--DynamicFramework2      
    |--StaticLibrary <- the same library that DynamicFramework1 links to

Project setup

Here are some details about the app's structure:

  1. The static library is named StaticLibrary. It:
  • Contains a single Objective-C class named SLClass1
  1. The first dynamic framework target is named DynamicFramework1. It:
  • Contains a single Objective-C class named DF1Class1 that calls into SLClass1; and
  • Has a MERGEABLE_LIBRARY build setting value of YES.
  1. The second dynamic framework target is named DynamicFramework2. It:
  • Contains a single Objective-C class named DF2Class1 that calls into SLClass1; and
  • Has a MERGEABLE_LIBRARY build setting value of YES.
  1. The app target is named App. It:
  • Contains a single Swift class named ViewController that calls into the DF1Class1 and DF2Class1 classes; and
  • Has a MERGED_BINARY_TYPE build setting value of Automatic. (1)

I've created a minimal Xcode project here that has the above structure.

Expected result

The merged app binary, when built it in Release mode, contains the symbols for DF1Class1, DF2Class1 and SLClass1 directly within it and it contains only one instance of each of these symbols (i.e. no duplicates).

I am basing this expectation on the Benefits of mergeable libraries section of the Meet mergeable libraries talk from WWDC 2023 where the speaker said:

When merging, the linker can de-duplicate content, such as strings, across all libraries. For instance, it removes redundant symbol references, Objective-C selectors, and objc_msgsend stubs.

Actual result

The merged app binary, when built it in Release mode, contains the symbols for DF1Class1, DF2Class1 and SLClass1 directly within it but it contains two instances of SLClass1's symbols (i.e. it contains duplicates). (2)

My Question

Have I missed something in the app's build settings or have I misunderstood the capability of Mergeable Libraries? Can I get the Xcode linker to deduplicate symbols in the app's merged binary?

Footnotes

  1. I have tried with a MERGED_BINARY_TYPE build setting value of Manual also but the result is the same.
  2. I have validated this by running the nm command on the app's executable file and inspecting the output.

Replies

I'm trying to determine whether Xcode's new Mergeable Libraries feature can remove duplicated symbols in a scenario where an app links to two dynamic frameworks which both link to the same static library,

I would’t expect this to work. Ignore dynamic libraries for the moment and imagine that everything here was a static library. You’d see one of two behaviours:

  • If the common code is invisible to the linker, you’d get no merging.

  • If the common code is visible to the linker, you’d get a duplicate symbol error.

Neither does what you want.

The mergeable libraries feature is effectively behaving like the static linker, and so it also won’t yield a useful result. As to which result you’ll actually get, your tests show that you always get the first result, which makes sense because dynamic libraries support a two-level namespace.

Note Whenever I talk about the linker I assume the terminology from An Apple Library Primer.

I am basing this expectation on the … talk from WWDC 2023 where the speaker said:

The things mentioned there are all visible to the linker and have established semantics such that the linker is free to merge them. That’s not true for code in general.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"