Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[android] Move to the NDK's unified sysroot #34491

Merged
merged 1 commit into from
Feb 7, 2021

Conversation

finagolfin
Copy link
Member

@finagolfin finagolfin commented Oct 29, 2020

Since the NDK is removing the platforms/ and sysroot/ directories in the next release, switch to the unified sysroot in toolchains/llvm/ and take advantage of a bunch of simplification that's now possible.

Starting with NDK 19 early last year, the unified sysroot was made available and it was just announced that the old split sysroot will be removed in the next NDK 22. I was able to cross-compile the stdlib up through llbuild with this patch and a tweaked #33724, using the unified sysroot from the current NDK 21d. The only disadvantage of this patch is that NDK 18 from 2018 and earlier will not be supported. I have kicked off a build natively in Termux with this patch, will update when that finishes no problem.

@compnerd, if you could try this out yourself, would be good to get independent testing and review.

@@ -70,6 +70,10 @@ function(_add_target_variant_c_compile_link_flags)
endif()
endif()

if("${CFLAGS_SDK}" STREQUAL "ANDROID")
set(DEPLOYMENT_VERSION ${SWIFT_ANDROID_API_LEVEL})
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting this variable adds the API level to the target triple just below, which then enables clang to automatically find the right Android libraries when linking.

@@ -297,12 +301,6 @@ function(_add_target_variant_c_compile_flags)
endif()

if("${CFLAGS_SDK}" STREQUAL "ANDROID")
list(APPEND result -nostdinc++)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without this flag, clang automatically finds the libc++ headers in the unified sysroot and swift_android_libcxx_include_paths is no longer needed.

@compnerd
Copy link
Member

compnerd commented Nov 4, 2020

CC: @drodriguez

@compnerd
Copy link
Member

compnerd commented Nov 4, 2020

@buttaface I'm not sure I fully understand how this is supposed to be backwards compatible. Does this basically force all builds to have the newest NDK?

Copy link
Contributor

@drodriguez drodriguez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing against raising the minimum needed NDK, if that's what the community wants. But before leaving behind some people we will need to figure out what those minimums mean. You say NDK 19 has the unified sysroot, does that map to some minimum version of Android that makes everyone happy?

However, this change is going to be synchronized with changes in CI, since those are still using r17, so this change will break them and we will completely make them fail. I want to also try to pre-check these changes on a similar setup to CI, hopefully over the weekend. Can I have a week before anything is merged? This might need changes in the CI configuration that only @shahmishal can do (as far as I know), so it needs a little bit more coordination.

Another detail would be trying to find any documentation that refers to supported minimums, and check if we need to update some of them.

One question: is adding the version to the triple important? Without the version, I suppose the latest API level is used? Also, I was under the impression that if one specifies the version in the triple, one might not need to inject the __ANDROID_API__ macro as well.

Finally, my recommendation would be moving many of the code happing in SwiftConfigureSDK.cmake into the Android specific fails, so all the particulars about the NDK and native paths are hidden and do not bother other platforms.

@@ -277,66 +271,59 @@ macro(configure_sdk_unix name architectures)

foreach(arch ${architectures})
if("${prefix}" STREQUAL "ANDROID")
# Get the prebuilt suffix to create the correct toolchain path when using the NDK
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like something that it is worth moving into SwiftAndroidSupport.cmake. A function that returns a sysrtoo variable, for example. It will remove code here with the specifics, and will reduce specific paths below (${SWIFT_ANDROID_NDK_SYSROOT}/usr/include reads better than ${SWIFT_ANDROID_NDK_PATH}/toolchains/llvm/prebuilt/${_swift_android_prebuilt_build}/sysroot/usr/include and will be easier to modify later, if the path changes again).

Something similar should be done with SWIFT_SDK_ANDROID_ARCH_${arch}_NDK_PREBUILT_PATH. I don't know why those ended up in this file.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These have been in this file for years, perhaps because these platform variables have always been set here, I'll look into reorganizing it.

@finagolfin
Copy link
Member Author

finagolfin commented Nov 5, 2020

Does this basically force all builds to have the newest NDK?

No, as noted above, this unified sysroot, that combines the unified headers from ndk/sysroot/ and the platform libraries from ndk/platforms/, was added with NDK 19 in January 2019, so all subsequent NDKs have it.

NDK 19 has the unified sysroot, does that map to some minimum version of Android that makes everyone happy?

