@@ -10,6 +10,7 @@ fn main() {
1010 let out_path = PathBuf :: from ( env:: var ( "OUT_DIR" ) . unwrap ( ) ) ;
1111 let builddir = env:: var ( "PYTHON_BUILD_DIR" ) . ok ( ) ;
1212 emit_rerun_instructions ( builddir. as_deref ( ) ) ;
13+ prefer_newest_libclang ( ) ;
1314 if gil_disabled ( srcdir, builddir. as_deref ( ) ) {
1415 println ! ( "cargo:rustc-cfg=py_gil_disabled" ) ;
1516 }
@@ -40,6 +41,39 @@ fn emit_rerun_instructions(builddir: Option<&str>) {
4041 }
4142}
4243
44+ /// When LIBCLANG_PATH is not already set, scan /usr/lib/llvm-*/lib for the
45+ /// newest available libclang and point bindgen at it. Ubuntu 24.04 ships
46+ /// libclang-18 by default, which has broken headers (stdatomic.h, mmintrin.h).
47+ /// CI jobs that install a newer LLVM (e.g. clang-20) also get a working
48+ /// libclang in /usr/lib/llvm-20/lib -- we just need to tell bindgen about it.
49+ fn prefer_newest_libclang ( ) {
50+ if env:: var_os ( "LIBCLANG_PATH" ) . is_some ( ) {
51+ return ;
52+ }
53+ let base = Path :: new ( "/usr/lib" ) ;
54+ let mut best: Option < ( u32 , PathBuf ) > = None ;
55+ if let Ok ( entries) = std:: fs:: read_dir ( base) {
56+ for entry in entries. flatten ( ) {
57+ let name = entry. file_name ( ) ;
58+ let name = name. to_string_lossy ( ) ;
59+ if let Some ( ver_str) = name. strip_prefix ( "llvm-" ) {
60+ if let Ok ( ver) = ver_str. parse :: < u32 > ( ) {
61+ let lib_dir = entry. path ( ) . join ( "lib" ) ;
62+ if lib_dir. is_dir ( ) {
63+ if best. as_ref ( ) . map_or ( true , |( v, _) | ver > * v) {
64+ best = Some ( ( ver, lib_dir) ) ;
65+ }
66+ }
67+ }
68+ }
69+ }
70+ }
71+ if let Some ( ( ver, lib_dir) ) = best {
72+ eprintln ! ( "cpython-sys: using libclang from llvm-{ver}" ) ;
73+ env:: set_var ( "LIBCLANG_PATH" , & lib_dir) ;
74+ }
75+ }
76+
4377fn gil_disabled ( srcdir : & Path , builddir : Option < & str > ) -> bool {
4478 let mut candidates = Vec :: new ( ) ;
4579 if let Some ( build) = builddir {
@@ -151,14 +185,6 @@ fn generate_c_api_bindings(srcdir: &Path, builddir: Option<&str>, out_path: &Pat
151185 builder = builder. clang_arg ( format ! ( "-I{}" , dir. display( ) ) ) ;
152186 }
153187
154- // Provide a fallback <stdatomic.h> for libclang versions that ship a
155- // broken one (e.g. libclang-18 on Ubuntu 24.04). Using -isystem places
156- // it after -I paths but before the default system headers, so it only
157- // takes effect when the real <stdatomic.h> is unusable.
158- let fallback_dir =
159- PathBuf :: from ( env:: var ( "CARGO_MANIFEST_DIR" ) . unwrap ( ) ) . join ( "bindgen-fallback" ) ;
160- builder = builder. clang_arg ( format ! ( "-isystem{}" , fallback_dir. display( ) ) ) ;
161-
162188 builder = add_target_clang_args ( builder, builddir) ;
163189
164190 let bindings = builder
0 commit comments