rust-lang/rust · error · io::Error

LLVM bitcode object in C static library (LTO not supported)

Error message

LLVM bitcode object in C static library (LTO not supported)

What it means

Emitted by add_c_staticlib_symbols in rustc's linker code when building a cdylib that needs to export symbols from a linked C static library. The function scans archive members and checks if any start with the LLVM bitcode magic bytes BC\xc0\xde (link.rs:2831). This indicates the C static library was compiled with clang -flto and contains raw LLVM bitcode objects instead of machine code. rustc cannot extract symbols from or link LLVM bitcode in C static libraries, so compilation aborts.

Solutions

  1. Recompile the C static library without -flto (e.g., remove -flto from CFLAGS/CXXFLAGS) and rebuild the Rust cdylib.
  2. If you control the C build, produce two variants: an LTO version for C-only builds and a non-LTO version for Rust interop.
  3. If using a system-provided static lib, check for a non-LTO variant or build from source without LTO.
  4. On some systems, use -fno-lto when compiling just the static library's translation units.

Example fix

# before: C lib compiled with LTO
cmake -DCMAKE_C_FLAGS="-flto=thin" ... && make
# the resulting libfoo.a contains BC\xc0\xde members
# after: compile without LTO for Rust interop
cmake -DCMAKE_C_FLAGS="-fno-lto" ... && make
# then rebuild the Rust cdylib
Defensive patterns

Strategy: validation

Validate before calling

// Before linking, scan the C static library for LLVM bitcode members.
use std::fs;
use std::path::Path;

fn check_no_llvm_bitcode(lib_path: &Path) -> Result<(), String> {
    let data = fs::read(lib_path).map_err(|e| format!("read error: {e}"))?;
    let archive = object::read::archive::ArchiveFile::parse(&data)
        .map_err(|e| format!("archive parse error: {e}"))?;
    for member in archive.members() {
        let member = member.map_err(|e| format!("member error: {e}"))?;
        let member_data = member.data(&data).map_err(|e| format!("data error: {e}"))?;
        if member_data.starts_with(b"BC\xc0\xde") {
            return Err(format!("library contains LLVM bitcode (LTO): recompile without -flto"));
        }
    }
    Ok(())
}

Try / catch

// This error surfaces as a rustc fatal: 'failed to process C static library'.
// There is no runtime catch — the compiler aborts. Prevent it by validating
// the library before building, or by recompiling the C dependency without -flto.
// In build.rs:
fn main() {
    // ensure the C library is built without LTO
    println!("cargo:rustc-link-lib=static=foo");
}

Prevention

When it happens

Trigger: Building a Rust cdylib crate type with a C static library dependency (declared via #[link(name = "...", kind = "static")] with export_symbols enabled) where the .a file was produced by clang -flto. The NativeLibKind must be Static { export_symbols: Some(true), .. } for add_c_staticlib_symbols to be invoked (link.rs:2928).

Common situations: A C/C++ dependency built with clang -flto for performance; a system package or Homebrew formula that defaults to LTO; switching a C library's build system to enable LTO; a prebuilt vendor SDK shipped with LTO bitcode objects.

Related errors


AI-assisted analysis of rust-lang/rust@7088e4b63a (2026-08-10). Data as JSON: /api/errors/e7ec1d37c646bb5a. Report an issue: GitHub.

Appendix: source

Thrown at compiler/rustc_codegen_ssa/src/back/link.rs:2832

    out: &mut Vec<SymbolExport>,
) -> io::Result<()> {
    let file_path = find_native_static_library(lib.name.as_str(), lib.verbatim, sess);

    let archive_map = unsafe { Mmap::map(File::open(&file_path)?)? };

    let archive = object::read::archive::ArchiveFile::parse(&*archive_map)
        .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;

    for member in archive.members() {
        let member = member.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;

        let data = member
            .data(&*archive_map)
            .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;

        // clang LTO: raw LLVM bitcode
        if data.starts_with(b"BC\xc0\xde") {
            return Err(io::Error::new(
                io::ErrorKind::InvalidData,
                "LLVM bitcode object in C static library (LTO not supported)",
            ));
        }

        let object = object::File::parse(&*data)
            .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;

        // gcc / clang ELF / Mach-O LTO
        if object.sections().any(|s| {
            s.name().map(|n| n.starts_with(".gnu.lto_") || n == ".llvm.lto").unwrap_or(false)
        }) {
            return Err(io::Error::new(
                io::ErrorKind::InvalidData,
                "LTO object in C static library is not supported",
            ));
        }

View on GitHub (pinned to 7088e4b63a)