Skip to content

feat(toolchain,build): llvm-musl static target — target libc++ payload axis - #492

Open
yspbwx2010 wants to merge 2 commits into
mcpp-community:mainfrom
cloud-teahouse:feat/llvm-musl-target
Open

feat(toolchain,build): llvm-musl static target — target libc++ payload axis#492
yspbwx2010 wants to merge 2 commits into
mcpp-community:mainfrom
cloud-teahouse:feat/llvm-musl-target

Conversation

@yspbwx2010

@yspbwx2010 yspbwx2010 commented Aug 23, 2026

Copy link
Copy Markdown
Member

Summary

  • The LLVM family could not serve *-linux-musl: a clang frontend carries no target libc, and the hosted clang-with-cfg path reconstructs the HOST's world (glibc payload, host libc++), which is exactly wrong for the target.
  • triple: new TargetInfo::llvmSysroot column + effective_llvm_sysroot(). The gcc-musl payload path is untouched (self-contained); the column names an xim package carrying the target's musl libc++ for the LLVM family only.
  • prepare: clang-on-musl resolves that payload into targetSysroot* and points stdModuleSource at the payload's std.cppm, so the std BMI is built over the target's libc++, not the host's.
  • flags: isLlvmMusl branch for compile and link — neutral driver (--no-default-config), target triple, --gcc-toolchain to the musl-gcc payload for crt/libgcc/libc, -nostdinc++/-nostdlib++ with explicit musl libc++ archives; the host kLinkDriverFlags (compiler-rt/libunwind) do not appear.

The payload package (xim:llvm-musl-libcxx) ships separately in the package index; until it exists this branch simply does not arm — zero behavior change for every existing toolchain/target combination.

Design doc: .agents/docs/2026-08-23-llvm-musl-target-design.md (in this PR).

Background: the gcc-musl route is currently blocked by a GCC 16 modules ICE (BMI read-back segfault; the gdb register dump shows a corrupted in-heap tree pointer inside cc1plus), while clang 22 compiles the same module-heavy codebase cleanly. This PR is the engine half of the llvm-musl route; the payload half follows in the package index.

Closes #491

Test plan

  • mcpp test unit/integration: 91 passed; 1 failure in unit/test_elf_runtime that is environmental and pre-existing on this sandbox (host /lib64/libtinfo.so.6 is a symlink chain, weakly_canonical rewrites the name the assertion greps for — unrelated code path, 3/3 reproducible with the change stashed)
  • New effective_llvm_sysroot tests: test_toolchain_triple 28/28 (3 new)
  • Self-hosted build green with the change (release, 125s incremental)
  • End-to-end: mcpp build --toolchain llvm@22.1.8 --target x86_64-linux-musl on a module-heavy workspace (~240 module TUs) once the payload package lands — validated locally via an equivalent direct-clang pipeline producing fully static x86_64 and aarch64 (qemu-verified) binaries

…d axis

The llvm family could not serve *-linux-musl: a clang frontend carries no
target libc, and the hosted clang-with-cfg path reconstructs the HOST's
world (glibc payload, host libc++), which is exactly wrong for the target
— the same class of bug as freestanding E1, one layer up.

- triple: new TargetInfo::llvmSysroot column + effective_llvm_sysroot().
  The gcc payload for *-linux-musl stays untouched (self-contained); the
  column names an xim package carrying the target's musl libc++ (headers,
  archives, std.cppm) for the LLVM family only.
- prepare: clang-on-musl resolves that payload into targetSysroot*, and
  points stdModuleSource at the payload's std.cppm so the std BMI is
  built over the target's libc++, not the host's.
- flags: isLlvmMusl branch for compile and link — neutral driver, target
  triple, --gcc-toolchain to the musl-gcc payload for crt/libgcc/libc,
  -nostdinc++/-nostdlib++ with explicit musl libc++ archives; the host
  kLinkDriverFlags (compiler-rt/libunwind) do not appear.

The payload package (xim:llvm-musl-libcxx) ships separately in the
package index; until it exists the branch simply does not arm.

Refs mcpp-community#491
Four defects the first end-to-end run surfaced, all found by building a
module TU against the llvm-musl-libcxx payload:

- pin override: the target vocabulary pin silently replaced --toolchain
  (it arrives via the env side channel, which the pin guard never read),
  so `--toolchain llvm --target x86_64-linux-musl` resolved gcc. The
  flag now blocks the pin on its own, regardless of target origin.
- triple propagation: the target-triple correction was scoped to
  freestanding only, but llvm-on-musl is the same one-binary case — the
  clang frontend's -dumpmachine answers with the host while the build
  targets musl, leaving the output dir, cache key and flags on the host
  triple (E1 for a hosted target). Freestanding-only side effects
  (hasImportStd off, the picolibc sysroot lookup) stay scoped.
- std module over the wrong libc: the std precompile used the shared
  host-flags producer (host libc++ headers + glibc), which fails on the
  payload's std.cppm with __config_site / bits/alltypes.h not found.
  llvm-musl now builds the std BMI from the payload headers over the
  musl-gcc sysroot (both payload naming shapes, with the xim- prefix).
- payload C runtime leak: the clangWithCfg PayloadFirst link flags name
  the HOST's glibc, whose loader became a static binary's PT_INTERP.
  Excluded for llvm-musl; its branch already assembles the target C
  runtime (musl sysroot, crt via --gcc-toolchain).

Verified end to end: mcpp build --toolchain llvm@22.1.8 --target
x86_64-linux-musl on a hello-module project produces a fully static
x86_64 musl ELF (no PT_INTERP, not a dynamic executable) that runs.
Unit suite 91 passed; the 1 test_elf_runtime failure is the known
environmental one (host /lib64/libtinfo.so.6 symlink chain), unchanged.

Refs mcpp-community#491
@yspbwx2010

Copy link
Copy Markdown
Member Author

End-to-end verification complete — the first push had four defects that only a real build against the payload exposed (all fixed in 728c2c5):

  1. The vocabulary pin silently replaced --toolchain (the env side channel it arrives through was invisible to the pin guard), so --toolchain llvm@22.1.8 --target x86_64-linux-musl resolved gcc@16.1.0.
  2. The target-triple correction was freestanding-only; llvm-on-musl is the same one-binary case, so the output dir / cache key / flags all stayed on the host triple.
  3. The std BMI was built over the host libc++ headers and glibc (__config_site / bits/alltypes.h not found); it now uses the payload's headers over the musl-gcc sysroot.
  4. The clangWithCfg PayloadFirst link flags leaked the host glibc loader into a static binary's PT_INTERP (runtime segfault).

Verified: mcpp build --toolchain llvm@22.1.8 --target x86_64-linux-musl on a module project now yields a fully static x86_64 musl ELF (no PT_INTERP, not a dynamic executable) that runs. Unit suite 91 passed; the single test_elf_runtime failure is the known environmental one (host /lib64/libtinfo.so.6 symlink chain), reproducible with the change stashed.

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.

feat: llvm-musl static target support (llvm toolchain family for *-linux-musl)

1 participant