Skip to content

Simplify LLVM bitcode linker in bootstrap #142357

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: master
Choose a base branch
from

Conversation

Kobzol
Copy link
Contributor

@Kobzol Kobzol commented Jun 11, 2025

We have several linker tools in bootstrap that act as "host tools", i.e. they will be executed by rustc on the host machine where it runs. Funnily, we use three different modes for compiling them:

  • ToolRustc (LlvmBitcodeLinker)
  • ToolStd (LldWrapper)
  • ToolBootstrap (WasmComponentLd)

Clearly, the existing bootstrap modes can't accurately describe how should these tools be built (more on this here). This also means that right now, when we do a stage 2 build, this tool is unnecessarily built twice, wasting CI time.

This PR tries to simplify the whole setup for LlvmBitcodeLinker. Notably, I removed the side effect of modifying the toolchain of a compiler from the LLVM bitcode linker step (I don't like these side effects and I think that we should localize them to the fewest possible amount of places in bootstrap - this will take a lot of work), and changed it so that it is built only once per target.

The tool is now also copied only into the rustlib/<target>/bin/self-contained directory, before it was also copied to rustlib/<target>/bin. However, I tested with rustc +stage1 src/main.rs -Zunstable-options -Clinker-flavor=llbc --target nvptx64-nvidia-cuda that rustc can get the binary from both places just fine, regardless of the value of -Clink-self-contained=[+-]linker. And the dist component of this tool only puts the binary into the self-contained directory, so it clearly works for people using the tool through rustup.

As a follow-up, I want to simplify LldWrapper and WasmComponentLd in a similar ways, and then introduce the new "host tool" mode for them.

r? @jieyouxu

Kobzol added 4 commits June 11, 2025 08:50
That step should be responsible for building the tool, not performing side-effects. Also, only copy the tool to the `self-contained` directory, not to the `rustlib/<target>/bin` directory.
This tool can be built with any compiler that can produce code for the host target of the compiler for which the linker should be installed. This change saves one rebuild of the tool in stage 2 build.
@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-bootstrap Relevant to the bootstrap subteam: Rust's build system (x.py and src/bootstrap) labels Jun 11, 2025
Copy link
Member

@jieyouxu jieyouxu left a comment

Choose a reason for hiding this comment

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

Thanks, some questions/feedback, but looks good overall

Comment on lines 2037 to 2039
let bindir_self_contained = builder
.sysroot(compiler)
.join(format!("lib/rustlib/{}/bin/self-contained", compiler.host));
Copy link
Member

Choose a reason for hiding this comment

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

Suggestion (follow-up, not for this PR): maybe pull out a method to do the "path to sysroot target self-contained" logic.

Copy link
Contributor Author

@Kobzol Kobzol Jun 11, 2025

Choose a reason for hiding this comment

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

I actually had a commit for that, but it's super tricky (lol). Because:

  • There are like 5 places in bootstrap that access the self-contained directory. Some of them need a relative path, some of them absolute, some of them work with a compiler, some don't, it's a mess.
  • The functions that we have in Builder for getting similar paths (invoked through the Libdir step) actually delete the directory before returning it to you 🤦 I tried to use it here and it broke everything 😂 I need to clean all of this up eventually, and move the directory clearing to a single step, so that you can get a path to something without bootstrap falling over, lol.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, this is uhhh tricky. I'll open a issue about this follow-up (and that it's tricky).

Copy link
Member

@jieyouxu jieyouxu Jun 11, 2025

Choose a reason for hiding this comment

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

#142361, not in scope for this PR (keeping this unresolved to make it easier to find).

