Skip to content

fix: run the Android llvm-ar probe in the caller's environment - #1867

Closed
MohammedAlkindi wants to merge 3 commits into
rust-lang:mainfrom
MohammedAlkindi:fix/android-ar-probe-env
Closed

fix: run the Android llvm-ar probe in the caller's environment#1867
MohammedAlkindi wants to merge 3 commits into
rust-lang:mainfrom
MohammedAlkindi:fix/android-ar-probe-env

Conversation

@MohammedAlkindi

@MohammedAlkindi MohammedAlkindi commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

The clang_android follow-up from #1866. Related: #1859.

This is stacked on #1866 and contains its two commits. Only the last one, fix: run the Android llvm-ar probe in the caller's environment, is new here. The diff will shrink to that once #1866 lands, so this is best read after it.

What broke

The Android branch of get_base_archiver_variant works out whether the NDK ships llvm-ar under that name by running llvm-ar --version, and it built that probe with a bare Command::new:

name = format!("llvm-{tool}").into();
match Command::new(&name).arg("--version").status() {

A bare name resolves through the ambient PATH, not the one Build::env set up. So a caller that points PATH at its own toolchain gets the question answered about a different toolchain, and cc falls back to the target-prefixed name.

This is the third site of the same root cause as #1859, after family detection and is_flag_supported. It is also the one that made clang_android unable to run on my machine: the test puts llvm-ar on PATH through Build::env, the probe never saw it, and the fallback arm-linux-androideabi-ar is not there either, so cc's error path exited the process and took the whole test binary with it.

error occurred in cc-rs: failed to find tool "arm-linux-androideabi-ar": program not found

Green on CI because the runners have something the probe can find in the ambient PATH.

The change

The probe goes through set_ar_detection_env, so it inherits Build::env and gets its own recording class rather than consuming an out{i} slot. That is the third class you and I discussed on #1866, and it is the reason this is a separate PR: it widens the design from two classes to three.

ProbeKind::ArDetection maps to CC_SHIM_OUT_FILES_FOR_AR_DETECTION, and Test gains collect_ar_detection_probes and get_ar_detection_probes alongside the other two.

I did not touch the fallback logic itself, only which environment the probe asks the question in.

Verified

Windows 11, x86_64-pc-windows-msvc, rustc 1.97.1.

Before, on the unmodified branch, clang_android did not fail, it aborted the process, which is why the rest of that binary never reported. After:

tests/test.rs   59 passed, 0 failed, 0 ignored

That is the whole binary green in one run for the first time here. Previously 58 of 59 passed when run one test per process, with clang_android killing the shared run.

Everything else, on this branch: every other test binary green, doc-tests 28 passed, cargo clippy --workspace --all-targets -- -D warnings clean, cargo fmt --all --check clean, and MSRV check -p cc on 1.65.0 clean.

The new assertion is test.get_ar_detection_probes(0).must_have("--version"), which fails on unmodified source because the probe never reaches the shim and no recording exists.

One thing worth your call

The probe still runs --version and inherits stdio, so under the shim it is a real process spawn per Android build. That was already true, and I left it alone rather than widening the PR, but if you would rather it were quieted or cached, say so and I will fold it in.

LLM usage, per the Rust policy: this change was developed with AI assistance (Claude). Adding this retroactively, since it should have been disclosed when the PR was opened.

`is_flag_supported_inner` built its probe from a fresh `Build`, dropping
`Build::env` along with the out dir and the caches. The probe therefore
resolved a bare compiler name such as `cc` through the ambient `PATH`
rather than the one the compile commands run in, and answered a question
about a different compiler than the one being built with. Compiler
family detection had the same gap at four more spawns: they applied no
environment at all, and `Tool::with_features` was never handed one.

Both now run in the environment `Build::env` sets up, and the family
lookup cache is keyed on that environment as well as the path and
arguments, so two builds that differ only in it cannot share an answer.

Reaching the right compiler means the probes now reach the test shim,
where they would have taken `out{i}` slots and shifted the numbering
every assertion depends on. Two variables opt one class of probe in by
name instead: `CC_SHIM_OUT_FILES_FOR_FAMILY_DETECTION` and
`CC_SHIM_OUT_FILES_FOR_FLAG_SUPPORT_CHECK`. cc renames the one matching
the probe it is about to spawn to `CC_SHIM_OUT_FILES`, rather than
copying `Build::env` over blindly, so a probe no test asked about
records nothing at all. That replaces the `-c` sniffing the shim did to
guess whether it was looking at a flag probe, and the panic on a missing
`CC_SHIM_OUT_DIR` that family detection relied on to keep failing.

`gnu_flag_if_supported` no longer skips Windows. It needed the probe to
reject a flag and got that from whatever compiler the machine happened
to have installed; it now says so with `CC_SHIM_FAIL_IF_ARG`.

Refs rust-lang#1859
Four things from the review, no behaviour change.

The shim collected argv twice. `split_first` gives the program and the rest
in one step, and `record` now takes `&[String]` rather than `&[&String]`.

The probe `Build` copies the env with `clone_from` instead of replaying it
key by key.

`ProbeKind` and `set_probe_env` are private again, behind a `CommandExt`
trait with `set_family_detection_env` and `set_flag_supported_env`, so a
caller names the probe class instead of passing an enum.

The test harness gained `collect_family_detection_probes` and
`collect_flag_supported_probes` with matching getters, so a test opts a
class in by name and `CC_SHIM_OUT_FILES_FOR_*` stays inside the harness.
The getters take an index because `clang_cl_scope_all` records two flag
support probes in one build, so a single file per class was not enough.
The Android branch of `get_base_archiver_variant` decides whether the NDK
ships `llvm-ar` under that name by running `llvm-ar --version`, and it
built that probe with a bare `Command::new`. A bare name resolves through
the ambient `PATH`, not the one `Build::env` set up, so a caller that
points `PATH` at its own toolchain gets the question answered about a
different toolchain and cc falls back to the target-prefixed name.

This is the third site of the same root cause as rust-lang#1859, after compiler
family detection and `is_flag_supported`, and it is the one that made
`clang_android` unable to run here: the test puts `llvm-ar` on `PATH`
through `Build::env`, the probe never saw it, and the fallback
`arm-linux-androideabi-ar` does not exist, so cc exited the process.

The probe now goes through `set_ar_detection_env`, so it inherits
`Build::env` and takes its own recording class rather than an `out{i}`
slot. `Test` gains `collect_ar_detection_probes` and
`get_ar_detection_probes` to match the other two classes.

@NobodyXu NobodyXu left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks LGTM, can be merged after the other one

@MohammedAlkindi

Copy link
Copy Markdown
Contributor Author

Superseded by #1868, which is this same commit rebased onto main now that #1866 has landed. This branch went conflicted the moment #1866 squash-merged, exactly as flagged, and updating it in place would have needed a force-push that my setup gates on a human, so a fresh branch was the clean route to a mergeable version.

#1868 is one commit instead of three and is green: tests/test.rs 59 passed in a single run, doc-tests 28, clippy -D warnings clean, fmt clean, MSRV 1.65.0 clean. Closing this one to keep the queue honest.

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.

2 participants