rust-lang/rust · error · io::Error
LTO object in C static library is not supported
Error message
LTO object in C static library is not supported
What it means
Emitted by add_c_staticlib_symbols alongside error 167, but for a different LTO representation. After parsing each archive member as an object file, the linker checks whether any section name starts with .gnu.lto_ or equals .llvm.lto (link.rs:2842-2843). These section names indicate gcc or clang ELF/Mach-O intermediate LTO representation — the object contains linker-ir LTO data instead of final machine code. rustc's archive symbol scanner cannot handle these, so it aborts.
Solutions
- Recompile the C static library without -flto and relink the Rust cdylib.
- Check the distro build flags (e.g., Arch Linux's /etc/makepkg.conf LTOFLAGS) and disable LTO for the library in question.
- Build the dependency from source with CFLAGS="-fno-lto" if a non-LTO prebuilt variant is unavailable.
- Verify the fix with: objdump -h libfoo.a | grep lto — output should be empty.
Example fix
# before: system .a built with gcc -flto (has .gnu.lto_ sections) # after: rebuild from source without LTO CFLAGS="-fno-lto" ./configure && make # or with cmake: cmake -DCMAKE_C_FLAGS="-fno-lto" -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=OFF ..
Defensive patterns
Strategy: validation
Validate before calling
// Before linking, scan the C static library for ELF/Mach-O LTO sections.
use std::fs;
use std::path::Path;
fn check_no_elf_lto(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}"))?;
let obj = object::File::parse(member_data).map_err(|e| format!("parse error: {e}"))?;
for section in obj.sections() {
if let Ok(name) = section.name() {
if name.starts_with(".gnu.lto_") || name == ".llvm.lto" {
return Err(format!("library contains LTO section '{}': recompile without -flto", name));
}
}
}
}
Ok(())
} Try / catch
// Same as error 167 — surfaces as a rustc fatal diagnostic. // Prevent by recompiling the C dependency without -flto. // Quick check from the command line: // objdump -h libfoo.a | grep -E '\.gnu\.lto_|\.llvm\.lto' // If output is non-empty, the library has LTO sections.
Prevention
- Build C dependencies with -fno-lto or CMAKE_INTERPROCEDURAL_OPTIMIZATION=OFF.
- Check distro package build flags — some distros (Arch, Gentoo) enable LTO globally.
- Run objdump -h libfoo.a | grep lto before linking to catch LTO sections early.
- Maintain a non-LTO build variant of C libraries specifically for Rust cdylib interop.
When it happens
Trigger: Building a Rust cdylib that links a C static library compiled with gcc -flto or clang -flto where the output uses ELF/Mach-O LTO sections (rather than raw bitcode). Triggered only when crate_type is Cdylib and the lib has NativeLibKind::Static { export_symbols: Some(true), .. }.
Common situations: C/C++ dependency built with gcc -flto on Linux (producing .gnu.lto_* sections); a prebuilt .a from a distribution that enables LTO by default (e.g., some Alpine or Gentoo packages); FFIs wrapping system libraries that were built with distro-wide LTO flags.
Related errors
- LLVM bitcode object in C static library (LTO 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/3c7e04bcbf349e84.
Report an issue: GitHub.
Appendix: source
Thrown at compiler/rustc_codegen_ssa/src/back/link.rs:2845
.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",
));
}
for symbol in object.symbols() {
// The `object` crate returns `Dynamic` for ELF/Mach-O global symbols,
// but always returns `Linkage` for COFF external symbols.
// Accept both for COFF (Windows and UEFI).
let scope = symbol.scope();
if scope != object::SymbolScope::Dynamic
&& !(sess.target.binary_format == BinaryFormat::Coff
&& scope == object::SymbolScope::Linkage)
{
continue;
}
let name = match symbol.name() {View on GitHub (pinned to 7088e4b63a)