I'm trying to build a static library in Swift, which is later linked with a C++ executable.
The swift library is built by declaring a product in the Package.swift:
swift build --product MyLibrary. The final executable is created via makefile and roughly speaking complies some
.o files and then calls the linker with
-L <path-to-directory-containing-libMyLibrary.a> -lMyLibrary -L/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/lib/swift.
This works fine as long as
MyLibrary is trivial (for instance, just calling
print). However, when I add more complicated logic into
MyLibrary (for my specific use case, this is
swift-argument-parser), the linking into a C++ executable fails with the following warnings:
ld: warning: Could not find or use auto-linked library 'swiftCompatibility50'
ld: warning: Could not find or use auto-linked library 'swiftCompatibilityDynamicReplacements'
ld: warning: Could not find or use auto-linked library 'swiftCompatibility51'
ld: warning: Could not find or use auto-linked library 'swiftCompatibilityConcurrency'
As well as a bunch of undefined symbol errors:
Undefined symbols for architecture x86_64:
"__swift_FORCE_LOAD_$_swiftCompatibility50", referenced from:
__swift_FORCE_LOAD_$_swiftCompatibility50_$_ArgumentParser in libMyLibrary.a(ExpressibleByArgument.swift.o)
__swift_FORCE_LOAD_$_swiftCompatibility50_$_ArgumentParser in libMyLibrary.a(ParsableCommand.swift.o)
...and so on
I couldn't find much information about the
swiftCompatibility... libraries, but I'm curious as to why it thinks I need compatibility at all. I'm both compiling the static library and linking it into an executable on the same system.
Any clues on how to fix this issue?
I've seen something like this in the past as well, and I'm not sure how I worked my way out of it. But the libraries it mentions that are missing here are contained in
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx/, so you can try either passing a
-L to this path, or explicitly passing the libraries on the command line so that the linker will forcibly include them (the former is preferred if possible so it could stop loading them in the future if they were no longer needed).
compatibility part of these they might also not be required if you bump your minimum deployment target in your Package.swift file.
Thanks, I'll give this a try!
Yup this did work, thanks again!
It seems that path is not available dynamically (like
xcrun --show-sdk-path), so I needed to hard-code it. This is unfortunate but can be worked around.
In normal circumstances, you are not normally supposed to need to explicitly pass that path, since the compiler and build system should know where the compatibility libraries are if they are needed for your deployment target. Would you be able to file a bug with your project?
The issue for me is that the product of the Swift build process is a static library. That static library is then passed to a separate non-Swift build process which links that static library with some other code (in this case some C++ code). Essentially, I needed to find the magic incantation to get the second build system to call
ld with the correct arguments to end up with a usable executable. For the record, I think this is highly specific to my one use-case which happens to be pathological for historical reasons.
Overall, I'm pretty sure this isn't a bug, though perhaps having some sort of better API for "give me the linker command I should use to link this SwiftPM built static library into a final executable later" might be useful.
I'm not sure if I'm having exactly the same problem, but this thread is the only Google hit for 'Undefined symbol: _swift_FORCE_LOAD$_swiftCompatibilityConcurrency' so I'll try here.
My situation is that I've built an XCFramework in XCode 13.2, distributed it via Swift PM and then a colleague in QA is testing it against a project in XCode 13.0 and gets this error message when building.
If I rebuild the Package in XCode 13.0 it builds fine and will then projects in 13.0 build OK too.
So the question is 'Is there something innate in a package built in XCode 13.2 that triggers the inclusion of the concurrency compatibility library, even when none of the code in the package uses any concurrency code?' Is there a system framework in 13.2 that is triggering the concurrency inclusion?
I had this issue on Bitrise and solved it just by updating Xcode to 13.2.x. The issue occurred for me with Xcode 13.0.x and 13.1.x.
I was also struggling with this issue but with another sdk, and solved it that way (updating Xcode from 13.0 to 13.3). Thanks @dylanmaryk
Just to clarify for everyone (especially @richardgroves, @dylanmaryk, and @jguillen), Swift xcframeworks, even those built with library evolution enabled, are not backward compatible. That is, libraries built using newer versions of the compiler are not guaranteed to work with older compilers. This is especially true for things like the concurrency back deployment features introduced in Xcode 13.2 (the
swiftCompatibilityConcurrency library linked above) as it may not exist at all in older versions. You should always use the same version of Xcode for all build products and keep those versions in sync as projects update Xcode versions over time.
Thanks for the clarification @Jon_Shier
Can we assume that XCFrameworks built in a given XCode version will always be usable in future versions of XCode? We distribute a binary framework and are OK with setting a minimum version, but making a specific build for each new XCode would be a pain (if possible at all).
As long as you build with library evolution enabled that should work. However, many, if not most, source frameworks are not designed to be built like that and may not themselves maintain binary compatibility going forward. So if it's really necessary for you to distribute binary products internally, rebuilding for each new Xcode and dependency version should keep things stable going forward. Most important is probably keeping everyone on the same version of Xcode though.
This worked for me:
Create an Empty Swift file using Xcode, such as named Void.swift, and every issue will be solved by Xcode automatically.
If you want to know what Xcode has done, submit the code before creating the file, and check the changes after creating the file.
Don't forget to check the correct Target subproject (if any) in the creation window and select "Create bridging header" if Xcode ask you about it.
The problem was probably a missing setting in the build settings of the project or missing/wrong bridging/swift header file (<project>-Swift.h and <project>-Bridging-Header.h)