-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Add support to llvm and cmark to cross-compile using an external sysroot #78991
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
Add support to llvm and cmark to cross-compile using an external sysroot #78991
Conversation
- This allows specifying an external sysroot to use to compile Swift against
- gold does not always know where to find libraries in different sysroots depending on the version of GCC and so forth
@swift-ci build toolchain |
@swift-ci test |
Hmm, what does that Windows error mean? I still do not understand these failures yet... |
I added this You may want to introduce a new cross-compile-sysroot flag instead, as the current build-script is limited in that regard and currently only looks in However, the build commands you list above make no sense: the flags |
So if you look at the ticket I filed, I stated there that my goal is be able to cross-compile Swift and all dependencies for a Linux architecture, such as armv7. I've also said this many times and in different ways, but I'll say it again. That currently doesn't work properly out of the box, so the goal here is to be able to do this. The way I envision it in the end is being able to have a buildbot like this:
And as long as you have the correct stuff, this should eventually generate an entire Swift toolchain with (hopefully) everything included, but there are a lot of things that do not build for armv7 or are not setup to cross compile properly. I am taking the approach of adding support for each component to cross compile properly to reduce the number of changes and ensure each piece does not break something else.
In this PR did
I added This will apparently build all of LLVM for the host (in my case, x86_64) and then it will build it for the target (armv7). However, with lld I see that it doesn't link properly when compiling for armv7 due to some symbols it cannot find. Here are the errors:
This does not happen with So as you see in the PR, I am using
Okay, I was not aware of this. So, you think a cross-compile-sysroot or sysroots flag would be more appropriate then? I can do this instead and maybe this could be helpful down the line too for stdlib, libdispatch, Foundation, etc which all need to know where the sysroot is at. I can go ahead and make these changes to leave cross-compile-deps-path to its original design, now that I understand what it was for. One thing I need you and anyone else to understand. I am spending time on this to reach the eventual goal of being able to easily cross-compile all of Swift so it can be possible to OFFICIALLY support other architectures than x86_64 and aarch64. The dream is being able to have toolchains you can download from swift.org for armv7, and Docker containers as well: |
First off, you never said this was your goal in the linked ticket. I went and read it again and don't see it. If you believe I'm wrong, please directly link to where you said it before. Second, that's not what I asked you, as building the toolchain and "all dependencies" is a long-term goal, which I don't care about. Instead, what I asked you was, what are the build products you are trying to build right now with the assorted
You're wrong about this, and I know this because I'm probably the only person in the world who has been cross-compiling and publicly releasing a fully 32-bit armv7 Swift toolchain for the last several years. I don't know how well it runs anymore, as my last Android arm7 device died in 2023, but it still builds. 😉 Now, of course linux armv7 is different and will require some changes, but it is probably not "a lot of things."
Sure, it is fine to selectively disable various build products when you get started. But that makes it particularly confusing for us, as we can't know which ones you intend to build first. That is why I keep asking you which build products you want to build first, and I even suggested a possible answer a couple days ago, "a native Swift compiler for the linux host and a cross-compiled stdlib for linux armv7?" I never got a response to that very specific question. Also, you just contradicted yourself: that flag disables building this swift repo completely, so "building swift will fail with other errors with this very command" can't happen.
I don't think it's because lld "finds dependencies... better," because lld is written as a dumb linker that requires clang to supply all dependency paths to it. More likely, gold is doing something else that interferes with the flags clang passes to it.
I can only give you ideas once I know what build products you are trying to build first. That lld issue with the indexstore symbols is known, but nobody has bothered to submit a proper fix yet.
Yes, that is a long-standing deficiency in this build-script that you could actually fix, rather than simply reusing this
That's fine, it's good to have such long-term goals. But you should still be able to answer questions about what your short-term aims are.
Yes, obviously that's why I'm asking you specific questions about what you're trying to build first. Therefore, there are only two ways to use it right:
My entire goal in asking you these questions is to help you with the easier route of 2., but if you don't answer them, I'm afraid you're stuck with the harder route of 1. |
@finagolfin well it's good we have you here then since you know how everything works. Let's work together instead of talking over each other! I started with using the And the next concern is the
To answer this question directly. All I am doing in this PR is getting past the initial errors that cmark and llvm give when they run the cmake configure step when I provide
Thanks for this. It will be useful in the future. |
@finagolfin Please can we tone this discussion down a bit? I appreciate you may be frustrated, but I think if you re-read what you've written above you will probably appreciate that it comes across, in places, as perhaps a bit less civil than we'd ideally like. I'm not going to comment on the PR itself right now as I don't have time, other than to thank @xtremekforever for looking at this and to note that @etcwilde and @edymtt's work on the build system is likely to make this a whole lot easier at some point in the (hopefully near) future. |
Thank you @al45tair . I am also looking forward to their changes, and when that is ready I would be happy to work with them to ensure that the new build system is able to cross compile! :) |
No, that is my point: it is not necessary in the beginning and not a good place to start.
Yes, you can either continue with this approach or add a whole new flag, either is fine. I just don't think you should submit pulls like this until you have reached some milestone, like successfully cross-compiling the stdlib for linux armv7. That's because once you reach that milestone, you will understand the code much better and can make a better decision on which approach to upstream back. If you start upstreaming pulls now, when you really don't have anything building yet, you will likely make mistakes that you will have to undo later.
This pull will have no effect on building Swift for Android, which doesn't use these CMake toolchain files yet. That's not what I'm worried about: I'm only worried about guiding you along to where you're trying to go, and making sure these pulls you submit are borne out of better knowledge of the code.
Yes, that new build-script flag would be useful when cross-compiling all the Swift repos.
Sure, but what you don't seem to understand is that you should have a goal of what initial smaller set of build products you want to cross-compile first and use the appropriate build-script command for that. Just slapping together various build-script commands with a jumble of flags is not a good way to start off. That's why I pointed you at some existing build-script configurations a couple days ago, when I said "take a look at the standalone stdlib preset or the Android doc for the kind of flags that need to be passed in." One thing you should've noticed is that neither uses the My suggestion is that you only focus on cross-compiling the stdlib for linux armv7 first and building nothing else. For that, you will have to download the latest trunk snapshot tag of the toolchain and check out this Swift repo, LLVM, and libdispatch to that same tag (cmark not needed), then run a command like After you apply this pull we're commenting on, that should pull your linux sysroot into the generated toolchain file and start cross-compiling the stdlib for linux armv7... or fail in some other corner of build-script. But the point is that command actually has a chance of working in the next week or two, once you make further small tweaks to the source, as opposed to the commands you tried above.
What places did you have in mind as "a bit less civil," @al45tair? I wrote my earlier comments dripping in frustration, as I wasn't getting answers to my specific technical questions, but that was my intent, to express my frustration at the lack of answers. I don't think I was ever uncivil though, and I don't think it's less civil to simply disagree strongly. Anyway, if you look at this comment, which I wrote up to him before seeing your comment, and his last one, we may finally be getting somewhere. 🥲 |
@finagolfin Okay, so I think we're getting on the same page here!
So this is interesting, because on latest trunk I'm running the command (with the paths populated) and it ends in:
The reason I went down the --cross-compile-hosts flag road is because it actually influences what the stdlib compiles for. With the command above with just
This kind of indicates to me that it wants to build for the host and not the target? However if I provide the --cross-compilation-hosts flag, this will change and it'll print armv7 in there instead. This is probably the source of the confusion. But for your android profile, I also see that you are including
So the big question is this. How do we tell the stdlib to cross compile when we have |
OMG I just added Here is my full command:
So, the only thing missing is that we need it to actually honor the cross-compile-deps-path, or the new cross-compile-sysroot param if we add that instead. It's just defaulting to "/":
Would this be correct to use instead then? If this is the path to take instead of using cross-compile-hosts, then it means we don't need to mess with LLVM right now and can go straight to building the stdlib, and making sure it can get a custom sysroot instead of defaulting "/". What do you think @finagolfin @MaxDesiatov ? |
You're on your own at this point: 😄 I can only point you in the right direction with an appropriate build-script command and it is up to you now to discover the rest of the tweaks needed for your target. I think I may have seen and tried this That suggests to me that it shouldn't be necessary, that it is being set automatically internally for other stdlib targets, but for some reason not for this one. I suggest you pass that flag externally for now, but at some point track down where it's being set internally for other targets and try to set it internally in the same way for this target too.
Sounds good, did you not apply this pull we are commenting on when building yet? If you did, that means simply setting the sysroot in this CMake toolchain file is not enough, and you will have to also set it elsewhere internally. This is where the C/C++ sysroot is defined in the middle of this repo's CMake config. Try to track where that is being passed back from this Python build-script and pass in cross-compile-deps-path there instead, if needed. Don't hesitate to ask us any questions at any time, but some of this you will have to read the code and learn for yourself, as no one person likely knows all of a large, continually multi-authored build tool like |
Nope I didn't include this pull at all since it isn't needed without that What I've done before in the past is just passing some new param to that file and set the CMAKE_SYSROOT path, like this for example:
So I'm sure something like this can be done. Maybe a CROSS_COMPILE_SYSROOT definition paired with a |
Not quite, I suggested applying this pull above, as otherwise, It's fine to simply hard-code Anyway, run through the build with that hard-coded first, and see how it goes. |
Yep, I'm coming up with a solution here. I'm already playing with setting that All I'm struggling with is the name of the sysroot flag, because it could also be something like But, I'll send a new PR with this soon so we can have a look. The stuff in this PR is now defunct and I plan to revisit it again in the future when we actually want to build LLVM with this external sysroot. |
Maybe something completely generic like |
So I thought about it some more @finagolfin and I settled back on Let me know if you think otherwise. But it makes sense to me and seems pretty easy to understand. There are also sections that are now enabled when CROSS_COMPILE_SYSROOT/cross_compile_sysroot are set, so existing use cases should not be affected. PR coming soon!
|
This goes towards #78960...
When cross-compiling, we typically do not want to build all of LLVM so we just add
--build-llvm=0
to the build script parameters. However, the cmake configuration stage for llvm still needs to be able to verify that it "can" cross-compile to the target arch, so that is what this PR does. This also applies to cmark if it is enabled.Changes
cross_compile_deps_path
fromget_linux_sysroot
if it is set to allow using an external sysroot.lld
when cross compiling to a Linux architecture, sincelld
is better at finding cross-libraries in a variety of sysroots.linux-<arch>
in the build scripts, includinglinux-x86_64
orlinux-aarch64
, which could be a useful tool when running on the opposite platform.Testing Locally
To test this, I created a swift:jammy docker container like this:
docker run -it --name swift-armv7-builder -v $(pwd):/src swift:jammy /bin/bash
Then, I installed the needed/missing packages:
apt update && apt install cmake ninja-build libsqlite3-dev ncurses-dev git python3 libstdc++-11-dev-armhf-cross
Then, to just test that llvm and cmark configure correctly without building anything else, I ran the following command from the workspace inside the container:
./swift/utils/build-script --cross-compile-hosts=linux-armv7 --cross-compile-deps-path=/ --build-llvm=0 --skip-local-build --skip-build-swift
This finds dependencies for armhf in the root "/", which were installed with the libstdc++-11-dev-armhf-cross package. However, an external sysroot can also be supplied:
./swift/utils/build-script --cross-compile-hosts=linux-armv7 --cross-compile-deps-path=/path/to/arch-sysroot--build-llvm=0 --skip-local-build --skip-build-swift
macOS Compatibility
This also can be run on macOS as long as
lld
is installed (brew install lld
) and you have an external sysroot. Using a sysroot from https://github.com/xtremekforever/swift-armv7/releases/tag/6.0.3, I was able to run the following command:./swift/utils/build-script --cross-compile-hosts=linux-armv7 --cross-compile-deps-path=sysroot-debian-bookworm --build-llvm=0 --skip-local-build --skip-build-swift
Conclusions
This is only step 1 of adding support to the Swift build scripts for cross-compiling to Linux architectures. Next will be the Swift stdlib along with libdispatch, which is required for Swift Concurrency.
@MaxDesiatov @finagolfin