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

SwiftDriver: initial work to properly handle android cross-compilation #1560

Merged
merged 2 commits into from
Jul 12, 2024

Conversation

compnerd
Copy link
Member

The intent here is to permit the Windows/macOS style cross-compilation for Android. This involves passing -sdk with the path to the "Swift SDK" which overlays the system's native SDK (NDK). The ANDROID_NDK_ROOT is a well-defined environment variable (setup by the SDK installer as well as a general expectation for Android development) that identifies the root of the installation of the NDK. This allows us to locate the native SDK root (--sysroot) for driving the linker driver amongst other paths.

if let sdk = parsedOptions.getLastArgument(.sdk)?.asSingle ?? env["SDKROOT"], !sdk.isEmpty {
rsrc = try VirtualPath(path: AbsolutePath(validating: sdk)
.appending(components: "usr", "lib", "swift")
.pathString)
Copy link
Contributor

Choose a reason for hiding this comment

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

Note that if -resource-dir is not specified, this behavior is already the default, so the only reason to do this is to override -resource-dir. Any reason why you need that? I think this is a bad idea to silently override it.

Copy link
Member Author

Choose a reason for hiding this comment

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

This is not the default - this is going to try to prefer the resources in the SDK rather than the toolchain (which allows us to have platform specific resources).

Copy link
Contributor

Choose a reason for hiding this comment

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

Huh, never mind, what I'm saying was true of the old C++ Driver, but is not true of this new swift-driver, after manually testing it on linux.

I think this is a genuine discrepancy between the two drivers that we should find the root cause and fix, rather than putting in partial workarounds like this.

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree that it's best to push swiftlang/swift#72409 over the line to avoid this particular workaround for SDK-relative logic here.

@compnerd
Copy link
Member Author

With this set of changes I am down to:

swiftc -target aarch64-unknown-linux-android28 -sdk "S:\Program Files\Swift\Platforms\Android.platform\Developer\SDKs\Android.sdk" -emit-executable -o hello hello.swift -Xclang-linker "-LS:\Program Files\Swift\Platforms\Android.platform\Developer\SDKs\Android.sdk\usr\lib\swift\android\aarch64" -Xclang-linker -resource-dir -Xclang-linker S:\b\android-ndk-r26b\toolchains\llvm\prebuilt\windows-x86_64\lib\clang\17

The bits that I would like to remove:

-Xclang-linker "-LS:\Program Files\Swift\Platforms\Android.platform\Developer\SDKs\Android.sdk\usr\lib\swift\android\aarch64"

This feels like we are failing to setup the library search path when we have a -sdk parameter for the layout like we do on Windows.

-Xclang-linker -resource-dir -Xclang-linker S:\b\android-ndk-r26b\toolchains\llvm\prebuilt\windows-x86_64\lib\clang\17

This is due to my builds missing clang_rt.builtins-... for Android and so we need to pull some files from the NDK.

Addressing those two issues would give us the following invocation:

swiftc -target aarch64-unknown-linux-android28 -sdk "S:\Program Files\Swift\Platforms\Android.platform\Developer\SDKs\Android.sdk" -emit-executable -o hello hello.swift

and with SDKROOT set to S:\Program Files\Swift\Platforms\Android.platform\Developer\SDKs\Android.sdk and ANDROID_NDK_ROOT set to S:\b\android-ndk-r26b, we should then be able to build code as:

swiftc -target aarch64-unknown-linux-android28 -emit-executable -o reduced reduced.swift

@finagolfin
Copy link
Contributor

The reason this entire approach doesn't already work is because of a regression in this new Swift Driver, see #1562. We should fix that for all platforms, not paper over it with these Android-specific changes.

@compnerd
Copy link
Member Author

I'm not sure I'm following the "papering over" here. The idea here is to default the -sdk parameter for android targets using ANDROID_NDK_ROOT, and subsequently -sysroot as well. You can always explicitly specify the parameters. We do something similar for Windows where SDKROOT will be used to default the parameter for -sdk on Windows, and we query the registry for determining the path to the various system include directories.

@finagolfin
Copy link
Contributor

There are two aspects to this pull, having this new swift driver read environment variables like SDKROOT/ANDROID_NDK_ROOT and looking in those paths for the right build files.

I don't think we should hard-code such environment variables in this driver, but always "explicitly specify" them, as you say. As for finding build files, the reason that doesn't work already is #1562: take a look at my detailed writeup from a couple weeks ago for why.

@compnerd
Copy link
Member Author

I disagree with you on that point. I would like the default value behavior for the targets where possible, much as it works on macOS. Fixing the behavior to work with the parameters however should be done.

The intent here is to permit the Windows/macOS style cross-compilation
for Android. This involves passing `-sdk` with the path to the "Swift
SDK" which overlays the system's native SDK (NDK). The
`ANDROID_NDK_ROOT` is a well-defined environment variable (setup by the
SDK installer as well as a general expectation for Android development)
that identifies the root of the installation of the NDK. This allows us
to locate the native SDK root (`--sysroot`) for driving the linker
driver amongst other paths.
@compnerd compnerd marked this pull request as ready for review June 24, 2024 20:13
@compnerd compnerd requested a review from artemcm June 24, 2024 20:13
@finagolfin
Copy link
Contributor

finagolfin commented Jun 25, 2024

@artemcm, as I already said, this should not be merged, as this is largely an Android-specific hack to paper over this problem till the real fix for all platforms, swiftlang/swift#72409, which has not been worked on for the last three months.

@compnerd
Copy link
Member Author

@swift-ci please test

@compnerd
Copy link
Member Author

@swift-ci please test Windows platform

Sources/SwiftOptions/Options.swift Show resolved Hide resolved
Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift Outdated Show resolved Hide resolved
if let sdk = parsedOptions.getLastArgument(.sdk)?.asSingle ?? env["SDKROOT"], !sdk.isEmpty {
rsrc = try VirtualPath(path: AbsolutePath(validating: sdk)
.appending(components: "usr", "lib", "swift")
.pathString)
Copy link
Contributor

Choose a reason for hiding this comment

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

I agree that it's best to push swiftlang/swift#72409 over the line to avoid this particular workaround for SDK-relative logic here.

@finagolfin
Copy link
Contributor

@compnerd, I think you've found a real bug in this repo with locating the Swift SDK overlay modules and headers in an SDK, which his swiftlang/swift#72409 fixes more generally.

Can you try reverting this pull in your local build, applying that frontend patch instead, and see if it fixes most of these issues? If it doesn't, you can pare this down to fix what's left, as that frontend fix will be needed for all platforms and should fix most of your issues here.

@hyp
Copy link
Contributor

hyp commented Jul 9, 2024

@artemcm I kept the 'swiftrt.o' adjustment based on the SDK path in this patch. swiftlang/swift#72409 does not work for Android specifically as I mentioned in that PR, as with that change Swift is unable to find the clang builtin headers next to the toolchain, which are separate from the Android SDK.

@hyp
Copy link
Contributor

hyp commented Jul 9, 2024

@swift-ci please test

@hyp
Copy link
Contributor

hyp commented Jul 11, 2024

@artemcm do you think this needs further changes?

Copy link
Contributor

@artemcm artemcm left a comment

Choose a reason for hiding this comment

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

The change overall LGTM. Maybe it would be interesting for @etcwilde to take a look.

@hyp hyp merged commit 270bf6c into swiftlang:main Jul 12, 2024
3 checks passed
@etcwilde
Copy link
Contributor

At a high-level, I think that this is the right direction. swiftrt.o is tied to the runtime. If it gets mismatched with the runtime, programs will explode. If the compiler generates extra metadata segments that the runtime doesn't know about, then they'll just be dead weight and won't get loaded and it should mostly be fine because the runtime won't try to use them. (We do need an availability story there though, but that's not about swiftrt.o). This does mean that the compiler needs to be at least as old as the runtime that it's building for though. (Technically, without any ABI stability story, you can't mix-and-match versions of the compiler and SDK though... And the swiftmodules in the SDK won't work with a mismatched compiler anyway? So maybe that's fine???)

But I would also like to ask for something of a vision document listing out what each of the files in the current Linux toolchain/SDK are tied to so that when they move, it doesn't come as a surprise and there is something we can discuss and point to instead of a smattering of compiler changes. When it comes down to it, the toolchain files should be pretty easy to move. Move the file and update the compiler at the same time, and since they're tied to that specific compiler, if anyone complains about a missing file, it means they were living life on the edge and were getting very lucky regarding ABI. SDK content is maybe a bit weirder, but given that, for now anyway, the Linux SDKs are sort of tied to a specific compiler build through ABI instability and rev-locked swiftmodule files, maybe it's okay?

Apple platforms and Windows both need to support the split builds due to how the SDKs and toolchains are split in Xcode and how libraries work on Windows, which is why they both look remarkably similar in terms of the layout. swiftrt.o(bj) is only relevant to Windows because the dynamic loader on Darwin knows how to unpack the runtime metadata from binaries automatically so it isn't necessary. Linux is the odd one where you can build against the system you're running on, and unfortunately that allowed for a disorganized Linux build. As you noted, @finagolfin, the Linux installs have the compiler running on a different Swift runtime than the one it was built against. We've gotten very lucky that things have played out as well as they have. Untangling it will require moving files to the appropriate locations though.

@finagolfin
Copy link
Contributor

Honestly, the swiftrt.o change in this pull is superfluous and unnecessary if swiftlang/swift#72409 is applied. Rather, this helps to change where the runtime libraries are placed, ie in arch-dependent directories, and change the meaning of -resource-dir just for this one SDK.

See the discussion on swiftlang/swift#72409 for more info on what they're doing.

@compnerd compnerd deleted the android branch July 12, 2024 15:28
@artemcm
Copy link
Contributor

artemcm commented Jul 12, 2024

I suspect this is causing macOS PR testing failures, not clear yet how.
https://ci.swift.org/job/swift-PR-macos-smoke-test/14409/

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.

5 participants