fix: fall back to compile-time musl detection when no system linker found#8825
fix: fall back to compile-time musl detection when no system linker found#8825
Conversation
…ound When neither glibc's ld-linux-* nor musl's ld-musl-* dynamic linker is present (e.g., scratch or busybox Docker containers), mise defaulted to glibc — even when the binary itself was compiled for musl. This caused musl-compiled mise to pick glibc lockfile entries. Fall back to cfg!(target_env = "musl") when no linker files are detected at runtime. This mirrors the approach already used by the Bun plugin. The fix is applied to both src/platform.rs (is_musl_system) and the mirrored logic in crates/vfox/src/config.rs (env_type), as noted by the "keep in sync" comments. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Greptile SummaryThis PR fixes a bug where a musl-compiled mise binary running inside a minimal container (scratch, busybox — no Key changes:
Confidence Score: 4/5Core runtime logic is correct and safe to ship; minor cleanup and known test-robustness concerns remain before merge. The fix itself is correct — the compile-time fallback is sound, MISE_LIBC validation is properly restricted to gnu/musl, and the two mirrored implementations stay in sync. Score is 4 rather than 5 because (a) the musl-gated tests can produce false failures when run on a glibc CI host, an unresolved concern noted in prior review threads, and (b) the /lib64 musl check is unnecessary dead code introduced alongside the real fix. src/platform.rs and crates/vfox/src/config.rs — the musl-gated tests and the /lib64-for-musl filesystem scan. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[is_musl_system / env_type called] --> B{MISE_LIBC set?}
B -- "musl" --> R_MUSL[return musl]
B -- "gnu" --> R_GNU[return gnu/false]
B -- invalid / unset --> C{"/lib or /lib64\nhas ld-linux-*?"}
C -- yes --> R_GNU
C -- no --> D{"/lib or /lib64\nhas ld-musl-*?"}
D -- yes --> R_MUSL
D -- no --> E{"cfg!(target_env = musl)?"}
E -- true --> R_MUSL
E -- false --> F{"config.rs only:\ncfg!(target_env = gnu)?"}
F -- true --> R_GNU
F -- false --> R_NONE[return None]
Reviews (8): Last reviewed commit: "[autofix.ci] apply automated fixes" | Re-trigger Greptile |
There was a problem hiding this comment.
Code Review
This pull request introduces a fallback mechanism to detect the environment type (musl) using compile-time configuration when no dynamic linker is found in the filesystem, which is useful for minimal environments like scratch or busybox containers. The review feedback suggests improving the robustness of this detection by checking both /lib and /lib64 directories for the musl linker and adding a similar fallback for GNU environments.
| if has_file_prefix("/lib", "ld-musl-") { | ||
| return Some("musl".to_string()); | ||
| } | ||
| // No linker found at all (e.g., scratch/busybox container) — | ||
| // fall back to the binary's compile-time target | ||
| if cfg!(target_env = "musl") { | ||
| return Some("musl".to_string()); | ||
| } |
There was a problem hiding this comment.
For consistency with the glibc detection logic above, consider checking both /lib and /lib64 for the musl linker. Additionally, to fully implement the "fallback to compile-time target" logic, you could also check for cfg!(target_env = "gnu") to ensure env_type() returns Some("gnu") even in scratch containers when using a glibc-compiled binary.
for dir in ["/lib", "/lib64"] {
if has_file_prefix(dir, "ld-musl-") {
return Some("musl".to_string());
}
}
// No linker found at all (e.g., scratch/busybox container) —
// fall back to the binary's compile-time target
if cfg!(target_env = "musl") {
return Some("musl".to_string());
}
if cfg!(target_env = "gnu") {
return Some("gnu".to_string());
}There was a problem hiding this comment.
Addressed in dd4ce3d — now checks both /lib and /lib64 for musl, and added cfg!(target_env = "gnu") fallback.
| if has_file_prefix("/lib", "ld-musl-") { | ||
| return true; | ||
| } | ||
| // No linker found at all (e.g., scratch/busybox container) — | ||
| // fall back to the binary's compile-time target | ||
| cfg!(target_env = "musl") |
There was a problem hiding this comment.
For consistency with the glibc detection logic above, consider checking both /lib and /lib64 for the musl linker. This ensures that the runtime detection is robust across different Linux distributions before falling back to the compile-time target.
for dir in ["/lib", "/lib64"] {
if has_file_prefix(dir, "ld-musl-") {
return true;
}
}
// No linker found at all (e.g., scratch/busybox container) —
// fall back to the binary's compile-time target
cfg!(target_env = "musl")There was a problem hiding this comment.
Addressed in dd4ce3d — now checks both /lib and /lib64 for musl before falling back to compile-time target.
- Check both /lib and /lib64 for musl linker (consistent with glibc detection) - Add cfg!(target_env = "gnu") fallback in env_type() for completeness Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- test_musl_binary_detects_musl: verifies musl binary always returns true - test_current_platform_has_qualifier: ensures qualifier is never None on Linux - test_env_type_returns_some_on_linux: env_type() never returns None - test_env_type_musl_binary_returns_musl: musl binary reports musl All tests are #[cfg(target_os = "linux")] — will run in CI. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Platform::current() only sets qualifier to Some("musl") when
is_musl_system() is true. On glibc it's None. The test was
incorrectly asserting is_some() on all Linux, but should only
check musl-compiled binaries.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Allows users to force musl or glibc detection via MISE_LIBC=musl or MISE_LIBC=gnu. Useful for scratch containers, cross-compilation, and testing. Checked before runtime linker detection. Also fix test that failed on glibc CI (qualifier is only set for musl). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Invalid values are now silently ignored (fall through to runtime detection) instead of being passed through. This keeps is_musl_system() and env_type() in sync — both reject invalid input identically. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
jdx
left a comment
There was a problem hiding this comment.
A few things to address before merging:
-
Fix
MISE_LIBCvalidation inconfig.rs—platform.rscorrectly only accepts"musl"viaeq_ignore_ascii_case, butconfig.rsblindly passes through any value (Some(val.to_lowercase())).MISE_LIBC=typowould silently produceSome("typo")and cause wrong tool selection. Validate it the same way asplatform.rs. -
Remove the tautology tests —
test_mise_libc_env_var_parsingandtest_mise_libc_env_var_acceptedtest Rust'seq_ignore_ascii_caseandto_lowercase, not your actual code. TheLazy/LazyLockcaching means you can't test the env var override in-process anyway, so these tests just add noise. Remove them. -
Document
MISE_LIBC— This is a useful escape hatch but it's not discoverable anywhere. Add it to the docs/settings so users can find it.
This comment was generated by Claude Code.
- Remove test_mise_libc_env_var_validation and test_mise_libc_env_var_accepted (tested Rust's string methods, not our code; LazyLock caching prevents in-process env var testing anyway) - Add MISE_LIBC documentation to docs/mise-cookbook/docker.md Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
All addressed. |
### 🚀 Features - **(install)** add per-tool install_before option by @sargunv-headway in [#8842](#8842) ### 🐛 Bug Fixes - **(cli)** respect `-q` flag in `mise prepare` command by @Marukome0743 in [#8792](#8792) - fall back to compile-time musl detection when no system linker found by @davireis in [#8825](#8825) ### 📚 Documentation - fix GitHub capitalization in Alpine docs by @Rohan5commit in [#8844](#8844) ### 📦 Registry - add dbt-fusion ([aqua:getdbt.com/dbt-fusion](https://github.com/getdbt.com/dbt-fusion)) by @ryan-pip in [#8837](#8837) ### New Contributors - @Marukome0743 made their first contribution in [#8792](#8792) - @sargunv-headway made their first contribution in [#8842](#8842) - @Rohan5commit made their first contribution in [#8844](#8844) - @ryan-pip made their first contribution in [#8837](#8837) - @rndmh3ro made their first contribution in [#8839](#8839) ## 📦 Aqua Registry Updates #### New Packages (1) - [`azu/dockerfile-pin`](https://github.com/azu/dockerfile-pin) #### Updated Packages (4) - [`anthropics/claude-code`](https://github.com/anthropics/claude-code) - [`dandavison/delta`](https://github.com/dandavison/delta) - [`goreleaser/goreleaser`](https://github.com/goreleaser/goreleaser) - [`zellij-org/zellij`](https://github.com/zellij-org/zellij)
Summary
ld-linux-*nor musl'sld-musl-*dynamic linker is found at runtime (e.g., scratch or busybox Docker containers), mise now falls back to the binary's compile-time target (cfg!(target_env = "musl")) instead of defaulting to glibc.src/platform.rs(is_musl_system()) and the mirrored logic incrates/vfox/src/config.rs(env_type()), as noted by the "keep in sync" comments.Problem
A musl-compiled mise binary running in a minimal container (scratch + busybox, no
/lib/ld-*files) incorrectly identifies the platform as glibc. This causes it to select glibc lockfile entries when both glibc and musl entries are available.Fix
When runtime linker detection finds no
/lib/ld-linux-*(glibc) and no/lib/ld-musl-*(musl), fall back tocfg!(target_env = "musl")— the binary's own compile-time target. This is a safe assumption: if the binary was compiled for musl and there's no linker to contradict that, tools installed by mise should also use musl.Precedent
The Bun plugin (
src/plugins/core/bun.rs) already usescfg!(target_env = "musl")for itsis_musl()check, so this pattern is established in the codebase.Reproduction
FROM scratchwith busybox and a musl-compiled mise binary.mise.lock) with both glibc and musl entries for a toolmise install— it picks the glibc entry (wrong)Test plan
cargo checkpasses (confirmed locally)is_musl_system()still returnsfalse(glibc linker detected first)is_musl_system()still returnstrue(musl linker detected)is_musl_system()now returnstrue(compile-time fallback)is_musl_system()returnsfalse(compile-time fallback,cfg!is false)🤖 Generated with Claude Code