Android link failures with --static-swift-stdlib

Hi everyone :slight_smile:

I'm attempting to build our Android shared library (using @Finagolfin's fantastic SDK builds) with a static stdlib and some weird things are happening:

Firstly, the final .so file (products: [.library(name: "...", type: .dynamic, ...)]) as built by swift build --static-swift-stdlib still links to libswiftCore.so and so on dynamically. I tried to work around this manually by running SwiftPM with -v, copying the final linker invocation, and changing the search path from -L/path/to/usr/lib/swift to -L/path/to/usr/lib/swift_static.

That almost works, but leads to the second issue: there are duplicate symbols in libswift_StringProcessing.a that are also present in libswiftCore.a: _swift_stdlib_getScriptExtensions and _swift_stdlib_getScript. I worked around this by running /usr/local/ndk/25.1.8937393//toolchains/llvm/prebuilt/darwin-x86_64/bin/llvm-objcopy -L _swift_stdlib_getScript and -L _swift_stdlib_getScriptExtensions, as described here. edit: just found this issue which is relevant here.

The final hurdle, and where I'm stuck, is: the final .so file seems to want to link the objc runtime. I get a dlopen failed: cannot locate symbol "objc_retainAutoreleasedReturnValue" referenced by [my .so file] when trying to load it. So I feel like something in the build setup of the Android static SDK is probably not correct. The objc runtime should not be referenced at all for Android builds.


I'm mostly posting this to make the issue known, and to gather some thoughts about how this might be improved in the SDK builds. Maybe someone has run into similar issues for Android or another Linux platform and has some ideas?

A working static build for Android would be a pretty amazing improvement. The (not quite working) stripped, statically linked binary is 75% smaller than the dynamically linked equivalent for us. And that is on top of the 50% reduction we already gained by removing Foundation recently.

Getting this working would make a lot of users (and me!) very happy :slight_smile:


FYI @Finagolfin's builds appear to use build_script (see here for more details):

./swift/utils/build-script -RA --skip-build-cmark --build-llvm=0 --android
--android-ndk /home/butta/android-ndk-r25b/ --android-arch aarch64 --android-api-level 24
--build-swift-tools=0 --native-swift-tools-path=/home/butta/swift-5.7-RELEASE-ubuntu20.04/usr/bin/
--native-clang-tools-path=/home/butta/swift-5.7-RELEASE-ubuntu20.04/usr/bin/
--host-cc=/usr/bin/clang-13 --host-cxx=/usr/bin/clang++-13
--cross-compile-hosts=android-aarch64 --cross-compile-deps-path=/home/butta/swift-release-android-aarch64-24-sdk
--skip-local-build --xctest --swift-install-components='clang-resource-dir-symlink;license;stdlib;sdk-overlay'
--install-swift --install-libdispatch --install-foundation --install-xctest
--install-destdir=/home/butta/swift-release-android-aarch64-24-sdk
--cross-compile-append-host-target-to-destdir=False --build-swift-static-stdlib -j9

I experimented with swiftc -static-stdlib and the SPM equivalent a couple years ago and found that, other than building small executables, it doesn't work very well, with various link-time errors. I don't think anybody has worked on really polishing it up, even on linux given the errors you note there, so if you'd like to use it, it will require some work.

1 Like

I actually had some major success with this after my original post (was on an intercontinental flight so could not update until now):

  1. I would be curious to find out "who" is deciding the library search path mentioned. If we can update that in the swift frontend for static builds, there'd be very little left to do. That's because:
  2. Should be fixed when this PR gets merged!
  3. I figured out the objc_retainAutoreleasedReturnValue issue soon after posting. I grepped the dynamic libraries in lib/swift/android for that string and found it in libFoundation.so and libswiftDispatch.so. That seemed strange to me, so I looked a bit further and found that there was one additional library in swift_static that references the symbol: DispatchStubs. So I added -lDispatchStubs to the linker invocation and boom, it "works"! (albeit with potential UB due to 2.). We'd also want to add this to the linker invocation.

The code size is down from a bunch of .so files (including Foundation, ICU, etc.) totalling ~50MB zipped a couple of months ago to less than 6MB now (Foundation removed, statically linked). We will not use the static build yet due to the UB but, once that fix is merged, static linking for Android will be very close to being generally available :ok_hand:

5 Likes