8000 Add basic support for building Rust by ojeda · Pull Request #299 · ClangBuiltLinux/tc-build · GitHub
[go: up one dir, main page]

Skip to content

Add basic support for building Rust #299

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

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open

Conversation

ojeda
Copy link
Member
@ojeda ojeda commented Apr 13, 2025

There a lot of options missing and it does not do any fancy kind of build. But it is a start, and it is already useful, e.g. Peter could have used it to test the new KCFI arity flag that requires LLVM 21 but upstream Rust still uses LLVM 20. It could also be useful to potentially/eventually have LLVM+Rust builds in kernel.org that use the exact same LLVM build.

I took the approach that the new script only takes care of building Rust provided an existing LLVM, which seemed simple and clear.

Thus add the basic infrastructure, plus a bit of documentation. Add it to the CI, too.

I successfully built it in a clean Debian 12 and Fedora 41.

A few notes:

  • The script works on its own, but the CI does not pass because llvm-config --bindir does not work with the set of flags used in CI for LLVM -- we are missing at least llvm-config in the distribution components of the LLVM step, but then also headers like llvm/Config/llvm-config.h.

    I am not sure how far you would want to modify the LLVM side or the do_llvm() step, so I decided to send this with the failing CI so that you see it.

  • If LLVM_INSTALL_UTILS is enabled (to get FileCheck installed, which is used by the Rust build system for testing), then we can leave codegen-tests to its default (enabled) in the Rust configuration.

    But perhaps we want to leave those tests anyway as the equivalent of the check-*s in LLVM, i.e. disabled by default even if the Rust configuration enables them by default, and let the user enable them.

  • Rust uses submodules and so on and manages them on its own if allowed, so I just did that. I didn't add/test shallow clones, so I didn't add them.

  • This does nothing about the LLVM patches that Rust may carry (until they get upstreamed). One could use --rust-folder to point to a checkout of the branch that Rust uses, and perhaps we should add some documentation about it, or even provide an option in ./build-llvm.py to build such a branch, but I didn't try/test anything related to that yet.

  • We probably want to offer eventually --quiet-x, --no-locked-deps, --tools, --codegen-tests, --docs, etc.

  • After this, we could add a --build-bindgen here or perhaps a new ./build-bindgen.py, so that we can easily get a full toolchain for the kernel. It is really just a one liner once one has the Rust toolchain, so it is not too important.

  • Some refactoring could be done so that both ./build-llvm.py and ./build-rust.py reuse certain bits, e.g. show_install_info().

I tried to follow the LLVM script as closely as possible and "copy" the style etc., but there may be mistakes -- please feel free to take this and modify it as you see fit, of course.

I hope this helps!

Cc: Peter Zijlstra (by email)

Copy link
Member
@nathanchance nathanchance left a comment

Choose a reason for hiding this comment

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

I will review this more in depth either later this week or early next week but one initial comment from a brief read.

Copy link
Member
@nathanchance nathanchance left a comment

Choose a reason for hiding this comment

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

I took this for a spin today and I think this is pretty good shape for a v1 but I will try to do an actual hard review over the next couple of days if I am able to.

I did work on my idea I suggested earlier and pushed that just to see if it worked and looked cleaner and I think it does: https://github.com/nathanchance/tc-build/commits/rust-review

@ojeda
Copy link
Member Author
ojeda commented Apr 23, 2025

I took this for a spin today and I think this is pretty good shape for a v1 but I will try to do an actual hard review over the next couple of days if I am able to.

I did work on my idea I suggested earlier and pushed that just to see if it worked and looked cleaner and I think it does: https://github.com/nathanchance/tc-build/commits/rust-review

Thanks! I agree it looks better (sorry, I should have replied above). Should I put your commit in this PR and apply the fixup?

Copy link
Member
@nathanchance nathanchance left a comment

Choose a reason for hiding this comment

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

Thanks! I agree it looks better (sorry, I should have replied above). Should I put your commit in this PR and apply the fixup?

No worries! Yes, I think that would be good.

I am not sure how far you would want to modify the LLVM side or the do_llvm() step, so I decided to send this with the failing CI so that you see it.

We should probably fix the CI configuration since it is custom tailored but should we also put an informative message in build-rust.py if these files cannot be found in the provided LLVM install folder?

