commit:     7a20a50d0784ca4875f675371ef11140033e8d87
Author:     Z. Liu <zhixu.liu <AT> gmail <DOT> com>
AuthorDate: Fri Oct  3 12:13:23 2025 +0000
Commit:     Sam James <sam <AT> gentoo <DOT> org>
CommitDate: Sun Oct 26 01:02:48 2025 +0000
URL:        https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=7a20a50d

dev-lang/rust: fix bootstrap build under llvm profile

When bootstrapping Rust with the llvm profile (both glibc and musl),
the build fails at the mrustc stage due to two issues related to C++
standard library handling.

1. Compilation failure

When llvm-core/llvm is built with clang, 'llvm-config --cxxflags' includes
'-stdlib=libc++', but not when built with GCC. But under musl profile, GCC
has a known bug (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=122409) in
handling the '-stdlib=libc++' option. It fails to search '/usr/include/c++/v1',
causing standard headers such as <cstddef> to be missing unless the include 
path is
manually specified via '-I/usr/include/c++/v1'.

This patch fixes the issue by wrapping llvm-config calls and explicitly
appending libc++'s header path whenever '-stdlib=libc++' is detected.

Below is the relevant error log:

> Calling 
> /var/tmp/portage/dev-lang/rust-1.74.1-r101/work/bootstrap/mrustc-stage0/rustc-build/build_rustc_llvm_run
>  failed (see 
> /var/tmp/portage/dev-lang/rust-1.74.1-r101/work/bootstrap/mrustc-stage0/rustc-build/build_rustc_llvm.txt_failed.txt
>  for stdout)

/var/tmp/portage/dev-lang/rust-1.74.1-r101/work/bootstrap/mrustc-stage0/rustc-build/build_rustc_llvm.txt_failed.txt

> running: "x86_64-pc-linux-musl-g++" "-O2" "-ffunction-sections" 
> "-fdata-sections" "-fPIC" "-gdwarf-4" "-fno-omit-frame-pointer" "-m64" "-O2" 
> "-pipe" "-I/usr/lib/llvm/17/include" "-std=c++17" "-stdlib=libc++" 
> "-D__STDC_CONSTANT_MACROS" "-D__STDC_FORMAT_MACROS" "-D__STDC_LIMIT_MACROS" 
> "-DLLVM_COMPONENT_AARCH64" "-DLLVM_COMPONENT_AMDGPU" "-DLLVM_COMPONENT_ARM" 
> "-DLLVM_COMPONENT_ASMPARSER" "-DLLVM_COMPONENT_AVR" 
> "-DLLVM_COMPONENT_BITREADER" "-DLLVM_COMPONENT_BITWRITER" 
> "-DLLVM_COMPONENT_BPF" "-DLLVM_COMPONENT_COVERAGE" "-DLLVM_COMPONENT_HEXAGON" 
> "-DLLVM_COMPONENT_INSTRUMENTATION" "-DLLVM_COMPONENT_IPO" 
> "-DLLVM_COMPONENT_LINKER" "-DLLVM_COMPONENT_LOONGARCH" "-DLLVM_COMPONENT_LTO" 
> "-DLLVM_COMPONENT_MIPS" "-DLLVM_COMPONENT_MSP430" "-DLLVM_COMPONENT_NVPTX" 
> "-DLLVM_COMPONENT_POWERPC" "-DLLVM_COMPONENT_RISCV" "-DLLVM_COMPONENT_SPARC" 
> "-DLLVM_COMPONENT_SYSTEMZ" "-DLLVM_COMPONENT_WEBASSEMBLY" 
> "-DLLVM_COMPONENT_X86" "-o" 
> "/var/tmp/portage/dev-lang/rust-1.74.1-r101/work/bootstrap/mrustc-stage0/r
 ustc-build/build_rustc_llvm/llvm-wrapper/PassWrapper.o" "-c" 
"llvm-wrapper/PassWrapper.cpp"
> cargo:warning=llvm-wrapper/PassWrapper.cpp:3:10: fatal error: cstddef: No 
> such file or directory
> cargo:warning=    3 | #include <cstddef>
> cargo:warning=      |          ^~~~~~~~~
> cargo:warning=compilation terminated.
> exit status: 1