Comment on lines +1318 to +1319
/// Return the lowest stage compiler that can compile code for the given `target`.
pub fn compiler_for_target(&self, target: TargetSelection) -> Compiler {
Copy link
Member

Choose a reason for hiding this comment

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

Discussion: maybe tool_compiler_for_target? I ask because this should also say something like "it must not be used to build stuff that depends on staged rustc/std", right?

Copy link
Contributor Author

@Kobzol Kobzol Jun 11, 2025

Choose a reason for hiding this comment

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

I don't think there's any requirement like this. It's really just "give me a compiler that can build code for target T". If stage0 could cross-compile for any target, we could use it for this always.

We actually have a bunch of situations like this in bootstrap already, but it was always done sort of implicitly. Here I wanted to make it explicit.

In other words, I think that this could be useful also for other things than just tools. But right now it's only for a single tool, ofc, so happy to rename if you want.

Copy link
Member

@jieyouxu jieyouxu Jun 11, 2025

Choose a reason for hiding this comment

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

Hm right. The reason I asked is that

this could be useful also for other things than just tools

is probably true, just that the "other things" must not use this method if they do "depend on staged compiler/std" (be it through rustc_private or directly or somehow).

For now, I think it's safer to name this as sth like tool_compiler_for_target to make it clear that you should not use it for sth beyond its purpose (because we also have Builder::{compiler,compiler_for}), and then consider its naming if we do use it for not-just-tools, but it's not really a blocking concern.

Comment on lines +1238 to +1241
/// Check that during a non-cross-compiling stage 2 build, we only compile rustc host tools
/// (such as llvm-bitcode-linker) only once.
#[test]
fn llvm_bitcode_linker_compile_once() {
Copy link
Member

Choose a reason for hiding this comment

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

Question: should we have another test that does check the cross-compiling case, that we do build a stage 1 (rustc, std) pair that can produce artifacts for target, and that llvm-bitcode-linker is produced by that pair for the target?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, happy to add it. Although from my local experiments, I'm almost sure that bootstrap is actually broken for these situations somehow. Like, ./x build --host i686-unknown-linux-gnu, which is like the simplest cross-compilation scenario on x64 Linux, fails for me on master.

Copy link
Member

Choose a reason for hiding this comment

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

And you would be right 🎡

@jieyouxu
Copy link
Member

@rustbot author

@rustbot rustbot removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jun 11, 2025
@rustbot
Copy link
Collaborator

rustbot commented Jun 11, 2025

Reminder, once the PR becomes ready for a review, use @rustbot ready.

@rustbot rustbot added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Jun 11, 2025
@rust-log-analyzer
Copy link
Collaborator

The job aarch64-gnu-llvm-19-2 failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)

failures:

---- core::builder::tests::dist::dist_all_cross stdout ----
cargo:warning=Compiler family detection failed due to error: ToolNotFound: failed to find tool "i486--netbsdelf-gcc": No such file or directory (os error 2)
cargo:warning=Compiler family detection failed due to error: ToolNotFound: failed to find tool "i486--netbsdelf-gcc": No such file or directory (os error 2)
cargo:warning=Compiler family detection failed due to error: ToolNotFound: failed to find tool "i486--netbsdelf-g++": No such file or directory (os error 2)
cargo:warning=Compiler family detection failed due to error: ToolNotFound: failed to find tool "i486--netbsdelf-g++": No such file or directory (os error 2)
cargo:warning=Compiler family detection failed due to error: ToolNotFound: failed to find tool "i486--netbsdelf-g++": No such file or directory (os error 2)
cargo:warning=Compiler family detection failed due to error: ToolNotFound: failed to find tool "i486--netbsdelf-g++": No such file or directory (os error 2)
Generating unstable book md files (i686-unknown-netbsd)
##[group]Building stage0 tool unstable-book-gen (i686-unknown-haiku)
##[endgroup]
##[group]Building stage0 tool rustbook (i686-unknown-haiku)
##[endgroup]
---

note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

---- core::builder::tests::dist::dist_only_cross_host stdout ----
/checkout/obj/build/bootstrap/aarch64-unknown-linux-gnu/debug/build/bootstrap-b5a02347f6e3af12/out/tmp-rustbuild-tests/core--builder--tests--dist--dist_only_cross_host/i686-unknown-hurd-gnu/llvm/bin/llvm-cov does not exist; skipping copy
/checkout/obj/build/bootstrap/aarch64-unknown-linux-gnu/debug/build/bootstrap-b5a02347f6e3af12/out/tmp-rustbuild-tests/core--builder--tests--dist--dist_only_cross_host/i686-unknown-hurd-gnu/llvm/bin/llvm-nm does not exist; skipping copy
/checkout/obj/build/bootstrap/aarch64-unknown-linux-gnu/debug/build/bootstrap-b5a02347f6e3af12/out/tmp-rustbuild-tests/core--builder--tests--dist--dist_only_cross_host/i686-unknown-hurd-gnu/llvm/bin/llvm-objcopy does not exist; skipping copy
/checkout/obj/build/bootstrap/aarch64-unknown-linux-gnu/debug/build/bootstrap-b5a02347f6e3af12/out/tmp-rustbuild-tests/core--builder--tests--dist--dist_only_cross_host/i686-unknown-hurd-gnu/llvm/bin/llvm-objdump does not exist; skipping copy
/checkout/obj/build/bootstrap/aarch64-unknown-linux-gnu/debug/build/bootstrap-b5a02347f6e3af12/out/tmp-rustbuild-tests/core--builder--tests--dist--dist_only_cross_host/i686-unknown-hurd-gnu/llvm/bin/llvm-profdata does not exist; skipping copy
/checkout/obj/build/bootstrap/aarch64-unknown-linux-gnu/debug/build/bootstrap-b5a02347f6e3af12/out/tmp-rustbuild-tests/core--builder--tests--dist--dist_only_cross_host/i686-unknown-hurd-gnu/llvm/bin/llvm-readobj does not exist; skipping copy
/checkout/obj/build/bootstrap/aarch64-unknown-linux-gnu/debug/build/bootstrap-b5a02347f6e3af12/out/tmp-rustbuild-tests/core--builder--tests--dist--dist_only_cross_host/i686-unknown-hurd-gnu/llvm/bin/llvm-size does not exist; skipping copy
/checkout/obj/build/bootstrap/aarch64-unknown-linux-gnu/debug/build/bootstrap-b5a02347f6e3af12/out/tmp-rustbuild-tests/core--builder--tests--dist--dist_only_cross_host/i686-unknown-hurd-gnu/llvm/bin/llvm-strip does not exist; skipping copy
/checkout/obj/build/bootstrap/aarch64-unknown-linux-gnu/debug/build/bootstrap-b5a02347f6e3af12/out/tmp-rustbuild-tests/core--builder--tests--dist--dist_only_cross_host/i686-unknown-hurd-gnu/llvm/bin/llvm-ar does not exist; skipping copy
/checkout/obj/build/bootstrap/aarch64-unknown-linux-gnu/debug/build/bootstrap-b5a02347f6e3af12/out/tmp-rustbuild-tests/core--builder--tests--dist--dist_only_cross_host/i686-unknown-hurd-gnu/llvm/bin/llvm-as does not exist; skipping copy
/checkout/obj/build/bootstrap/aarch64-unknown-linux-gnu/debug/build/bootstrap-b5a02347f6e3af12/out/tmp-rustbuild-tests/core--builder--tests--dist--dist_only_cross_host/i686-unknown-hurd-gnu/llvm/bin/llvm-dis does not exist; skipping copy
/checkout/obj/build/bootstrap/aarch64-unknown-linux-gnu/debug/build/bootstrap-b5a02347f6e3af12/out/tmp-rustbuild-tests/core--builder--tests--dist--dist_only_cross_host/i686-unknown-hurd-gnu/llvm/bin/llvm-link does not exist; skipping copy
/checkout/obj/build/bootstrap/aarch64-unknown-linux-gnu/debug/build/bootstrap-b5a02347f6e3af12/out/tmp-rustbuild-tests/core--builder--tests--dist--dist_only_cross_host/i686-unknown-hurd-gnu/llvm/bin/llc does not exist; skipping copy
/checkout/obj/build/bootstrap/aarch64-unknown-linux-gnu/debug/build/bootstrap-b5a02347f6e3af12/out/tmp-rustbuild-tests/core--builder--tests--dist--dist_only_cross_host/i686-unknown-hurd-gnu/llvm/bin/opt does not exist; skipping copy

thread 'core::builder::tests::dist::dist_only_cross_host' panicked at src/bootstrap/src/core/builder/tests.rs:560:9:
assertion failed: `(left == right)`

Diff < left / right > :

@bors
Copy link
Collaborator

bors commented Jun 12, 2025

☔ The latest upstream changes (presumably #142392) made this pull request unmergeable. Please resolve the merge conflicts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-bootstrap Relevant to the bootstrap subteam: Rust's build system (x.py and src/bootstrap)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants