Repository: rust
Issue: Failed to link against LLVM libunwind when running library/std tests with `llvm-libunwind = 'in-tree'`
Labels: A-linkage,T-bootstrap,C-bug,requires-custom-config

<!--
Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
along with any information you feel relevant to replicating the bug.
-->

I am working on adding support for user-space programs written in Rust for our internally developed microkernel operating system. Our OS is compatible with musl libc. After reviewing some code in the `library/` directory, I noticed that on Unix-like platforms, Rust interacts with the underlying operating system through the `libc` crate. This includes operations like heap access, thread creation, syscall invocation, etc. In theory, Rust programs compiled with the `x86_64-unknown-linux-musl` target should be executable directly on our OS.

However, since our OS doesn't currently support runtime compilation of applications, we compile the applications on a host machine and then run them on our OS. This implies we need Rust applications to be dynamically linked against musl libc, rather than the default static linking provided by the `x86_64-unknown-linux-musl` target. Therefore, we need to add `-C target-feature=-crt-static` during application compilation. Additionally, since our host uses the `x86_64-unknown-linux-gnu` target, we also need to install musl libc on the host.

Furthermore, for some reasons, I want `library/unwind` to be statically linked to LLVM libunwind instead of linking to `libgcc_s.so` when using `-C target-feature=-crt-static`. Based on the code in [library/unwind/lib.rs](https://github.com/rust-lang/rust/blob/fe3eae3f310b2f709aa5b39d76a94fc1ea843854/library/unwind/src/lib.rs#L40-L56C2), I need to enable the `llvm-libunwind` feature for this crate. 

Given this, here's the config.toml I used while compiling rustc:

```toml
# Includes one of the default files in src/bootstrap/defaults
profile = "compiler"
changelog-seen = 2

[build]
target = ["x86_64-unknown-linux-gnu", "x86_64-unknown-linux-musl"]

[rust]
llvm-libunwind = 'in-tree'
musl-root = '/usr/local/musl'
debug = true
```

I used the following command to compile the `library/std` unit tests, aiming to obtain dynamically linked tests against musl libc for running on our OS:

```bash
RUSTFLAGS_NOT_BOOTSTRAP="-C target-feature=-crt-static" RUSTFLAGS_BOOTSTRAP="-C target-feature=-crt-static" ./x test --stage 1 -v library/std
```

Unfortunately, the command failed to compile the tests correctly and instead produced a linker error. Upon inspecting the provided linker invocation(see [pastebin](https://pastebin.com/v9LVa7sr)), it seems the issue arises from unresolved libunwind symbols due to the linker does not link against either `libunwind.a` or `libgcc_s.so`. 

Reviewing the code in `library/unwind/lib.rs`, the logic for `linux-gnu` targets is as [follows](https://github.com/rust-lang/rust/blob/fe3eae3f310b2f709aa5b39d76a94fc1ea843854/library/unwind/src/lib.rs#L97-L113):

```rust
#[cfg(all(
    target_os = "linux",
    any(target_env = "gnu", target_env = "uclibc"),
    not(feature = "llvm-libunwind"),
    not(feature = "system-llvm-libunwind")
))]
#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
extern "C" {}

#[cfg(all(
    target_os = "linux",
    any(target_env = "gnu", target_env = "uclibc"),
    not(feature = "llvm-libunwind"),
    feature = "system-llvm-libunwind"
))]
#[link(name = "unwind", cfg(not(target_feature = "crt-static")))]
extern "C" {}
```

This logic does not consider the situation when the `llvm-libunwind` feature is enabled (only handling `system-llvm-libunwind`), causing an issue with the config.toml setting `llvm-libunwind` to `in-tree`. With this configuration, the `x86_64-unknown-linux-gnu` target doesn't match any of the `#[cfg]` conditions, resulting in the compiled `library/unwind` crate not specifying the linkage requirements for the native unwinder library.

The full output log can be found [here](https://drive.google.com/file/d/1d44iMllhcpPKny6QjKRmOkMcGk_IfkAj/view?usp=sharing).

The analysis above is based on my understanding of Rust bootstrap process and `library/unwind`, there may be some mistakes. Besides, there is an anomaly I can't explain: when I compile only rustc (without tests) using the mentioned `config.toml`, the compilation succeeds. Furthermore, I can use the resulting rustc to compile Rust applications that dynamically link against musl libc.

For easier reproduction and investigation, I've created a Docker environment that stably reproduces this issue. If anyone is interested in looking into this problem, you can find the repository [here](https://github.com/fourstring/rust-issue-docker).

My questions are:

* Why doesn't the `library/unwind` handle the `llvm-libunwind` feature for `linux-gnu` targets? Is this a bug, or is this the intended behavior?
* Why is this problem absent when compiling only rustc? The logic in `library/unwind/lib.rs` for `linux-gnu` targets seems to be unrelated to whether `library/std` unit tests are compiled.
* Is my way correct to run `library/std` tests?