@@ -40,6 +40,34 @@ fn emit_rerun_instructions(builddir: Option<&str>) {
4040 }
4141}
4242
43+ /// Find the newest clang resource directory on the system.
44+ ///
45+ /// Ubuntu 24.04 ships libclang-18 whose built-in headers (stdatomic.h,
46+ /// mmintrin.h) are broken. CI jobs install a newer clang (e.g. clang-20)
47+ /// whose resource directory at /usr/lib/llvm-20/lib/clang/20 has working
48+ /// headers. We pass -resource-dir to bindgen's clang so it picks up those
49+ /// headers instead of the broken libclang-18 ones.
50+ fn newest_clang_resource_dir ( ) -> Option < PathBuf > {
51+ let base = Path :: new ( "/usr/lib" ) ;
52+ let mut best: Option < ( u32 , PathBuf ) > = None ;
53+ for entry in std:: fs:: read_dir ( base) . ok ( ) ?. flatten ( ) {
54+ let name = entry. file_name ( ) ;
55+ let name = name. to_string_lossy ( ) ;
56+ if let Some ( ver_str) = name. strip_prefix ( "llvm-" )
57+ && let Ok ( ver) = ver_str. parse :: < u32 > ( )
58+ {
59+ // Resource dir: /usr/lib/llvm-<N>/lib/clang/<N>
60+ let resource_dir = entry. path ( ) . join ( "lib" ) . join ( "clang" ) . join ( ver_str) ;
61+ if resource_dir. join ( "include" ) . is_dir ( )
62+ && best. as_ref ( ) . map_or ( true , |( v, _) | ver > * v)
63+ {
64+ best = Some ( ( ver, resource_dir) ) ;
65+ }
66+ }
67+ }
68+ best. map ( |( _, p) | p)
69+ }
70+
4371fn gil_disabled ( srcdir : & Path , builddir : Option < & str > ) -> bool {
4472 let mut candidates = Vec :: new ( ) ;
4573 if let Some ( build) = builddir {
@@ -63,6 +91,21 @@ fn generate_c_api_bindings(srcdir: &Path, builddir: Option<&str>, out_path: &Pat
6391 // Suppress all clang warnings (deprecation warnings, etc.)
6492 builder = builder. clang_arg ( "-w" ) ;
6593
94+ // Use the newest clang resource directory available on the system.
95+ // Bindgen links against whatever libclang it finds (often an older
96+ // system version), but the built-in headers in that version may be
97+ // broken (e.g. libclang-18 on Ubuntu 24.04 has broken stdatomic.h
98+ // and mmintrin.h). Overriding -resource-dir makes clang use a
99+ // newer set of built-in headers without changing which libclang.so
100+ // is loaded.
101+ if let Some ( resource_dir) = newest_clang_resource_dir ( ) {
102+ eprintln ! (
103+ "cpython-sys: using clang resource dir {}" ,
104+ resource_dir. display( )
105+ ) ;
106+ builder = builder. clang_arg ( format ! ( "-resource-dir={}" , resource_dir. display( ) ) ) ;
107+ }
108+
66109 // Tell clang the correct target triple for cross-compilation when we have
67110 // an LLVM-specific triple. Otherwise let bindgen translate Cargo's TARGET
68111 // itself (e.g. aarch64-apple-ios-sim -> arm64-apple-ios-simulator).
@@ -150,6 +193,7 @@ fn generate_c_api_bindings(srcdir: &Path, builddir: Option<&str>, out_path: &Pat
150193 for dir in include_dirs {
151194 builder = builder. clang_arg ( format ! ( "-I{}" , dir. display( ) ) ) ;
152195 }
196+
153197 builder = add_target_clang_args ( builder, builddir) ;
154198
155199 let bindings = builder
0 commit comments