Some NDKs over the years have dropped lower APIs, for example, NDK 18 dropped ICS APIs 14 and 15 in 2018. I have no idea who wants older Android APIs supported: the default used in this repo is 21, which is the oldest API supported in the unified sysroot in the current NDK 21d,(never mind, the unified sysroot supports all the same APIs: API 16 and newer for 32-bit and API 21 and newer for 64-bit) and the first API that supported 64-bit Android, which is the vast majority of Android use today.

Can I have a week before anything is merged?

No problem, I thought you controlled the Android community CI, didn't think Mishal had anything to do with changing that config.

find any documentation that refers to supported minimums

I'll look in this repo, anywhere else?

is adding the version to the triple important?

As noted in my comment above, that is what makes it possible to remove swift_android_lib_for_arch() from this pull, replacing it with this logic in the clang Driver instead.

Without the version, I suppose the latest API level is used?

No, it just errors out and you have to specify the path to the API libraries to link against yourself, to get it to work again.

if one specifies the version in the triple, one might not need to inject the __ANDROID_API__ macro as well.

I have been specifying that myself recently for the corelibs, just like it's done here for the stdlib, but I now see there was a commit added for that many years back, swiftlang/llvm-project@a89d8ff. I don't know if that's applied though, I'll check.

@finagolfin
Copy link
Member Author

finagolfin commented Nov 5, 2020

Made the changes asked for in a new commit for easy review, and after making sure that __ANDROID_API__ is now applied by clang, once the API level is passed in the triple, removed it from the CMake config. Confirmed by cross-compiling the stdlib and corelibs again with this pull.

@drodriguez, what do you think about a separate pull to similarly add the __ANDROID_API__ in the ClangImporter, if the API is specified in the Swift triple? Never mind, I checked and it's already applied by ClangImporter if the API is included in the Swift triple.

@drodriguez
Copy link
Contributor

I will try to find time tomorrow for more testing, but as it is, it seems to be missing some paths to link correctly.

I tested the r17c used in CI, and it will not work. I checked r18 just in case, and the results are the same.

With r19c it seems to advance a little bit more, but there seems to be problems finding -latomic. In my r19 copy, for AArch64 it seems to be in android-ndk-r19c/toolchains/llvm/prebuilt/linux-x86_64/aarch64-linux-android/lib64/ (a little to the side of the sysroot) and for ARMv7 in android-ndk-r19c/toolchains/llvm/prebuilt/linux-x86_64/arm-linux-androideabi/lib/.

Which NDK are you using?

@finagolfin
Copy link
Member Author

I tested the r17c used in CI, and it will not work. I checked r18 just in case, and the results are the same.

Sure, that's to be expected from what I noted above.

With r19c it seems to advance a little bit more, but there seems to be problems finding -latomic.

Huh, never had that problem with NDK 21d, and I see libatomic.a in the same paths in that one. What clang do you use when building? I make sure to use the one from the NDK.

I will try building with NDK 19 and see if I can reproduce. In the meantime, you could remove the libatomic dependency and move forward, as it's not needed and I submitted an earlier pull to remove it. If that works, maybe we can bring that commit to this pull and get it in.

@finagolfin
Copy link
Member Author

Just tried building the Nov. 4 source snapshot with NDK 19c and it errors out when configuring LLVM for Android AArch64, both with and without this pull:

-- Performing Test LLVM_LIBSTDCXX_MIN - Failed
CMake Error at cmake/modules/CheckCompilerVersion.cmake:97 (message):
  libstdc++ version must be at least 5.1.                                                        

I guess you're not using the NDK's clang if you don't hit that first. I apply #34437 and pass in these build-script compiler flags to make sure only the NDK's clang is used:

--native-clang-tools-path=/home/butta/swift/android-ndk-r19c/toolchains/llvm/prebuilt/linux-x86_64/bin --host-cc=/home/butta/swift/android-ndk-r19c/toolchains/llvm/prebuilt/linux-x86_64/bin/clang --host-cxx=/home/butta/swift/android-ndk-r19c/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++