2. Linker failure

Found on llvm profile for both glibc and musl if llvm-core/llvm is built
by GCC. The bundled llvm is always built by gcc because bootstrap with
murst requires gcc. Under the llvm profile `LLVM_USE_LIBCXX=1` is
defined, causing Rust build scripts to link with `-lc++` instead of
`-lstdc++`. Since mrustc’s g++-compiled objects depend on libstdc++,
linking fails with (glibc):

> /.../x86_64-pc-linux-musl/bin/ld: 
> /var/tmp/portage/dev-lang/rust-1.74.1-r101/work/bootstrap/mrustc-stage0/rustc-build/build_rustc_llvm/libllvm-wrapper.a(PassWrapper.o):
>  undefined reference to symbol '_ZNSt6localeD1Ev@ <AT> GLIBCXX_3.4'
> /.../x86_64-pc-linux-musl/bin/ld: 
> /usr/lib/gcc/x86_64-pc-linux-musl/15/libstdc++.so.6: error adding symbols: 
> DSO missing from command line

or (musl):

> /.../x86_64-pc-linux-musl/bin/ld: warning: x86_64.o: missing .note.GNU-stack 
> section implies executable stack
> /.../x86_64-pc-linux-musl/bin/ld: NOTE: This behaviour is deprecated and will 
> be removed in a future version of the linker
> /.../x86_64-pc-linux-musl/bin/ld: 
> /var/tmp/portage/dev-lang/rust-1.74.1-r101/work/bootstrap/mrustc-stage0/rustc-build/build_rustc_llvm/libllvm-wrapper.a(PassWrapper.o):
>  in function `std::_Rb_tree_iterator<std::pair<unsigned long const, 
> llvm::GlobalValue::LinkageTypes> >::operator--()':
> /usr/lib/gcc/x86_64-pc-linux-musl/14/include/g++-v14/bits/stl_tree.h:298:(.text._ZNSt8_Rb_treeImSt4pairIKmN4llvm11GlobalValue12LinkageTypesEESt10_Select1stIS5_ESt4lessImESaIS5_EE24_M_get_insert_unique_posERS1_.isra.0+0x93):
>  undefined reference to `std::_Rb_tree_decrement(std::_Rb_tree_node_base*)'

Fix by unsetting `LLVM_USE_LIBCXX` during bootstrap, ensuring that the
build links against libstdc++ instead of libc++. See the relevant Rust code
in `compiler/rustc_llvm/build.rs`.

Note: llvm-config may refer to the bundled LLVM if USE="-system-llvm",
so we avoid relying on tc-get-cxx-stdlib in this context.

Signed-off-by: Z. Liu <zhixu.liu <AT> gmail.com>
Part-of: https://github.com/gentoo/gentoo/pull/44129
Closes: https://github.com/gentoo/gentoo/pull/44129
Signed-off-by: Sam James <sam <AT> gentoo.org>

 dev-lang/rust/rust-1.74.1-r101.ebuild | 62 +++++++++++++++++++++++++++++++++--
 1 file changed, 60 insertions(+), 2 deletions(-)

diff --git a/dev-lang/rust/rust-1.74.1-r101.ebuild 
b/dev-lang/rust/rust-1.74.1-r101.ebuild
index 2aeca76715d5..910c77941d1e 100644
--- a/dev-lang/rust/rust-1.74.1-r101.ebuild
+++ b/dev-lang/rust/rust-1.74.1-r101.ebuild
@@ -237,7 +237,10 @@ pkg_setup() {
 
                if use mrustc-bootstrap; then
                        if ! tc-is-gcc; then
-                               die "USE=mrustc-bootstrap reqires that the 
build environment use GCC"
+                               # USE="mrustc-bootstrap" reqires that the build 
environment use GCC
+                               export CC=${CHOST}-gcc
+                               export CXX=${CHOST}-g++
+                               tc-is-gcc || die "tc-is-gcc failed in spite of 
CC=${CC}"
                        fi
                else
                        rust_pkg_setup
@@ -459,7 +462,11 @@ src_configure() {
                        ranlib = "$(tc-getRANLIB)"
                        llvm-libunwind = "$(usex llvm-libunwind $(usex 
system-llvm system in-tree) no)"
                _EOF_
