rust-lang/rust · critical

Could not load libgccjit.so. Attempted paths: {:#?}

Error message

Could not load libgccjit.so. Attempted paths: {:#?}

What it means

`panic!("Could not load libgccjit.so. Attempted paths: {:#?}")` in `GccCodegenBackend::init`, reached after the backend iterated every `--sysroot` path (via `sysroot.all_paths()`), checked for the existence of `rustlib/codegen-backends/lib/<target>/libgccjit.so`, and found none. The panic lists the exact paths tried so the user can see where the backend expected the library. Unlike error 156, here the file was never found at all.

Source

Thrown at compiler/rustc_codegen_gcc/src/lib.rs:228

        // We use all_paths() instead of only path() in case the path specified by --sysroot is
        // invalid.
        // This is the case for instance in Rust for Linux where they specify --sysroot=/dev/null.
        for path in sess.opts.sysroot.all_paths() {
            let libgccjit_target_lib_file = file_path(path, sess);
            if let Ok(true) = fs::exists(&libgccjit_target_lib_file) {
                load_libgccjit_if_needed(&libgccjit_target_lib_file);
                break;
            }
        }

        if !gccjit::is_loaded() {
            let mut paths = vec![];
            for path in sess.opts.sysroot.all_paths() {
                let libgccjit_target_lib_file = file_path(path, sess);
                paths.push(libgccjit_target_lib_file);
            }

            panic!("Could not load libgccjit.so. Attempted paths: {:#?}", paths);
        }

        #[cfg(feature = "master")]
        {
            gccjit::set_lang_name(c"GNU Rust");

            let target_cpu = target_cpu(sess);

            // Get the second TargetInfo with the correct CPU features by setting the arch.
            let context = Context::default();
            if target_cpu != "generic" {
                context.add_command_line_option(format!("-march={}", target_cpu));
            }

            *self.target_info.info.lock().expect("lock") =
                IntoDynSyncSend(Some(context.get_target_info()));
        }

View on GitHub (pinned to 22057b88b0)

Solutions

  1. Install/place `libgccjit.so` under `<sysroot>/lib/rustlib/<host>/codegen-backends/lib/<target>/libgccjit.so` exactly as the panic's path list shows.
  2. Drop the `--sysroot` override (or `RUST_SYSROOT`) so the default toolchain sysroot is used.
  3. Install the rustc_codegen_gcc toolchain / component that ships the runtime library.
  4. Verify `rustc --print sysroot` resolves to the directory that actually contains the listed subpath.
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check all candidate sysroot paths the backend would search
use std::path::Path;

fn find_libgccjit(sysroots: &[&str], host_triple: &str, target_triple: &str) -> Result<String, String> {
    let mut attempted: Vec<String> = Vec::new();
    for sysroot in sysroots {
        let p = format!(
            "{}/lib/rustlib/{}/codegen-backends/lib/{}/libgccjit.so",
            sysroot, host_triple, target_triple
        );
        attempted.push(p.clone());
        if Path::new(&p).exists() {
            return Ok(p);
        }
    }
    // Check GCC_BACKEND_PATH override
    if let Ok(override_path) = std::env::var("GCC_BACKEND_PATH") {
        if Path::new(&override_path).exists() {
            return Ok(override_path);
        }
        attempted.push(override_path);
    }
    // Check ldconfig
    let ldc = std::process::Command::new("sh")
        .args(["-c", "ldconfig -p 2>/dev/null | grep libgccjit | head -1"])
        .output()
        .ok()
        .and_then(|o| String::from_utf8(o.stdout).ok())
        .unwrap_or_default();
    if !ldc.trim().is_empty() {
        return Ok(ldc.trim().to_string());
    }
    Err(format!("Could not find libgccjit.so. Attempted paths: {:#?}", attempted))
}

// Usage in build.rs:
// let sysroot = std::process::Command::new("rustc").arg("--print").arg("sysroot").output().unwrap();
// let sr = String::from_utf8_lossy(&sysroot.stdout).trim().to_string();
// find_libgccjit(&[&sr], std::env::consts::ARCH, std::env::consts::ARCH)?;

Try / catch

// Catch exhaustive-load failure and provide actionable diagnostics
use std::process::Command;

fn build_with_gcc_backend(crate_path: &str) -> Result<(), String> {
    let out = Command::new("rustc")
        .args(["-Z", "codegen-backend=gcc"])
        .arg(crate_path)
        .output()
        .map_err(|e| e.to_string())?;
    if !out.status.success() {
        let stderr = String::from_utf8_lossy(&out.stderr);
        if stderr.contains("Could not load libgccjit") {
            // Provide remediation
            return Err(format!(
                "libgccjit.so not found in any sysroot. Fix:\n\
                 1. Install libgccjit-dev\n\
                 2. Or set GCC_BACKEND_PATH=/path/to/libgccjit.so\n\
                 3. Or use the LLVM backend instead\n\
                 Original error: {}",
                stderr.lines().find(|l| l.contains("Could not load")).unwrap_or("unknown")
            ));
        }
        return Err(stderr.to_string());
    }
    Ok(())
}

Prevention

When it happens

Trigger: Compiling with `-Ccodegen-backend=gcc` when the libgccjit target library is absent from every sysroot, e.g. the GCC backend component was never installed, or `--sysroot` was overridden to a path that lacks the codegen-backends directory (Rust for Linux passes `--sysroot=/dev/null`).

Common situations: Fresh rustc_codegen_gcc setup where the backend crate is built but the runtime `libgccjit.so` was not placed under `rustlib/codegen-backends/lib/<target>/`; cross-compiling to a target with no matching triplet directory; rust-toolchain override pointing at a minimal sysroot.

Related errors


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