ld: duplicate symbols when swift_library depend on apple_framework
i-pavlov opened this issue · 4 comments
Hi, I was trying to use static apple_framework
to compile a mixed ObjC+swift module.
The apple_framework
is not a leaf node of my dependency graph, so it has some swift_library
dependencies that are also used by other pure-swift modules in my app.
As a result, symbols of these dependencies are duplicated in top-level binary, so I'm getting a linker issue. It looks ~ similar to problem discussed in #430. But I still able to reproduce in the latest commit from master branch.
Do you have any suggestions about this scenario? Is it supported by design?
I guess I can update all modules in the app to be dynamic frameworks, but it looks like the last possible option :D
Sample repo
I created a repo with the smallest possible way to reproduce: https://github.com/i-pavlov/reproduce-rules-ios-duplicate-symbols
The dependency graph is pretty simple. It has three modules:
Data
(swift_library)Utils
(apple_framework, static)Module
(swift_library)ModuleTests
(unit-test bundle)
1. `Data` has no dependencies
2. `Utils` depends on `Data`
3. `Module` depends on `Data` and `Utils`
4. `ModuleTests` depends on `Module`
If I remove the dependency between Module
and Data
the issue will disappear.
Steps to reproduce
Need to build unit test bundle
bazel build //App/Module:ModuleTests
Linker error
When I compile unit-tests, I'm getting this error.
Looks like two versions of libData
were created. When we try to link them - getting an error.
/Users/ipavlov/Developer/bazel_platforms_test/App/Module/BUILD:24:14: Linking App/Module/ModuleTests.__internal__.__test_bundle_bin failed: (Aborted): wrapped_clang failed: error executing command
(cd /private/var/tmp/_bazel_ipavlov/23ebc518c1b7878a1b2c6f2ef4486ae1/sandbox/darwin-sandbox/332/execroot/__main__ && \
exec env - \
APPLE_SDK_PLATFORM=iPhoneSimulator \
APPLE_SDK_VERSION_OVERRIDE=15.2 \
PATH=/bin:/usr/bin:/usr/local/bin \
XCODE_VERSION_OVERRIDE=13.2.1.13C100 \
ZERO_AR_DATE=1 \
external/local_config_cc/wrapped_clang @bazel-out/ios-sim_arm64-min14.2-applebin_ios-ios_sim_arm64-dbg-ST-19517cdb79de/bin/App/Module/ModuleTests.__internal__.__test_bundle_bin-2.params)
# Configuration: 59b07bb4057e96974d443e7f597806a5e3cd105462e50da71b86a983ab7c4496
# Execution platform: @local_config_platform//:host
Use --sandbox_debug to see verbose messages from the sandbox and retain the sandbox build root for debugging
duplicate symbol 'nominal type descriptor for Data.Item' in:
bazel-out/ios-sim_arm64-min14.2-applebin_ios-ios_sim_arm64-dbg-ST-19517cdb79de/bin/App/Data/libData.a(Contract.swift.o)
bazel-out/ios-sim_arm64-min14.2-applebin_ios-ios_sim_arm64-dbg-ST-37412340fa95/bin/App/Data/libData.a(Contract.swift.o)
Subcommands
It's clear that libData
compiled twice if print subcommands:
The first one:
SUBCOMMAND: # //App/Data:Data [action 'Compiling Swift module //App/Data:Data', configuration: 92d4594cb8fd2799aa91d544c582450cb49f7bc02075d927c8db7c90cf3652a7, execution platform: @local_config_platform//:host]
(cd /private/var/tmp/_bazel_ipavlov/23ebc518c1b7878a1b2c6f2ef4486ae1/execroot/__main__ && \
exec env - \
APPLE_SDK_PLATFORM=iPhoneSimulator \
APPLE_SDK_VERSION_OVERRIDE=15.2 \
SWIFT_AVOID_WARNING_USING_OLD_DRIVER=1 \
XCODE_VERSION_OVERRIDE=13.2.1.13C100 \
bazel-out/darwin_arm64-opt-exec-2B5CBBC6-ST-f0056b8e5833/bin/external/build_bazel_rules_swift/tools/worker/worker swiftc @bazel-out/ios-sim_arm64-min14.2-applebin_ios-ios_sim_arm64-dbg-ST-37412340fa95/bin/App/Data/Data.swiftmodule-0.params)
# Configuration: 92d4594cb8fd2799aa91d544c582450cb49f7bc02075d927c8db7c90cf3652a7
# Execution platform: @local_config_platform//:host
The second one:
SUBCOMMAND: # //App/Data:Data [action 'Compiling Swift module //App/Data:Data', configuration: 03f1ac5615d5fcff438b70835b28294822a3e2d8e6fd637bb3830da04dd4addb, execution platform: @local_config_platform//:host]
(cd /private/var/tmp/_bazel_ipavlov/23ebc518c1b7878a1b2c6f2ef4486ae1/execroot/__main__ && \
exec env - \
APPLE_SDK_PLATFORM=iPhoneSimulator \
APPLE_SDK_VERSION_OVERRIDE=15.2 \
SWIFT_AVOID_WARNING_USING_OLD_DRIVER=1 \
XCODE_VERSION_OVERRIDE=13.2.1.13C100 \
bazel-out/darwin_arm64-opt-exec-2B5CBBC6-ST-dedf359489b7/bin/external/build_bazel_rules_swift/tools/worker/worker swiftc @bazel-out/ios-sim_arm64-min14.2-applebin_ios-ios_sim_arm64-dbg-ST-19517cdb79de/bin/App/Data/Data.swiftmodule-0.params)
# Configuration: 03f1ac5615d5fcff438b70835b28294822a3e2d8e6fd637bb3830da04dd4addb
# Execution platform: @local_config_platform//:host
This is expected when linking static frameworks. Since Module
depends on Data
and Util
does as well, Data needs to be a dynamic framework or you'll get duplicate symbols.
Thanks for the explanation!
Btw, looks like I found ~ a workaround for my case.
If I convert Data
to a static framework too, the issue will not happen.
Looks like the linking strategy for swift_library
and static apple_framework
are slightly different.
This is expected when linking static frameworks. Since Module depends on Data and Util does as well, Data needs to be a dynamic framework or you'll get duplicate symbols.
I think there's a few wires crossed in the build file - you should be able to have many apps, tests, and apple_framework
s depending on one another - and not have a duplicate symbol:
- adding
Module
throughswift_library
might cause an issue - compiling the file
Test.swift
into 2 times
Looks like the linking strategy for swift_library and static apple_framework are slightly different.
I think the issue might be in the way the build graph is setup: running these deps through swift_library
here might not be accounted for
After some time debugging and diving into bazel I found the root cause of my problem.
The default value of --ios_multi_cpus
is x86_64
, but I'm compiling it on an arm64
laptop.
So setting --ios_multi_cpus=sim_arm64
made my tests compilable.
Still not sure how ios_multi_cpus
can cause the Data
module to be compiled twice by using different configurations. I think it might be related to the 1:K transition for framework packaging.
But if initially it is caused by incorrect build parameters, I don't think someone else can get the same problem in real-life scenarios.