-               if use system-llvm; then
+               if use mrustc-bootstrap; then
+                       cat <<- _EOF_ >> "${S}"/config.toml
+                               llvm-config = "${WORKDIR}/llvm-config"
+                       _EOF_
+               elif use system-llvm; then
                        cat <<- _EOF_ >> "${S}"/config.toml
                                llvm-config = 
"$(get_llvm_prefix)/bin/llvm-config"
                        _EOF_
@@ -648,13 +655,64 @@ mrustc_bootstrap() {
        # These flags are used in every invocation of our bootstrap `cargo`.
        local cargo_flags="--target ${CFG_COMPILER_HOST_TRIPLE} -j 
$(makeopts_jobs) --release --verbose"
 
+       # for bootstrap, let's using the built-in stdlib of compiler (could be 
the bundled one)
+       filter-flags '-stdlib=*'
+
+       # mrustc requires gcc, so disable libcxx to avoid linker failure on w/o 
'-lstdc++'
+       [[ "${LLVM_USE_LIBCXX}" == "1" ]] && unset LLVM_USE_LIBCXX
+
+       local llvm_config_wrapper_cxxflags=0
+
        if use system-llvm; then
                export LLVM_CONFIG="$(get_llvm_prefix)/bin/llvm-config"
+
+               local llvm_config_cxxflags=$(${LLVM_CONFIG} --cxxflags)
+               elog "Checking llvm-config --cxxflags: 
'${llvm_config_cxxflags}'"
+               [[ "${llvm_config_cxxflags}" =~ 
(^|[[:space:]])-stdlib=libc\+\+([[:space:]]|$) ]] && {
+                       elog "Found LLVM CXXFLAGS has \"--stdlib=libc++\""
+                       llvm_config_wrapper_cxxflags=1
+               }
        else
                llvm_bootstrap
                export LLVM_CONFIG="${WORKDIR}/bootstrap/llvm/bin/llvm-config"
        fi
 
+       elog "LLVM_CONFIG before wrappers: ${LLVM_CONFIG}"
+
+       # workaround for gcc bug 122409 on musl by wrapping llvm-config
+       # to append libc++ header if has "-stdlib=libc++"
+       elog "Preparing wrapper of llvm-config (${WORKDIR}/llvm-config)"
+       cat > ${WORKDIR}/llvm-config <<-EOF || die
+       #!/bin/bash
+
+       RULES=()
+       for flag in "\$@"; do
+           case "\${flag}" in
+       $([[ "${llvm_config_wrapper_cxxflags}" == 1 ]] && {
+               echo "        --cxxflags) RULES+=( \"-E\" 
\"s@(^|[[:space:]]+)(-stdlib=libc\\+\\+)(\\$|[[:space:]])@\\1-I${EPREFIX}/usr/include/c++/v1
 \\2\\3@g\" ) ;;"
+       })
+               *)
+                   ;;
+           esac
+       done
+
+       [[ -z "\${RULES}" ]] && {
+           ${LLVM_CONFIG} "\$@"
+       } || {
+           ${LLVM_CONFIG} "\$@" | \\
+               tee -a ${T}/llvm-config.0.log | \\
+               sed "\${RULES[@]}" | \\
+               tee -a ${T}/llvm-config.1.log
+           exit \${PIPESTATUS[0]}
+       }
+       EOF
+       export LLVM_CONFIG="${WORKDIR}/llvm-config"
+       chmod +x ${WORKDIR}/llvm-config || die
+
+       einfo "llvm-config wrapper contents:"
+       cat "${LLVM_CONFIG}" || die
+       echo
+
        # define the mrustc sysroot and common minicargo arguments.
        local 
mrustc_sysroot="${BROOT}/usr/lib/rust/mrustc-${MRUSTC_VERSION}/lib/rustlib/${CFG_COMPILER_HOST_TRIPLE}/lib"
        local minicargo_common_args=(

Reply via email to