Also, because of the issues noted in #30170, I don't simply build the Android SDK alongside the host linux one by passing in --stdlib-deployment-targets=android-aarch64 as before, but pass in --build-swift-tools=0 --native-swift-tools-path=/home/butta/swift/swift-DEVELOPMENT-SNAPSHOT-2020-11-04-a-ubuntu20.04/usr/bin/ --cross-compile-hosts=android-aarch64 --skip-local-build instead to only build the Android SDK (that requires the one-line LLVM-related patch shown in the main comment describing #34437 to be applied, to avoid building unnecessary LLVM targets).

Getting back to NDK 19c, is that stdc++ versioning issue expected? I don't see it with the latest stable NDK 21d.

@finagolfin
Copy link
Member Author

Just tried swapping in NDK 20b, no problem, with the additional flags and two other small patches mentioned in my last comment.

@drodriguez
Copy link
Contributor

What clang do you use when building? I make sure to use the one from the NDK.

The command that fails is using the just built Clang, which reports being 10.0.0, so probably close to 10.0.0 + the Apple patches.

In the meantime, you could remove the libatomic dependency and move forward, as it's not needed and I submitted an earlier pull to remove it.

I will try to find time to check that commit again. It doesn't seem to apply cleanly (or at least GitHub UI says so), so if you to clean it up, it would be nice. Also, since you are linking to one commit, are you saying to apply just one commit, or the full PR?

I guess you're not using the NDK's clang if you don't hit that first.

Right. The build script normally uses the system Clang (version 6.0.0-1ubuntu2 from Ubuntu 18.04 LTS) to build LLVM, and then the just built Clang to build Swift and the rest. The NDK Clang is not used for anything (as far as I remember). The NDK did not ship with Clang, so it has never been used (if I am not mistaken).

I apply #34437 and pass in these build-script compiler flags to make sure only the NDK's clang is used

Is there a full plan of what you are trying to to, and links to each of the PRs, in what order they should be applied, and anything else that would help to clarify all the pieces involved? I imagine that the options you propose can be provided as part of the build preset, but those options also mean moving the minimum NDK (which I repeat, I am fine, but has to be done carefully). Also the Clang from the NDK should not be that different from the upstream Clang that's build. For example in NDK r19c, there seems to be a Clang 8.0.2. It is difficult to track which differences Google added on top, but I am pretty sure most of the biggest differences must be available in upstream Clang by the time 10.0.0 was released.

I don't simply build the Android SDK alongside the host linux one

I don't know if the CI can do a two-step invocation of build-script. That's something that needs to be changed in the configuration of CI. If we can avoid the two-steps, it would be so much easier to apply all these changes. If I understand correctly the two-step process seems to depend on some changes that are not in any PR, only in a comment, right?

is that stdc++ versioning issue expected?

LLVM increased their requisite for stdc++ version "recently" (like in the last year or a little more). I think for a couple of releases there's a CMake configuration that one can provide to avoid the problem (look for LLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN).

My recommendation would be making a clear path to your objective. Small modifications (one of top of the other, if necessary), that we can check and apply. We should not break the little CI that we already have in place. Making small changes allows us to check and plan before commiting to a huge change.

@finagolfin
Copy link
Member Author

finagolfin commented Nov 9, 2020

The command that fails is using the just built Clang

OK, should be fine then. If you were passing in --build-swift-tools=0 like me, it can pick up some really old system clang, which could cause problems and why I asked. I think the issue here is that the NDK clang in toolchains/llvm/prebuilt/linux-x86_64 automatically picks up libatomic next to it, but the freshly built clang doesn't.

since you are linking to one commit, are you saying to apply just one commit, or the full PR?

Just the commit, which is why I mentioned potentially bringing it here. I will see if it needs to be updated and let you know. It is really easy to change those 2-3 Android-specific lines manually yourself in the meantime if you like.

Is there a full plan of what you are trying to to

I upstream patches used to build the native Swift toolchain for Android, which ships as a Termux package. This pull is mostly outside that though: I submitted this because I found out that the next NDK is removing the platforms/ and sysroot/ directories that this repo's NDK config uses, so this Swift build will break when that's released. It so happens the Termux builds already use the unified sysroot the NDK is switching to, so some of my Termux patches came in handy for this switch.

links to each of the PRs, in what order they should be applied, and anything else that would help to clarify all the pieces involved?

