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
- Recompile the C static library without -flto (e.g., remove -flto from CFLAGS/CXXFLAGS) and rebuild the Rust cdylib.
- If you control the C build, produce two variants: an LTO version for C-only builds and a non-LTO version for Rust interop.
- If using a system-provided static lib, check for a non-LTO variant or build from source without LTO.
- 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
- Compile C static libraries with -fno-lto when they will be linked into a Rust cdylib.
- Check for LLVM bitcode with: objcopy --dump-section .llvm.lto=/dev/null libfoo.a /dev/null or scan for the BC magic bytes.
- If using clang, pass -fno-lto or -emit-obj to produce machine code, not bitcode.
- Document the no-LTO requirement for C dependencies in your project's build instructions.
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
- LTO object in C static library is not supported
- from rlib
- from uncompressed file
- Accessing live loans requires `-Zpolonius=next`
- archive member at offset
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)