rust-lang/rust · critical

Cannot load libgccjit.so: {}

Error message

Cannot load libgccjit.so: {}

What it means

`panic!("Cannot load libgccjit.so: {}")` in `load_libgccjit_if_needed`, reached when `gccjit::load(&path)` returns `Err`. The backend located a candidate `libgccjit.so` under `<sysroot>/rustlib/codegen-backends/lib/<target>/libgccjit.so` and tried to dlopen it, but loading failed. The formatted `{}` is the underlying load error (missing symbol, ABI mismatch, missing transitive shared library, corrupt file).

Source

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

#[derive(Clone)]
pub struct GccCodegenBackend {
    target_info: LockedTargetInfo,
    lto_supported: Arc<AtomicBool>,
}

fn load_libgccjit_if_needed(libgccjit_target_lib_file: &Path) {
    if gccjit::is_loaded() {
        // Do not load a libgccjit second time.
        return;
    }

    let path = libgccjit_target_lib_file.to_str().expect("libgccjit path");

    let string = CString::new(path).expect("string to libgccjit path");

    if let Err(error) = gccjit::load(&string) {
        panic!("Cannot load libgccjit.so: {}", error);
    }
}

impl CodegenBackend for GccCodegenBackend {
    fn name(&self) -> &'static str {
        "gcc"
    }

    fn init(&self, sess: &Session) {
        fn file_path(sysroot_path: &Path, sess: &Session) -> PathBuf {
            let rustlib_path =
                rustc_target::relative_target_rustlib_path(sysroot_path, &sess.host.llvm_target);
            sysroot_path
                .join(rustlib_path)
                .join("codegen-backends")
                .join("lib")
                .join(sess.target.llvm_target.as_ref())
                .join("libgccjit.so")

View on GitHub (pinned to 22057b88b0)

Solutions

  1. Run `ldd <sysroot>/.../libgccjet.so` to find the missing transitive dependency and install it.
  2. Reinstall the rustc_codegen_gcc toolchain (or `rustup component add`-equivalent) so the bundled libgccjit and its deps match.
  3. Confirm the file is not corrupt: `file libgccjit.so` and `nm -D libgccjit.so | grep gccjit_create_context`.
  4. If you set `--sysroot`, point it at the toolchain root that actually ships libgccjit.so for your target.
Defensive patterns

Strategy: validation

Validate before calling

// Validate libgccjit.so is loadable BEFORE invoking the GCC backend
use std::path::Path;

fn libgccjit_loadable(sysroot: &str, host_triple: &str, target_triple: &str) -> Result<(), String> {
    // The backend looks for: sysroot/lib/rustlib/{host}/codegen-backends/lib/{target}/libgccjit.so
    let candidate = format!(
        "{}/lib/rustlib/{}/codegen-backends/lib/{}/libgccjit.so",
        sysroot, host_triple, target_triple
    );
    if Path::new(&candidate).exists() {
        // Verify it is actually dlopen-able (not a broken symlink)
        let probe = std::process::Command::new("sh")
            .args(["-c", &format!("ldd '{}' 2>&1", candidate)])
            .output()
            .map_err(|e| format!("Cannot run ldd: {}", e))?;
        let out = String::from_utf8_lossy(&probe.stdout);
        if out.contains("not found") {
            return Err(format!("libgccjit.so exists at {} but has unresolved dependencies: {}", candidate, out));
        }
        return Ok(());
    }
    // Fall back to system-wide ldconfig lookup
    let ldc = std::process::Command::new("sh")
        .args(["-c", "ldconfig -p 2>/dev/null | grep libgccjit"])
        .output()
        .map_err(|e| format!("Cannot run ldconfig: {}", e))?;
    if ldc.stdout.is_empty() {
        return Err("libgccjit.so not found. Install libgccjit-dev (apt) or gccjit-devel (dnf), or set GCC_BACKEND_PATH.".into());
    }
    Ok(())
}

Try / catch

// Catch libgccjit load failure at the build-script / CI level and fall back
use std::process::Command;

fn compile_with_gcc_or_fallback(crate_path: &str) -> Result<(), String> {
    let gcc_result = Command::new("rustc")
        .args(["-Z", "codegen-backend=gcc"])
        .arg(crate_path)
        .output()
        .map_err(|e| format!("Failed to invoke rustc: {}", e))?;
    if !gcc_result.status.success() {
        let stderr = String::from_utf8_lossy(&gcc_result.stderr);
        if stderr.contains("Cannot load libgccjit") {
            eprintln!("Warning: GCC backend unavailable, falling back to LLVM");
            let llvm_result = Command::new("rustc")
                .arg(crate_path)
                .output()
                .map_err(|e| e.to_string())?;
            if !llvm_result.status.success() {
                return Err(String::from_utf8_lossy(&llvm_result.stderr).to_string());
            }
        } else {
            return Err(stderr.to_string());
        }
    }
    Ok(())
}

Prevention

When it happens

Trigger: Using `-Ccodegen-backend=gcc` (or a rustc configured with the GCC backend as default) when the discovered libgccjit.so fails to dlopen: e.g. built against libstdc++.so.N that is not installed, or built for a different libgccjit soname, or compiled with a conflicting `-Ctarget-cpu`/ABI.

Common situations: A rustc_codegen_gcc toolchain installed without its runtime dependency libraries; a system upgrade that removed or bumped libstdc++/libgmp; a manually copied libgccjit.so with a broken DT_NEEDED; cross-target sysroot pointing at the wrong triplet.

Related errors


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