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

bootstrap: LLVM build disregards LDFLAGS #93880

Closed
jonhoo opened this issue Feb 10, 2022 · 4 comments · Fixed by #93918
Closed

bootstrap: LLVM build disregards LDFLAGS #93880

jonhoo opened this issue Feb 10, 2022 · 4 comments · Fixed by #93918
Labels
C-bug Category: This is a bug. T-bootstrap Relevant to the bootstrap subteam: Rust's build system (x.py and src/bootstrap) T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@jonhoo
Copy link
Contributor

jonhoo commented Feb 10, 2022

When the bootstrap code builds LLVM, it sometimes sets the CMake variable CMAKE_EXE_LINKER_FLAGS. For example, when instructed to also build the LLVM tools:

if builder.config.llvm_tools_enabled {
if !target.contains("msvc") {
if target.contains("apple") {
cfg.define("CMAKE_EXE_LINKER_FLAGS", "-static-libstdc++");
} else {
cfg.define("CMAKE_EXE_LINKER_FLAGS", "-Wl,-Bsymbolic -static-libstdc++");
}
}
}

When CMAKE_EXE_LINKER_FLAGS is unset, CMake initializes it to LDFLAGS, but it does not consider LDFLAGS if CMAKE_EXE_LINKER_FLAGS is set. This means that Rust's LLVM bootstrap will sometimes respect (potentially required) LDFLAGS and sometimes not depending on a number of unexpected factors, such as whether llvm tools are also being built, whether we're building for a non-FreeBSD RISC-V target, or if we're building for powerpc-unknown-freebsd. This, in turn, makes it difficult to bootstrap Rust in situations where additional linker flags are required, such as if dependencies are not stored in standard system-wide location such as /usr/lib.

I propose that anywhere we set CMAKE_EXE_LINKER_FLAGS, we append LDFLAGS from the environment to the value to retain parity with the behavior when the configuration isn't set.

@jonhoo jonhoo added the C-bug Category: This is a bug. label Feb 10, 2022
@pnkfelix pnkfelix added T-bootstrap Relevant to the bootstrap subteam: Rust's build system (x.py and src/bootstrap) T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Feb 10, 2022
@Mark-Simulacrum
Copy link
Member

That makes sense to me, would be happy to accept a PR. It may also make sense to ask/file a similar bug against llvm recommending the logic to append always happen, since it seems like better behavior to me.

@jonhoo
Copy link
Contributor Author

jonhoo commented Feb 11, 2022

I don't think this is really a bug in llvm; this is a standard CMAKE flag, and the observed behavior is expected behavior; changing it would be a breaking change to cmake sadly.

I'd be happy to push a PR, though looking through the code raised a few other questions for me:


First, when llvm.ldflags is set, the current implementation sets the CMAKE_*_LINKER_FLAGS variables unilaterally

if let Some(ref s) = builder.config.llvm_ldflags {
cfg.define("CMAKE_SHARED_LINKER_FLAGS", s);
cfg.define("CMAKE_MODULE_LINKER_FLAGS", s);
cfg.define("CMAKE_EXE_LINKER_FLAGS", s);
}

And since configure_cmake is run after all the logic that sets the linker flags based on other parts of the config, here:

configure_cmake(builder, target, &mut cfg, true);

It means that llvm.ldflags is currently an override, not an append. Do we want to keep that behavior, meaning that if llvm.ldflags is set in config.toml, LDFLAGS will not be appended? Should we document that llvm.ldflags overrides any ldflags the bootstrap may want to set? Or should we change it to be appending the way llvm.cflags and llvm.cppflags are?


Second, the current bootstrap logic sets CMAKE_EXE_LINKER_FLAGS multiple times:

cfg.define("CMAKE_EXE_LINKER_FLAGS", "-Wl,-Bsymbolic -static-libstdc++");

cfg.define("CMAKE_EXE_LINKER_FLAGS", "-latomic -static-libstdc++");

cfg.define("CMAKE_EXE_LINKER_FLAGS", "-fuse-ld=bfd");

Most of those are mutually exclusive, but when they're not, the later setting takes precedence. Is this intentional, or should the logic be fixed so that ldflags is added to, and then set in a single place at the end?

Anecdotally, we handle CFLAGS by appending:

if builder.config.llvm_clang_cl.is_some() {
cflags.push_str(&format!(" --target={}", target))
}
cfg.define("CMAKE_C_FLAGS", cflags);

and same with CXXFLAGS:
if let Some(ref s) = builder.config.llvm_cxxflags {
cxxflags.push_str(&format!(" {}", s));
}
if builder.config.llvm_clang_cl.is_some() {
cxxflags.push_str(&format!(" --target={}", target))
}
cfg.define("CMAKE_CXX_FLAGS", cxxflags);


Third, it turns out we have a similar problem with CFLAGS and CXXFLAGS, except those we always override, so CFLAGS and CXXFLAGS from the environment is never respected. Should that be fixed too?

@Mark-Simulacrum
Copy link
Member

I'm pretty sure that most of this behavior is unintentional and can largely be explained by incremental changes without really looking above/below in the file to make sure things aren't being set twice etc. I'm not particularly worried about breaking changes in bootstrap (e.g., if we start respecting LDFLAGS or CXXFLAGS etc), particularly when we're moving to what seems like relatively cleaner model.

In general happy to see a PR that goes through and cleans the logic up.

@jonhoo
Copy link
Contributor Author

jonhoo commented Feb 11, 2022

PR: #93918

bors added a commit to rust-lang-ci/rust that referenced this issue Feb 15, 2022
…ark-Simulacrum

bootstrap: tidy up flag handling for llvm build

This tidies up the logic in `src/bootstrap/native.rs` such that:

 - `CMAKE_*_LINKER_FLAGS` is not overridden if we add to it twice.
 - `CMAKE_*_FLAGS` also include the standard `*FLAGS` environment
   variables, which CMake respects when we _don't_ set `CMAKE_*_FLAGS`.
 - `llvm.ldflags` from `config.toml` appends to the ldflags Rust's
   bootstrap logic adds, rather than replacing them.

It also takes a second stab at rust-lang#89983 by moving `-static-libstdc++` to just be passed as a linker flag, since that's what it is.

Fixes rust-lang#93880. Fixes rust-lang#70468. Closes rust-lang#89983.
@bors bors closed this as completed in 07dae5a Feb 15, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug. T-bootstrap Relevant to the bootstrap subteam: Rust's build system (x.py and src/bootstrap) T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants