CI for Packages on Windows & Android?

I don’t know anymore if I’m actually getting closer, or if I’m just derailing it further...

CANNOT LINK EXECUTABLE: library "lib/swift/android/i686/libswiftCore.so" not found

That appears to be a relative path, but what is it supposed to be relative to? LD_LIBRARY_PATH? The executable location? I tried copying libswiftCore.so to both and it didn’t help.

Even more confusing, libswiftCore.so does not even reside in i686 in the SDK. Where is the path coming from?

Maybe this is the problem?

$ [...]/llvm-objdump -p .build/i686-unknown-linux-android/debug/libswiftCore.so
.build/i686-unknown-linux-android/debug/libswiftCore.so: file format ELF32-i386
[...]
Version definitions:
1 0x01 0x0303464f lib\swift\android\i686\libswiftCore.so
[...]

Ugh, the whole directory structure mess :-(. This is directly related to the Swift Linux layout considerations thread.

/Library/Developer/Platforms/Android.platform/Developer/SDKs/Android.sdk/usr/lib/swift/android/libswiftCore.so is the actual location in the SDK that you find libswiftCore.so. Im still not certain why its looking for it by absolute path.

You could try adding a library search path for it and seeing if that helps. It could also be an errant RPATH entry in the binary? The debug output seems unrelated.

Maybe the strange path has something to do with my workaround for --sysroot? SwiftPM was obstinately pointing --sysroot at the Android.sdk directory, so I copied the real sysroot contents into it.

The branch where I’ve been toying with it is here (for now).

No, it probably has nothing to do with my handling of --sysroot. The test executable produced by SwiftPM looks like it was linked properly:

$ [...]/llvm-objdump -p .build/i686-unknown-linux-android/debug/WorkspacePackageTests.xctest
.build/i686-unknown-linux-android/debug/WorkspacePackageTests.xctest: file format ELF32-i386
[...]
RUNPATH $ORIGIN
NEEDED libswiftSwiftOnoneSupport.so
NEEDED libswiftCore.so
NEEDED libFoundation.so
NEEDED libswiftGlibc.so
NEEDED libdl.so
NEEDED libm.so
NEEDED libswiftDispatch.so
NEEDED libdispatch.so
NEEDED libBlocksRuntime.so
NEEDED libFoundationXML.so
NEEDED libFoundationNetworking.so
NEEDED libXCTest.so
NEEDED libc.so

Whereas the libswiftSwiftOnoneSupport.so from the SDK contains a reference to lib/swift/android/i686/libswiftCore.so that looks out of place:

$ [...]/llvm-objdump -p .build/i686-unknown-linux-android/debug/libswiftSwiftOnoneSupport.so
.build/i686-unknown-linux-android/debug/libswiftSwiftOnoneSupport.so: file format ELF32-i386
[...]
NEEDED libm.so
NEEDED libdl.so
NEEDED liblog.so
NEEDED libc++_shared.so
NEEDED libicuin64.so
NEEDED libicuuc64.so
NEEDED lib/swift/android/i686/libswiftCore.so
NEEDED libc.so

At least libswiftGlibc.so also exhibits the same NEEDED entry: lib/swift/android/i686/libswiftCore.so

Amazing. This sounds like an artifact of the terrible CMake in CMake build that we have for the standard library. We should trace through the swift build and fix it so that the link is done properly and the DT_NEEDED entry is libswiftCore.so and we setup the DT_RUNPATH properly.

Thanks for continuing to push on this.

I was able to bandage it for now with patchelf.

Now I get:

library "libicudt64.so" not found

The Azure artifact of ICU (for Android x86) only contains libicuin64.so and libicuuc64.so. Where is the third one supposed to come from?

I definitely need help with that aspect. That is the data file itself, which is non-trivial (understatement!) to build. You might be able to get away with grabbing the one from the last Linux builds (which seems to have unexpectedly broken (without a change to the build). See the rules at swift-build/CMakeLists.txt at master · compnerd/swift-build · GitHub for details on how that is built.

Hey, I've been building the Swift toolchain natively on Android and ran into some similar issues before. I had the same problem with linking against the full path to the shared library when the soname for the library wasn't set, maybe that's affecting you somehow. readelf -d libswiftCore.so | grep SONAME will tell you if the soname has been set: compare with the result for other working Swift libraries to see the difference.

Another issue that might affect you is that Android uses DT_RUNPATH and actually enforces it, ie every shared library must list its shared library dependencies explicitly. This can give you cryptic errors in a dependency tree, where it errors because it can't find libFoundation.so, but you're confused because the library libFoo.so that you're linking against clearly lists that dependency and its RUNPATH. But if libFoo.so depends on some other library libGoo.so that doesn't have the RUNPATH for Foundation set properly, that might really be the one causing the problem: the dynamic linker error simply won't tell you which library is missing its dependency.

As for building libicu for Android, I use the Termux package for that. You can download the binary package and unpack it or build it from source yourself. The only issue is that it's built against Android API 24, so you will have to build the Swift SDK for Android with that API too.

If you have any questions, let me know.

1 Like

Hurray! I got the package tests to run successfully. :partying_face: Some clean‐up is in order, and then I’ll post it back here.

For ICU, I noticed that @Geordie_J/flowkey’s bundling of the Azure artifacts does include the addition of libicudt64.so. @compnerd, you should ask them how they got it built. All I had to do was experiment a little to find an architecture that was both provided by flowkey and worked in the emulator on GitHub’s host—half of them just time out trying to boot. So x86_64 is viable, but while the other architectures build just as easily, it seems they cannot be tested with GitHub Actions at this time.

As for the attempts at getting libicudt64.so from other places:

  • The Linux binary didn’t seem to work as a drop‐in substitute.
  • I did try to adjust the swift-build set‐up to include it, but the error messages were too vague so I gave up for the time being and went looking for other options. (I may come back to it though; we’ll see.)
  • Artifacts and build scripts for ICU for Android are a dime a dozen across the web, but everything I could find ended up with different .so files incompatible with the rest of the toolchain.
  • I briefly tried the Termux package, but the downloaded archive was only 100 kB—instead of the expected 25 MB—and it couldn’t unarchive successfully. I’m not sure what was up with that.

I built the ICU data for the various architectures using the standard autotools configure/make scripts included in the ICU source bundle, no tricks or patches needed. I think @compnerd is aware this is possible but wanted to get a CMake build working so hasn’t yet integrated it

1 Like

Okay, this is the script for Android. I would be happy to fix anything that looks wrong to those of you smarter than I.

Workaround Notes:

  1. SwiftPM isn’t in the cross‐compilation toolchain, so two toolchains are needed at once.
  2. SwiftPM must be ≤ 5.1.1; newer releases suffer from SR‐12123.
  3. libswiftSwiftOnoneSupport.so and libswiftGlibc.so need linkage adjustments. (See earlier posts.)
  4. SwiftPM insists on the wrong --sysroot, so the contents of the real sysroot need to be copyied to where it points.
  5. libicudt64.so needs to be acquired separately.
  6. (I haven’t bothered with FoundationNetworking or FoundationXML yet; they have additional dependencies.)

I will continue working on trying to actually fix some of the bugs involved so the workarounds can be removed and the scripts can be shortened, but I will do that in other threads.

If I try to use FoundationNetworking, I get this error at runtime:

CANNOT LINK EXECUTABLE "[...]PackageTests.xctest": cannot locate symbol "zlibVersion" referenced by "[...]/libFoundationNetworking.so"...

I tried putting libz.so (from the Azure artifact) in the same directory, but it made no difference.

Any ideas?

IIRC, android does have a system provided zlib. If it is linking against the NDK version, then there would be issues with the system platform version and the NDK platform version which could manifest as unresolved dependencies.

I don't see any shared libraries in the Android SDK that reference that symbol, either from the latest 5.1.4 release or a master snapshot from last month (both natively built on Android), but it may be that RUNPATH issue I mentioned earlier, where some shared library that FoundationNetworking depends on looks for that symbol.

You can check if that library is linked against zlib with readelf -d libFoundationNetworking.so | grep NEEDED and if it calls that symbol with readelf -sW libFoundationNetworking.so | grep zlibVersion, but my guess is both will turn up empty. Then you can search each of its dependencies in turn, to figure out which library's linkage is broken.

I tried to build the example from https://github.com/compnerd/swift-build-examples/tree/master/HelloWorld-CMake and got the following error using the command listed there. What can I do to fix this?

BTW, Azure DevOps Services | Sign In should be changed to https://compnerd.visualstudio.com/swift-build/ on https://github.com/compnerd/swift-build/blob/master/docs/Windows.md .

    Run Build Command(s):C:/Library/ninja/ninja.exe cmTC_58eb8 && [1/1] Linking Swift executable cmTC_58eb8.exe
    FAILED: cmTC_58eb8.exe CMakeFiles/cmTC_58eb8.dir/main.swift.obj cmTC_58eb8.swiftmodule
    cmd.exe /C "cd . && C:\Library\Developer\Toolchains\unknown-Asserts-development.xctoolchain\usr\bin\swiftc.exe -output-file-map CMakeFiles\cmTC_58eb8.dir\output-file-map.json -incremental -num-threads 2 -emit-executable -o cmTC_58eb8.exe -emit-module -emit-module-path cmTC_58eb8.swiftmodule -emit-dependencies    main.swift  -Xlinker -implib:cmTC_58eb8.lib   && cd ."
    <unknown>:0: error: unable to load standard library for target 'x86_64-unknown-windows-msvc'
    ninja: build stopped: subcommand failed.

Yes, those are a bit outdated. Stdlib is a part of SDK now, and swiftc needs some guidance to find it. The easiest way is to prepare cmake caches with correct "-resource-dir" and link directory flags.

Check out this caches file. You can pass "-D CMAKE_Swift_SDK=" and include caches file with "-C" option. Note that CMAKE_Swift_SDK have to be passed before caches option. And don't forget to delete previous cmake output.

Maybe someone could just update GitHub - compnerd/swift-cmake-examples: Swift example projects accordingly so there is an easy starting point? Being not familiar with cmake I still have to puzzle over it... Thanks.

The problem is that the invocation of the flags are somewhat more complicated. It is due to the file system layout that the additional flags are needed (in theory if you symlinked the SDK into the toolchain, the options would disappear, but make some other things more complicated). Furthermore, the examples are cross-platform (that is, they should be usable on Linux, Windows, and macOS). Each platform's toolchain has its own quirks (see Swift Linux layout considerations (aka Linux is difficult, lets go shopping) for a more desirable state).

However, patches to improve the documentation are welcome :slight_smile: