@@ -176,6 +176,8 @@ fn main() {
176176 println ! ( "cargo:rustc-link-lib=dylib=pthread" ) ;
177177 println ! ( "cargo:rustc-link-lib=dylib=m" ) ;
178178
179+ configure_hermetic_libcxx ( & mut builder, & webrtc_include) ;
180+
179181 // In order to avoid any ABI mismatches we use the sysroot's headers.
180182 add_gio_headers ( & mut builder) ;
181183
@@ -496,6 +498,71 @@ fn add_lazy_load_so(builder: &mut cc::Build, name: &str, libraries: Vec<String>)
496498 }
497499}
498500
501+ /// Compile against the same hermetic libc++ that is baked into libwebrtc.a.
502+ ///
503+ /// The Linux libwebrtc build sets `use_custom_libcxx=true`, so every std type in
504+ /// its public API lives in the `std::__Cr` ABI namespace with libc++ layouts.
505+ /// Using the host's libstdc++ here instead is not merely a mangling mismatch that
506+ /// the linker would catch: `std::span` is layout-different between the two, so a
507+ /// span handed to libwebrtc silently arrives with its pointer and size swapped.
508+ ///
509+ /// Mirrors the flags in the WebRTC checkout's `build/config/c++/BUILD.gn`. The
510+ /// matching `_LIBCPP_*` defines come from webrtc.ninja via `webrtc_defines()`.
511+ fn configure_hermetic_libcxx ( builder : & mut cc:: Build , webrtc_include : & path:: Path ) {
512+ let libcxx = webrtc_include. join ( "third_party/libc++/src/include" ) ;
513+ let libcxxabi = webrtc_include. join ( "third_party/libc++abi/src/include" ) ;
514+ if !libcxx. join ( "span" ) . exists ( ) {
515+ panic ! (
516+ "hermetic libc++ headers missing from {}.\n \
517+ This libwebrtc artifact predates use_custom_libcxx=true; rebuild it with \
518+ build_linux.sh or point LK_CUSTOM_WEBRTC at a newer one.",
519+ libcxx. display( )
520+ ) ;
521+ }
522+
523+ // Chromium's libc++ is clang-only. At _LIBCPP_ABI_VERSION 2 it marks unique_ptr
524+ // and shared_ptr __attribute__((trivial_abi)), which GCC accepts and silently
525+ // ignores (a -Wattributes warning that cc's `-w` swallows). That attribute
526+ // changes the calling convention, not just layout: libwebrtc.a returns
527+ // std::unique_ptr in a register, while a GCC caller reads it back from an sret
528+ // slot the callee never wrote, yielding a garbage pointer at the first use.
529+ if env:: var_os ( "CXX" ) . is_none ( ) {
530+ if Command :: new ( "clang++" ) . arg ( "--version" ) . output ( ) . is_err ( ) {
531+ panic ! (
532+ "clang++ is required to build webrtc-sys on Linux: libwebrtc.a is built \
533+ against Chromium's hermetic libc++, whose trivial_abi annotations GCC \
534+ ignores, which silently breaks the calling convention for std::unique_ptr \
535+ and std::shared_ptr. Install clang, or set CXX to a clang.",
536+ ) ;
537+ }
538+ builder. compiler ( "clang++" ) ;
539+ }
540+
541+ builder
542+ . flag ( "-nostdinc++" )
543+ . flag ( format ! ( "-isystem{}" , libcxx. display( ) ) )
544+ . flag ( format ! ( "-isystem{}" , libcxxabi. display( ) ) )
545+ // Holds __config_site, which pins _LIBCPP_ABI_NAMESPACE=__Cr.
546+ . include ( webrtc_include. join ( "buildtools/third_party/libc++" ) ) ;
547+
548+ // libc++/libc++abi are already archived into libwebrtc.a, so linking the
549+ // host libstdc++ on top would only add a second, incompatible stdlib.
550+ builder. cpp_link_stdlib ( None ) ;
551+
552+ // The cxx crate builds its own runtime (cxx.cc) with the host default stdlib,
553+ // so the rust::String <-> std::string conversions it exports are mangled for
554+ // libstdc++ and cannot satisfy the std::__Cr call sites in the generated
555+ // bridges. Compile a second copy with the flags above to provide those.
556+ // DEP_CXXBRIDGE1_HEADER is `cargo:HEADER` from the cxx crate: <root>/include/cxx.h.
557+ let cxx_h = env:: var ( "DEP_CXXBRIDGE1_HEADER" )
558+ . expect ( "cxx crate did not export HEADER; cannot locate its cxx.cc" ) ;
559+ let cxx_root = path:: Path :: new ( & cxx_h)
560+ . parent ( )
561+ . and_then ( path:: Path :: parent)
562+ . expect ( "unexpected DEP_CXXBRIDGE1_HEADER layout" ) ;
563+ builder. file ( cxx_root. join ( "src/cxx.cc" ) ) ;
564+ }
565+
499566fn add_gio_headers ( builder : & mut cc:: Build ) {
500567 let webrtc_dir = webrtc_sys_build:: webrtc_dir ( ) ;
501568 let target_arch = webrtc_sys_build:: target_arch ( ) ;
0 commit comments