Couple more minor comments but I think I am pretty happy with this, at least as an initial revision. If you felt like any of the “nice to have”s in the initial PR message were worth following up on in the future, feel free to open issues here for tracking.

nathanchance and others added 4 commits May 3, 2025 17:17
We will be adding Rust support in the future, so pull out common git
repository management code from LLVMSourceManager that can be shared
with a RustSourceManager.

Signed-off-by: Nathan Chancellor <nathan@kernel.org>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
There a lot of options missing and it does not do any fancy kind of
build. But it is a start, and it is already useful, e.g. Peter could
have used it to test the new KCFI arity flag that requires LLVM 21 but
upstream Rust still uses LLVM 20.

I took the approach that the new script only takes care of building Rust
provided an existing LLVM, which seemed simple and clear.

Thus add the basic infrastructure, plus a bit of documentation. Add it
to the CI, too.

I successfully built it in a clean Debian 12 and Fedora 41.

Cc: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
@ojeda
Copy link
Member Author
ojeda commented May 7, 2025

v2:

The biggest change is that instead of writing a bootstrap.toml manually, I used their configure script instead:

  • It uses the dist profile, which is geared towards users and distributions that do not plan to do development, and seems the right thing to do to benefit from any new defaults there anyway.

  • It figures out the target.<target>s for us for the llvm-config setting, so that is simpler. I checked that, indeed, in an emulated arm64 host, it fills it with the expected one (note: I just configured to see that, I did not run the build, so proper testing of that is of course very welcome!).

  • It writes a boostrap.toml that includes a copy of the documentation for each tweaked value, which is nice.

  • The script fills configure-args too, which is also nice.

The dist profile already enables extended and disables download-ci-llvm, so I removed those for simplicity (we could also explicitly keep them to ensure that does not change).

Moreover, I reviewed the rest of the dist profile and it sets a few other bits differently -- I leave some notes here before I forget about them:

  • They enable llvm-bitcode-linker and lld, which are disabled by default in the main configuration file. They do not give a good reason, though. lld is not used if one provides a llvm-config (and one gets a warning); and apparently llvm-bitcode-linker is so far only used for running nvptx tests (I guess they enabled it to be able to run all tests).

  • They set compression-profile to balanced, while previously it would have been the default from the main configuration file, i.e. fast. There is also best. We don't do tarballs so far anyway.

  • They disable download-rustc, but that is already the default in the main configuration file anyway, which is why I was not setting it. (Not sure why they do it explicitly, though.)

  • They set channel to auto-detect explicitly, so that it is not dev. This, in turn, means optimized-compiler-builtins should be set to true already, which is what I was doing manually, so I removed it. It will also mean omit-git-hash is false now, which seems OK (I didn't check what happens in the case of a tarball, though). They also say download-ci-llvm depends on the channel, but the main configuration file does not say so (anyway, they set that one to false explicitly).

  • They set *-stages to 2, i.e. the defaults, but that should not matter since we use the install target which its default was 2 already.

  • They disable the recently added compiletest-use-stage0-libtest, which sounds like the right thing to do.

  • They do not do anything with the change-id. I did not keep it in v2 (which can be done '--set', 'change-id=ignore') to keep it simpler and avoid having a --set option (it is just a few lines of output). In fact, I wonder if we should track it in tc-build like the "known good revision".

A few other notes:

  • I used their --llvm-root option, instead of --llvm-config, since the former adds the bin/llvm-config part.

  • I also changed a couple bits to do the configuration also inside the build folder (by the way, perhaps we should now factor out the install_folder), so now less changes should happen in the source folder (git clean -xdf now only reports a __pycache__ after a build).

  • In turn, that means we can manually skip setting the build-dir (which does not have a custom flag for it, i.e. we would need to use '--set', f'build.build-dir={self.folders.build}',). It does mean we introduce an extra folder (build), but that seems fine and in fact may be for the better (because it is the default and because it "separates" the install and build folders when they are the same).

Finally, I modified the LLVM side a bit to unbreak the CI. It turns out we will need some changes on the LLVM (please see the TODO commit):

  • To add a few distribution components (on top of the build tools ones and others already built by the CI options): llvm-config, llvm-headers and llvm-libraries.

    For the moment, I enabled them unconditionally, but we probably want to put them separately. Perhaps as a new flag, enabled by default, e.g. --library, intended to be used when LLVM will be used as a library by something else, like rustc. I also considered --rust/--for-rust or similar, but that probably requires figuring out the exact set of things to add (and changing the list into a set), i.e. in case someone does not enable the build tools.

  • To avoid using the thin archives (i.e. CMAKE_CXX_ARCHIVE_*). If we have the --library flag, that could disable them. For the moment, for testing, I commented it out.

Copy link
Member
@nathanchance nathanchance left a comment

Choose a reason for hiding this comment

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

I wanted to get this fully reviewed and flushed out today but I ran out of time so I am just posting what I have and coming back to it later because I should not have left you hanging for so long.

I was able to test this on AArch64 and it worked fine until I got an error due to an old copy of binutils in my path so I am rerunning it now.

I want to run some measurements on how much the default install size would change if we just enabled the things that --library would need and just did not give an option to turn it off.

'--release-description', self.vendor_string,
'--disable-docs',
'--enable-locked-deps',
'--tools', 'cargo,clippy,rustdoc,rustfmt,src',
Copy link
Member

Choose a reason for hiding this comment

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

If you think this list will ever grow or want to be customizable, consider using a separate list variable then ','.join(...).

@ojeda
Copy link
Member Author
ojeda commented Jun 2, 2025

No worries at all, I understand, and it is not easy to review and test this kind of PR.

Great to hear at least the arm64 is not completely broken.

Thanks for checking if we could do --library unconditionally too. That would be simpler for everyone (i.e. including users), but I assumed you probably wanted to keep the tarballs as small as possible.

@nathanchance
Copy link
Member

Great to hear at least the arm64 is not completely broken.

Better than not completely broken now :)