To be clear, I was just explaining how I cross-compiled the stdlib and corelibs for Android alone with this pull, but the additional patches are not necessary to build this pull. If you simply use the 6-7 additional flags I listed, but change --native-clang-tools-path to --native-llvm-tools-path (because of a bug that #34437 fixes), leave off the --skip-local-build flag I used, and add one more flag I forgot to mention, --build-runtime-with-host-compiler=1, you can build with this pull alone. The other patches and the removed local build flag merely skip building unneeded LLVM targets and the linux SDK for Swift too.

the Clang from the NDK should not be that different from the upstream Clang that's build

Yes, I was mostly trying to avoid some old system clang 3.8 or something, plus the NDK clang probably automatically picks up some libraries next to it.

I don't know if the CI can do a two-step invocation of build-script

I'm not sure what two steps of invoking build-script that you are referring to. I simply download a prebuilt trunk snapshot of the Swift toolchain, apply this pull and the two other small patches I mentioned, and run this build-script command once (I use the prebuilt Termux package of ICU for Android):

./swift/utils/build-script -R --no-assertions --skip-build-cmark --skip-build-llvm
--android --android-ndk /home/butta/swift/android-ndk-r21d/ --android-arch aarch64
--android-api-level 24 --android-icu-uc /data/data/com.termux/files/usr/lib/libicuuc.so
--android-icu-uc-include /data/data/com.termux/files/usr/include/
--android-icu-i18n /data/data/com.termux/files/usr/lib/libicui18n.so
--android-icu-i18n-include /data/data/com.termux/files/usr/include/
--android-icu-data /data/data/com.termux/files/usr/lib/libicudata.so
--build-swift-tools=0 --native-swift-tools-path=/home/butta/swift/swift-DEVELOPMENT-SNAPSHOT-2020-11-04-a-ubuntu20.04/usr/bin/
--native-clang-tools-path=/home/butta/swift/android-ndk-r21d/toolchains/llvm/prebuilt/linux-x86_64/bin
--host-cc=/home/butta/swift/android-ndk-r21d/toolchains/llvm/prebuilt/linux-x86_64/bin/clang
--host-cxx=/home/butta/swift/android-ndk-r21d/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++
--cross-compile-hosts=android-aarch64 --skip-local-build --build-runtime-with-host-compiler=1 -j9

As noted above, you can build with this pull alone and no added patches if the flags used are changed slightly.

look for LLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN

OK, I guess that's only an issue when using --cross-compile-hosts like I do with NDK 19c, whereas you simply build the Swift stdlib for Android as part of the linux toolchain, which doesn't configure LLVM with the NDK.

Making small changes allows us to check and plan before commiting to a huge change.

Yeah, that's pretty much what I've been doing. I think the issue is more that I haven't built the Swift toolchain for linux since January, downloading the official snapshots or releases and using those instead.

Why don't you try some variation of that prebuilt compiler approach with this pull, ie after swapping out my Termux libicu with what you normally do, and I will try the full compiler build with this pull and make any changes needed? That way, we will have both tried each major approach and can make the build more robust.

@finagolfin
Copy link
Member Author

finagolfin commented Nov 9, 2020

Alright, I was able to reproduce your issue much easier, by keeping my build-script invocation to build the Swift stdlib for Android alone with a prebuilt Swift toolchain, but replacing the path in each of the three clang flags with the Swift-forked prebuilt clang, eg --native-clang-tools-path=/home/butta/swift/swift-DEVELOPMENT-SNAPSHOT-2020-11-04-a-ubuntu20.04/usr/bin/ instead of the NDK clang path used above. I went ahead and pulled that commit removing the libatomic dependency over to this pull, along with a couple other places that were missed.

Finally, linking failed because it was now missing the path to libgcc when linked with the non-NDK clang, so I added a last three-line commit so the stdlib has the path for that too and it finally built fine. I suggest you apply this new pull, or just the last two commits, to your failing build and --reconfigure: it should cross-compile the stdlib fine for Android now.

@drodriguez
Copy link
Contributor

Doesn't seem to work. I get the same problem.

[67/316][ 21%][2.328s] Linking C shared library test-android-aarch64/libBlocksRuntime.so
FAILED: test-android-aarch64/libBlocksRuntime.so
: && /usr/bin/clang -fPIC -Wno-unknown-warning-option -Werror=unguarded-availability-new -fno-stack-protector -fPIC -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wmissing-field-initializers -Wimplicit-fallthrough -Wcovered-switch-default -Wdelete-non-virtual-dtor -Wstring-conversion -fdiagnostics-color -ffunction-sections -fdata-sections -O3  -target aarch64-unknown-linux-android21 --sysroot=/home/danielrodriguez/android-ndk-r19c/toolchains/llvm/prebuilt/linux-x86_64/sysroot -lm -fuse-ld=lld -shared -Wl,-soname,libBlocksRuntime.so -o test-android-aarch64/libBlocksRuntime.so test/CMakeFiles/BlocksRuntimeStub-android-aarch64.dir/__/test-android-aarch64/Inputs/BlocksRuntime.c.o -L/home/danielrodriguez/swift-source/build/my_android_aarch64/llvm-linux-x86_64/./lib   -L/home/danielrodriguez/swift-source/build/my_android_aarch64/swift-linux-x86_64/./lib/swift/android/aarch64   -L/home/danielrodriguez/swift-source/build/my_android_aarch64/swift-linux-x86_64/./bin/../lib/swift/android/aarch64   -L/home/danielrodriguez/swift-source/build/my_android_aarch64/swift-linux-x86_64/./bin/../lib/swift/android   -L/usr/lib/swift   -L/home/danielrodriguez/android-ndk-r19c/toolchains/llvm/prebuilt/linux-x86_64/sysroot/../lib/gcc/aarch64-linux-android/4.9.x   -L/home/danielrodriguez/libiconv-libicu-android/arm64-v8a -ldl  -llog  /home/danielrodriguez/android-ndk-r19c/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/libc++abi.a  /home/danielrodriguez/android-ndk-r19c/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/libc++_shared.so  /home/danielrodriguez/libiconv-libicu-android/arm64-v8a/libicui18nswift.so  /home/danielrodriguez/libiconv-libicu-android/arm64-v8a/libicuucswift.so && :
/usr/bin/ld.lld: error: cannot open crtbegin_so.o: No such file or directory
/usr/bin/ld.lld: error: unable to find library -lm
/usr/bin/ld.lld: error: unable to find library -ldl
/usr/bin/ld.lld: error: unable to find library -llog
/usr/bin/ld.lld: error: unable to find library -ldl
/usr/bin/ld.lld: error: unable to find library -lc
/usr/bin/ld.lld: error: unable to find library -ldl
/usr/bin/ld.lld: error: cannot open crtend_so.o: No such file or directory
clang: error: linker command failed with exit code 1 (use -v to see invocation)

I tested the lib atomic change in isolation (since when I tested #30170 I got so many errors), and it seems that it doesn't create more breakage (I could not test the executable tests, only the non-executable). If you want to submit that one as an independent change, I imagine we can merge that small piece independently.

@finagolfin
Copy link
Member Author

Doesn't seem to work. I get the same problem.

No, this is completely different now, it's somehow trying to cross-link libdispatch.so for Android but with the system clang, not the Swift-forked clang or the NDK clang. Honestly, I always just disable building libdispatch as part of this repo, as it's built separately later anyway. Are you still building with the preset, ie building the compilers and everything? Maybe that's a bug that it's not using the right clang to build that.

I tested the lib atomic change in isolation... we can merge that small piece independently.

OK, I will spin that off.

when I tested #30170 I got so many errors

Yeah, I need to rebase that and rework parts of it. I will let you know when it's ready.

Btw, I'm putting together prebuilt SDKs for Android now, try that out and let me know what you think.

@drodriguez
Copy link
Contributor

No, this is completely different now, it's somehow trying to cross-link libdispatch.so for Android but with the system clang, not the Swift-forked clang or the NDK clang.

I see. Maybe we can try to prefer the just built Clang for that libdispatch external project. I wonder if @compnerd has some opinion about it. It seems that the system Clang is preferred, but I don't understand the exact reason.

Honestly, I always just disable building libdispatch as part of this repo, as it's built separately later anyway. Are you still building with the preset, ie building the compilers and everything? Maybe that's a bug that it's not using the right clang to build that.

The idea of the build-script and the presets is that they are defining what happens in CI, so it is reproducible. Unless someone knows for sure that we can do something else, the build-script has to be executed in CI, and only once, with a preset (and some options, but those should not change that much).

All those multi-step processes you are describing are not going to be a realistic option (for CI). That's fine for third party SDKs.

@finagolfin
Copy link
Member Author

It seems that the system Clang is preferred, but I don't understand the exact reason.

I'll look into what it's doing.

All those multi-step processes you are describing are not going to be a realistic option

As I noted above, there is no multi-step process. I simply apply this pull, a couple other small patches, and run the build-script command given once.

The issue here really is that the current Android preset tries to build way too much, rather than just build the Android SDK with a prebuilt compiler, as I've been doing with the build-script command shown above. If doing that, the libdispatch build in this repo is completely unnecessary, as it isn't needed for the standalone stdlib. In fact, it's really only needed for a couple ancillary host tools like SourceKit, so it can be disabled most of the time unless you know those tools are being built.

Actually, I guess that means you're not building with the preset anymore, if it's trying to cross-compile libdispatch for the host tools? If so, what do you think about disabling the libdispatch build in this repo with another CMake check when building a standalone stdlib like this? I can add a patch for that to this pull.

In the meantime, you can disable that CMake check I linked and see if this pull works when that's disabled.

@finagolfin
Copy link
Member Author

I'll look into what it's doing.

Looks like it uses the host-cc clang to build libdispatch. But the preset shouldn't be cross-compiling the host tools and my alternate build-script invocation that only builds SDKs says to pass in the NDK clang as host-cc, so I'm not sure what build-script command you're running at this point. That's why I asked yesterday if you're still running the preset or something else.

@finagolfin
Copy link
Member Author

Split off the libatomic commit as #34757, which now needs to be applied before building this pull, and rebased.

@finagolfin
Copy link
Member Author

Since there's some confusion about what build-script command to use when testing this pull, I downloaded the Nov. 17 trunk source snapshot and official prebuilt toolchain, applied this pull alone, and found a command that should work:

./swift/utils/build-script -R --no-assertions --skip-build-cmark --skip-build-llvm
--android --android-ndk /home/butta/swift/android-ndk-r21d/ --android-arch aarch64
--android-api-level 24 --android-icu-uc /data/data/com.termux/files/usr/lib/libicuuc.so
--android-icu-uc-include /data/data/com.termux/files/usr/include/
--android-icu-i18n /data/data/com.termux/files/usr/lib/libicui18n.so
--android-icu-i18n-include /data/data/com.termux/files/usr/include/
--android-icu-data /data/data/com.termux/files/usr/lib/libicudata.so
--build-swift-tools=0 --native-swift-tools-path=/home/butta/swift-DEVELOPMENT-SNAPSHOT-2020-11-17-a-ubuntu20.04/usr/bin/
--native-clang-tools-path=/home/butta/swift-DEVELOPMENT-SNAPSHOT-2020-11-17-a-ubuntu20.04/usr/bin/
--host-cc=/home/butta/swift-DEVELOPMENT-SNAPSHOT-2020-11-17-a-ubuntu20.04/usr/bin/clang
--host-cxx=/home/butta/swift-DEVELOPMENT-SNAPSHOT-2020-11-17-a-ubuntu20.04/usr/bin/clang++
--libicu --build-runtime-with-host-compiler=1 -j9

Since this builds the Android stdlib with a prebuilt Swift-forked clang, not the NDK clang, the Android preset used by the CI should also work, which compiles the Swift-forked clang from scratch.

@drodriguez
Copy link
Contributor

Questions about the previous build-script line. I would have to turn those into a preset, and some of the flags are not really possible in CI, I am afraid.

  • --skip-build-cmark: I imagine this one is just to save time and doesn't change a lot the later work.
  • --skip-build-llvm: This one is probably not going to be possible. LLVM needs to be built to build the Swift compiler. If I understand correctly you are using pre-compiled toolchains and only dealing with the SDK. The CI does things in one go (toolchain + SDK). Do you think this is an essential flag or are you adding it for saving time?
  • --build-swift-tools=0: Same as above. I suppose this is to save time? CI will probably need to build those.
  • --native-swift-tools-path=… and --native-clang-tools-path=…: I imagine this are needed since LLVM and the Swift tools are being skipped, but should not be needed if CI is building LLVM and the Swift toolchain, right?
  • --host-cc and --host-cxx: Since we start without any Swift toolchain snapshot, CI will need to use the system compiler and not provide this ones explicitely.
  • --build-runtime-with-host-compiler: This is possible in your setup because the "host" compiler is actually one from a Swift snapshot, and has support for the Swift calling convention. This would not work the system compiler, as it is done in the CI machine.

We can do modifications to the CI preset (called buildbot_linux_crosscompile_android,tools=RA,stdlib=RD,build and buildbot_linux_crosscompile_android,tools=RA,stdlib=RD,build,aarch64 in the file utils/build-presets.ini), but the set of flags you offer are not possible for CI. They require pieces that will not be available in CI (like the snapshots). In CI we have to build from scratch the toolchain, and then build the SDK.

If you want to check if the CI would work, I would recommend the following:

  • Create a file in your home directory named .swift-build-presets.
  • Add the following content:
[preset: my_android_aarch64]
 mixin-preset=buildbot_linux_crosscompile_android,tools=RA,stdlib=RD,build,aarch64
 build-subdir=my_android_aarch64
 install-destdir=<path to swift-source directory>/build/my_android_aarch64/destdir
 installable-package=<path to swift-source directory>/build/my_android_aarch64/installable-package.tgz
 android-ndk=<path to your ndk>
 android-icu-uc=<path to your libicu for android>/libicuuc.so
 android-icu-uc-include=<path to your libicu for android includes>
 android-icu-i18n=<path to your libicu for android>/libicui18n.so
 android-icu-i18n-include=<path to your libicu for android>
 android-icu-data=<path to your libicu for android>/libicudata.so
  • Invoke the build script like the following: utils/build-script --preset=my_android_aarch64 install_destdir=foo installable_package=bar ndk_path=baz arm_dir=woot (even if the values that use those variables are overriden, one have to provide bogus values for testing).

If that passes, we are in the good track. Otherwise we need to tweak the build scripts and the preset as necessary. But we have to remember that we cannot use the toolchain until we build one.

I will try the last version before the weekend to see if we can advance this a little bit more. Thanks for all the hard work.

@finagolfin
Copy link
Member Author

I have not proposed anywhere that the CI change or that you add another preset, though I did criticize the current preset above. I'm giving you that command to try for your personal testing. If a variation of the command I gave, with the paths to your own prebuilt Android libicu, fails for you, then the preset from the CI will most likely not work with this pull either.

If this minimal SDK-only command works for you, then you should go ahead and start the much longer-running preset the CI uses, as it will most likely pass.

@drodriguez
Copy link
Contributor

The problem is that this PR as it stands (with the changes from 5 days ago), still fails. If we merge it, it will make the CI fail to build, so it should not be merged.

What I am trying to understand is what we need to change for these changes to go forward, and that's going to involve more changes, and maybe changes in the CI preset.

From what it looks, the problem was never the external project to build dispatch/BlocksRuntime, but a small stub library created for the tests (in test/CMakeLists.txt). That library is build using one of the helpers from the standard library, however, the standard library directory performs a lot of changes in the CMake variables to use the just built LLVM products or use the host compiler. Those changes are not done in the test directory (they cannot be done there, in fact).

With your setup (using a previously built Swift toolchain as the host compiler), you are using a newer compiler than the one available in Ubuntu 18.04 (that the CI machines are currently using). When that stub BlocksRuntime library tries to be compiled with the old system compiler, it fails because it doesn't know how to navigate the new NDK to find the necessary libraries. If I execute the same command pointing to a newer compiler, it works.

I have to figure out a way to make that work. The good thing is that it is independent of these changes. I will come back here when that work is done.

@finagolfin
Copy link
Member Author

The problem is that this PR as it stands (with the changes from 5 days ago), still fails.

With what error and which build-script command? Are you talking about the same error from six days ago? It wasn't clear what build-script command produced that error.

the problem was never the external project to build dispatch/BlocksRuntime, but a small stub library created for the tests (in test/CMakeLists.txt)

OK, that makes sense, as I have seen some other libdispatch being mentioned in the build output before, but a search of the test/ CMake config for dispatch turns up nothing. Maybe it's pulled in automatically by the CMake dependency system?

If you know where that compiler is set up in CMake, could you change it to use the freshly built Swift-forked clang? After all, if it's tied to testing the stdlib, it should be using the same compiler.

Part of the problem here is that I never run the tests when cross-compiling, only running the tests natively on Android with the Termux app, so I wasn't aware of this issue.

When that stub BlocksRuntime library tries to be compiled with the old system compiler, it fails because it doesn't know how to navigate the new NDK to find the necessary libraries.

I have to figure out a way to make that work.

An alternative to modifying the CMake config like I mentioned above would be to update the system clang in your CI to 10.0, or the oldest clang that you want to support and that detects the unified sysroot that was introduced with NDK 19 in January 2019, which would avoid needing any other changes to this repo.

@drodriguez
Copy link
Contributor

Created #34859. Those changes on top of this PR seems to correctly compile the stub and the test execute from a clean build.

With what error and which build-script command? Are you talking about the same error from six days ago? It wasn't clear what build-script command produced that error.

The same error as last week, and using a build-script command with a setup similar to the one described in #34491 (comment).

OK, that makes sense, as I have seen some other libdispatch being mentioned in the build output before, but a search of the test/ CMake config for dispatch turns up nothing. Maybe it's pulled in automatically by the CMake dependency system?

Look for BlocksRuntime in test/CMakeLists.txt or check #34859 to see what I was referring to.

If you know where that compiler is set up in CMake, could you change it to use the freshly built Swift-forked clang? After all, if it's tied to testing the stdlib, it should be using the same compiler.

Indeed it should have been the same compiler from the start. Because the stub was so simple, the host compiler was enough most of the time. Because of the changes here, that led many of the NDK paths to the compiler to find, older compilers couldn't no longer work.

An alternative to modifying the CMake config like I mentioned above would be to update the system clang in your CI to 10.0,

I will check if this is possible in the LTS that's installed in the servers. Let's do one change at at time, though.

@finagolfin
Copy link
Member Author

I just noticed that the doc also referred to the removed NDK directories, so updated the doc a bit too.

@finagolfin
Copy link
Member Author

Rebased and fixed merge conflict in C++ interop test.

Since the NDK removes the platforms/ and sysroot/ directories in the latest NDK
22, switch to the unified sysroot in toolchains/llvm/ and take advantage of a
bunch of simplification that's now possible.
@finagolfin
Copy link
Member Author

Updated to list the latest LTS NDK in the docs and disable the single failing C++ Interop test for Android instead, until we get #35707 working.

@drodriguez, this is ready to go, we should get it in so that NDK 22 and future NDKs keep working.

@drodriguez
Copy link
Contributor

I will try to have a look at this tomorrow and maybe a little during the weekend. Sorry for the delay.

@finagolfin
Copy link
Member Author

finagolfin commented Feb 5, 2021

I was just testing this pull out with #33724 and while there's no problem with the latest Feb. 2 trunk source snapshot and cross-compiling from linux with NDK 21e, I get the following error when switching to NDK 22:

swift-corelibs-foundation/Sources/Foundation/Data.swift:88:20: error: global function 'malloc' cannot be used in an '@inlinable' function because 'CoreFoundation' was imported implementation-only
return malloc(size)

This implies that Bionic C functions are being exported by CoreFoundation after updating the Android NDK. @spevans, any idea what might be going on or how we'd track this down?

@drodriguez
Copy link
Contributor

Checked both ARMv7 and AArch64 in the CI setup (with #35806 applied to avoid a test failure in AArch64) and it seems to work.

If @buttaface says it is good to merge after the testing succeeds, and anyone can merge, please do.

@drodriguez
Copy link
Contributor

@swift-ci please test

@drodriguez
Copy link
Contributor

@swift-ci please test Windows platform

@finagolfin
Copy link
Member Author

Windows CI failed because it ran out of disk space. 😄

@drodriguez
Copy link
Contributor

@swift-ci please test Windows platform

1 similar comment
@drodriguez
Copy link
Contributor

@swift-ci please test Windows platform

@finagolfin
Copy link
Member Author

Still the same problem, someone's going to need to clean the Windows CI up a bit:

There is not enough space on the disk.
        0 file(s) copied.
Build step 'Execute Windows batch command' marked build as failure

@drodriguez
Copy link
Contributor

I am going to merge. I don't think the Windows setup has been broken with these changes.

@drodriguez drodriguez merged commit e6f5913 into swiftlang:main Feb 7, 2021
@drodriguez
Copy link
Contributor

@buttaface seems that the test needed an extra // UNSUPPORTED: OS=linux-androideabi, but it seems to have passed in aarch64 (I don't know why I didn't get that problem in my tests).

@finagolfin
Copy link
Member Author

Thanks for reviewing and getting this in, I will cherry-pick to the 5.4 branch next so that keeps working.

@finagolfin finagolfin deleted the ndk-sysroot branch February 8, 2021 09:30
zayass pushed a commit to readdle/swift that referenced this pull request Apr 2, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants