rust-lang/rust · critical

TARGET was not set

Error message

TARGET was not set

What it means

Thrown at build.rs:224 via `env::var("TARGET").expect("TARGET was not set")`. Cargo normally exports TARGET (the triple being built for) to every build script as part of its documented environment; rustc_llvm uses TARGET pervasively (cross-compile detection at build.rs:226, platform-specific linking in build.rs:348-547). Its absence means the build script is not running under a normal Cargo invocation, so the contract is broken.

Source

Thrown at compiler/rustc_llvm/build.rs:224

    //
    // In that case, there's no guarantee that we can actually run the target,
    // so the build system works around this by giving us the LLVM_CONFIG for
    // the host platform. This only really works if the host LLVM and target
    // LLVM are compiled the same way, but for us that's typically the case.
    //
    // We *want* detect this cross compiling situation by asking llvm-config
    // what its host-target is. If that's not the TARGET, then we're cross
    // compiling. Unfortunately `llvm-config` seems either be buggy, or we're
    // misconfiguring it, because the `i686-pc-windows-gnu` build of LLVM will
    // report itself with a `--host-target` of `x86_64-pc-windows-gnu`. This
    // tricks us into thinking we're doing a cross build when we aren't, so
    // havoc ensues.
    //
    // In any case, if we're cross compiling, this generally just means that we
    // can't trust all the output of llvm-config because it might be targeted
    // for the host rather than the target. As a result a bunch of blocks below
    // are gated on `if !is_crossed`
    let target = env::var("TARGET").expect("TARGET was not set");
    let host = env::var("HOST").expect("HOST was not set");
    let is_crossed = target != host;

    let components = output(Command::new(&llvm_config).arg("--components"));
    let mut components = components.split_whitespace().collect::<Vec<_>>();
    components.retain(|c| OPTIONAL_COMPONENTS.contains(c) || REQUIRED_COMPONENTS.contains(c));

    for component in REQUIRED_COMPONENTS {
        if !components.contains(component) {
            panic!("require llvm component {component} but wasn't found");
        }
    }

    for component in components.iter() {
        println!("cargo:rustc-cfg=llvm_component=\"{component}\"");
    }

    // Link in our own LLVM shims, compiled with the same flags as LLVM

View on GitHub (pinned to 22057b88b0)

Solutions

  1. Run the build through cargo or bootstrap (`./x.py build`) so Cargo injects TARGET and the other standard build-script variables.
  2. If invoking the build script manually for debugging, export the variables Cargo would: `TARGET=<triple> HOST=<triple> ... ./build-script-build`.
  3. Check that no wrapper script or container is sanitizing the environment passed to the build script.
Defensive patterns

Strategy: validation

Validate before calling

# TARGET is set by cargo/x.py; running build.rs standalone leaves it unset
[ -n "${TARGET:-}" ] || { echo "TARGET not set: invoke via './x.py build' or 'cargo build', not rustc directly"; exit 1; }

Prevention

When it happens

Trigger: Running the build script through a mechanism that does not set Cargo's standard build-script environment variables — e.g. invoking the compiled build script binary directly, or wrapping cargo in a way that strips env vars. Under normal `cargo build`/`./x.py`, Cargo always sets TARGET.

Common situations: Debugging by executing `./target/debug/build/rustc_llvm-<hash>/build-script-build` by hand; sandboxed/containers that filter the environment; broken custom build orchestration layered on top of cargo.

Related errors


AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03). Data as JSON: /data/errors/95b26fe77cafec6f.json. Report an issue: GitHub.