$ build/rust/final/bin/rustc -vV
rustc 1.89.0-nightly (449c80178 2025-06-02) (ClangBuiltLinux)
binary: rustc
commit-hash: 449c801783ecef2aad3ae03d6c9e4ac007de7d4b
commit-date: 2025-06-02
host: aarch64-unknown-linux-gnu
release: 1.89.0-nightly
LLVM version: 21.0.0

Thanks for checking if we could do --library unconditionally too. That would be simpler for everyone (i.e. including users), but I assumed you probably wanted to keep the tarballs as small as possible.

While I do use tc-build for the kernel.org toolchains, I use a custom --install-targets so a change to the default distribution list would not affect those tarballs. Doing the space measurements, I do not think I can justify doing the same for the kernel.org toolchains though, which I think is fine but I am open to discussion on it.

$ diskus default
465.24 MB (465,244,160 bytes)

$ diskus additional-files
983.01 MB (983,011,328 bytes)

I think that it would be reasonable to add those to the distributions list by default, as it only adds about 300 build targets in my testing and I would expect people using this to have a reasonable amount of space for build and install artifacts when the space requirements for the source is already rather large.

We could make it easier on people doing local builds if we could utilize thin archives in certain circumstances since my measurements show significant savings but I understand it might be tricky to safely do.

$ diskus additional-files-thin-archives
645.21 MB (645,214,208 bytes)

Additionally, we might be missing some things in the distribution list, as I get the following error when I run build-rust.py --llvm-install-folder against a folder that was generated using build-llvm.py --install-targets distribution.

thread 'main' panicked at src/bootstrap/src/lib.rs:1798:24:
src.symlink_metadata() failed with No such file or directory (os error 2) ("src = .../bin/llvm-cov")
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Panic was initiated from src/bootstrap/src/lib.rs:1798:24

This has probably not been noticed because we run just the install target by default, which will install everything, not just what was in the distribution. The distribution is only useful as a shortcut by default when just building the toolchain, not installing it for future use as well.

@ojeda
Copy link
Member Author
ojeda commented Jun 4, 2025

Better than not completely broken now :)

🎉

Doing the space measurements, I do not think I can justify doing the same for the kernel.org toolchains though, which I think is fine but I am open to discussion on it.

Yeah, doubling doesn't sound good. What about the LLVM+Rust toolchains? If we eventually start providing the combined ones with this, then I assume we can eventually drop the two tables and just provide one table (since it will be exactly matching), thus we would save some space there at least.

Additionally, we might be missing some things in the distribution list,

Good catch, thanks! I can take a look (it might take me some time).

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.

2 participants
0