11#![ expect( clippy:: panic, reason = "panic only during build time" ) ]
22
33use std:: {
4- env,
4+ env, fs ,
55 path:: { Path , PathBuf } ,
66} ;
77
@@ -104,9 +104,10 @@ fn main() {
104104 // Include our wrapper vars.
105105 . allowlist_var ( "(__)?RS_.*" )
106106 . allowlist_var ( "(__)?UA_.*" )
107- // Explicitly set C99 standard to force Windows variants of `vsnprintf()` to conform to this
108- // standard. This also matches the expected (or supported) C standard of `open62541` itself.
109- . clang_arg ( "-std=c99" )
107+ // Explicitly set C11 standard. C11 is required for `<stdatomic.h>` with types like
108+ // `atomic_uintptr_t` used in `open62541` headers. C11 also forces Windows variants of
109+ // `vsnprintf()` to conform to the standard (as it is a superset of C99).
110+ . clang_arg ( "-std=c11" )
110111 . clang_arg ( format ! ( "-I{}" , dst_include. display( ) ) )
111112 . default_enum_style ( bindgen:: EnumVariation :: NewType {
112113 is_bitfield : false ,
@@ -216,8 +217,8 @@ fn prepare_mbedtls(src: PathBuf) -> EncryptionDst {
216217 . define ( "CMAKE_INSTALL_INCLUDEDIR" , CMAKE_INCLUDE )
217218 // Some systems (Fedora) default to `lib64/` instead of `lib/` for 64-bit libraries.
218219 . define ( "CMAKE_INSTALL_LIBDIR" , CMAKE_LIB )
219- // Use same C99 standard as is used for building `open62541`.
220- . define ( "C_STANDARD" , "99 " )
220+ // Use same C11 standard as is used for building `open62541`.
221+ . define ( "C_STANDARD" , "11 " )
221222 // Skip building binary programs unnecessary for linking library.
222223 . define ( "ENABLE_PROGRAMS" , "OFF" )
223224 // Skip building test programs that we are not going to run anyway.
@@ -266,9 +267,16 @@ fn build_open62541(src: PathBuf, encryption: Option<&EncryptionDst>) -> PathBuf
266267 . define ( "CMAKE_INSTALL_INCLUDEDIR" , CMAKE_INCLUDE )
267268 // Some systems (Fedora) default to `lib64/` instead of `lib/` for 64-bit libraries.
268269 . define ( "CMAKE_INSTALL_LIBDIR" , CMAKE_LIB )
269- // Explicitly set C99 standard to force Windows variants of `vsnprintf()` to conform to this
270+ // Explicitly set C11 standard to force Windows variants of `vsnprintf()` to conform to this
270271 // standard. This also matches the expected (or supported) C standard of `open62541` itself.
271- . define ( "C_STANDARD" , "99" )
272+ . define ( "C_STANDARD" , "11" )
273+ // Override default value `ON` of `UA_ENABLE_DEBUG_SANITIZER`.
274+ // When the build type is Debug (which is what Cargo uses for test/debug builds) on UNIX with Clang,
275+ // it automatically appends -fsanitize=address,undefined -fno-omit-frame-pointer to all C compiler flags.
276+ // This causes libopen62541.a to be compiled with ASAN+UBSAN instrumentation. The Rust toolchain then
277+ // fails to link the test binary because the Apple Clang sanitizer runtime (libclang_rt.asan_osx_dynamic.dylib etc.)
278+ // is not linked.
279+ . define ( "UA_ENABLE_DEBUG_SANITIZER" , "OFF" )
272280 // Python defaults to creating bytecode in `__pycache__` directories. During build, this may
273281 // happen when the tool `nodeset_compiler` is called. When we package a crate, builds should
274282 // never modify files outside of `OUT_DIR`, so we disable the cache to prevent this.
@@ -282,6 +290,25 @@ fn build_open62541(src: PathBuf, encryption: Option<&EncryptionDst>) -> PathBuf
282290 cmake
283291 . cflag ( "-idirafter/usr/include" )
284292 . cflag ( format ! ( "-idirafter/usr/include/{arch}-linux-gnu" ) ) ;
293+
294+ // Provide a shim for `<bits/stdio_lim.h>` which is a glibc-specific header that is not
295+ // available in musl libc. `open62541` includes it directly in `eventloop_posix.h`. The
296+ // standard constants it would define are already provided by standard headers (`<stdio.h>`
297+ // and `<limits.h>`) that are included before this file in the same translation unit.
298+ let out = PathBuf :: from ( env:: var ( "OUT_DIR" ) . expect ( "should have OUT_DIR" ) ) ;
299+ let shim_bits_dir = out. join ( "include-shim" ) . join ( "bits" ) ;
300+ fs:: create_dir_all ( & shim_bits_dir)
301+ . expect ( "should create shim include directory for musl compatibility" ) ;
302+ fs:: write (
303+ shim_bits_dir. join ( "stdio_lim.h" ) ,
304+ "/* Shim for musl libc compatibility.\n \
305+ * The glibc-specific <bits/stdio_lim.h> is not available in musl libc.\n \
306+ * The constants it defines are already provided by the standard headers\n \
307+ * (<stdio.h> and <limits.h>) included earlier in the same translation unit.\n \
308+ */\n ",
309+ )
310+ . expect ( "should write bits/stdio_lim.h shim for musl compatibility" ) ;
311+ cmake. cflag ( format ! ( "-idirafter{}" , out. join( "include-shim" ) . display( ) ) ) ;
285312 }
286313
287314 if matches ! ( env:: var( "TARGET" ) , Ok ( env) if env == "x86_64-unknown-linux-gnu" ) {
0 commit comments