diff --git a/MODULE.bazel b/MODULE.bazel index bcc4ec076..42875b40f 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -40,9 +40,17 @@ osx.frameworks(names = [ "ColorSync", "CoreFoundation", "CoreGraphics", + "CoreImage", + "CoreMedia", + "CoreMIDI", "CoreServices", "CoreText", + "CoreVideo", + "DiskArbitration", "AudioToolbox", + "AVFoundation", + "AVFAudio", + "AVRouting", "CFNetwork", "FontServices", "AudioUnit", @@ -50,11 +58,19 @@ osx.frameworks(names = [ "CoreAudioTypes", "Foundation", "ImageIO", + "IOSurface", "IOKit", "Kernel", + "Metal", + "MetalKit", + "OpenGL", "OSLog", + "QuartzCore", + "ScreenCaptureKit", "Security", "SystemConfiguration", + "UniformTypeIdentifiers", + "VideoToolbox", ]) use_repo(osx, "macos_sdk") @@ -345,6 +361,23 @@ crate.annotation( inject_repo(crate, "llvm", "llvm-project", "macos_sdk") +crate.annotation( + # Provide the hermetic SDK path so the build script doesn't try to invoke an unavailable `xcrun --show-sdk-path`. + build_script_data = [ + "@macos_sdk//sysroot", + ], + build_script_env = { + "WEBRTC_SYS_DARWIN_SDK_PATH": "$(location @macos_sdk//sysroot)", + "WEBRTC_SYS_LINK_OUT_DIR": "1", + }, + crate = "webrtc-sys", + gen_build_script = "on", + patch_args = ["-p1"], + patches = [ + "//patches:webrtc-sys_hermetic_darwin_sysroot.patch", + ], +) + # Fix readme inclusions crate.annotation( crate = "windows-link", diff --git a/codex-rs/cli/BUILD.bazel b/codex-rs/cli/BUILD.bazel index 8998d759d..a8a97cef0 100644 --- a/codex-rs/cli/BUILD.bazel +++ b/codex-rs/cli/BUILD.bazel @@ -1,8 +1,9 @@ -load("//:defs.bzl", "codex_rust_crate", "multiplatform_binaries") +load("//:defs.bzl", "MACOS_WEBRTC_RUSTC_LINK_FLAGS", "codex_rust_crate", "multiplatform_binaries") codex_rust_crate( name = "cli", crate_name = "codex_cli", + rustc_flags_extra = MACOS_WEBRTC_RUSTC_LINK_FLAGS, ) multiplatform_binaries( diff --git a/codex-rs/cloud-tasks/BUILD.bazel b/codex-rs/cloud-tasks/BUILD.bazel index f6e8bfcc5..9beb5f87b 100644 --- a/codex-rs/cloud-tasks/BUILD.bazel +++ b/codex-rs/cloud-tasks/BUILD.bazel @@ -1,6 +1,7 @@ -load("//:defs.bzl", "codex_rust_crate") +load("//:defs.bzl", "MACOS_WEBRTC_RUSTC_LINK_FLAGS", "codex_rust_crate") codex_rust_crate( name = "cloud-tasks", crate_name = "codex_cloud_tasks", + rustc_flags_extra = MACOS_WEBRTC_RUSTC_LINK_FLAGS, ) diff --git a/codex-rs/realtime-webrtc/BUILD.bazel b/codex-rs/realtime-webrtc/BUILD.bazel index 3e37dd62a..1be89f035 100644 --- a/codex-rs/realtime-webrtc/BUILD.bazel +++ b/codex-rs/realtime-webrtc/BUILD.bazel @@ -1,12 +1,7 @@ -load("@rules_rust//rust:defs.bzl", "rust_library") +load("//:defs.bzl", "MACOS_WEBRTC_RUSTC_LINK_FLAGS", "codex_rust_crate") -rust_library( +codex_rust_crate( name = "realtime-webrtc", crate_name = "codex_realtime_webrtc", - crate_root = "src/lib.rs", - srcs = ["src/lib.rs"], - edition = "2024", - rustc_flags = ["--cfg=codex_bazel"], - deps = ["@crates//:thiserror"], - visibility = ["//visibility:public"], + rustc_flags_extra = MACOS_WEBRTC_RUSTC_LINK_FLAGS, ) diff --git a/codex-rs/realtime-webrtc/src/lib.rs b/codex-rs/realtime-webrtc/src/lib.rs index b6eb50000..69761ecd5 100644 --- a/codex-rs/realtime-webrtc/src/lib.rs +++ b/codex-rs/realtime-webrtc/src/lib.rs @@ -1,4 +1,4 @@ -#[cfg(all(target_os = "macos", not(codex_bazel)))] +#[cfg(target_os = "macos")] mod native; use std::fmt; @@ -31,7 +31,7 @@ pub struct StartedRealtimeWebrtcSession { } pub struct RealtimeWebrtcSessionHandle { - #[cfg(all(target_os = "macos", not(codex_bazel)))] + #[cfg(target_os = "macos")] inner: native::SessionHandle, local_audio_peak: Arc, } @@ -45,11 +45,11 @@ impl fmt::Debug for RealtimeWebrtcSessionHandle { impl RealtimeWebrtcSessionHandle { pub fn apply_answer_sdp(&self, answer_sdp: String) -> Result<()> { - #[cfg(all(target_os = "macos", not(codex_bazel)))] + #[cfg(target_os = "macos")] { self.inner.apply_answer_sdp(answer_sdp) } - #[cfg(any(not(target_os = "macos"), codex_bazel))] + #[cfg(not(target_os = "macos"))] { let _ = answer_sdp; Err(RealtimeWebrtcError::UnsupportedPlatform) @@ -57,7 +57,7 @@ impl RealtimeWebrtcSessionHandle { } pub fn close(&self) { - #[cfg(all(target_os = "macos", not(codex_bazel)))] + #[cfg(target_os = "macos")] self.inner.close(); } @@ -70,7 +70,7 @@ pub struct RealtimeWebrtcSession; impl RealtimeWebrtcSession { pub fn start() -> Result { - #[cfg(all(target_os = "macos", not(codex_bazel)))] + #[cfg(target_os = "macos")] { let started = native::start()?; Ok(StartedRealtimeWebrtcSession { @@ -82,7 +82,7 @@ impl RealtimeWebrtcSession { events: started.events, }) } - #[cfg(any(not(target_os = "macos"), codex_bazel))] + #[cfg(not(target_os = "macos"))] { Err(RealtimeWebrtcError::UnsupportedPlatform) } diff --git a/codex-rs/tui/BUILD.bazel b/codex-rs/tui/BUILD.bazel index ef6866293..33cc13343 100644 --- a/codex-rs/tui/BUILD.bazel +++ b/codex-rs/tui/BUILD.bazel @@ -1,4 +1,4 @@ -load("//:defs.bzl", "codex_rust_crate") +load("//:defs.bzl", "MACOS_WEBRTC_RUSTC_LINK_FLAGS", "codex_rust_crate") codex_rust_crate( name = "tui", @@ -23,4 +23,5 @@ codex_rust_crate( extra_binaries = [ "//codex-rs/cli:codex", ], + rustc_flags_extra = MACOS_WEBRTC_RUSTC_LINK_FLAGS, ) diff --git a/defs.bzl b/defs.bzl index a8ffaa77b..6972b65a6 100644 --- a/defs.bzl +++ b/defs.bzl @@ -31,6 +31,18 @@ WINDOWS_RUSTC_LINK_FLAGS = select({ "//conditions:default": [], }) +# libwebrtc uses Objective-C categories from native archives. Any Bazel-linked +# macOS binary/test that can pull it in must keep category symbols alive. +MACOS_WEBRTC_RUSTC_LINK_FLAGS = select({ + "@platforms//os:macos": [ + "-C", + "link-arg=-ObjC", + "-C", + "link-arg=-lc++", + ], + "//conditions:default": [], +}) + def multiplatform_binaries(name, platforms = PLATFORMS): for platform in platforms: platform_data( diff --git a/patches/BUILD.bazel b/patches/BUILD.bazel index 4db61293c..0924842e4 100644 --- a/patches/BUILD.bazel +++ b/patches/BUILD.bazel @@ -20,6 +20,7 @@ exports_files([ "v8_bazel_rules.patch", "v8_module_deps.patch", "v8_source_portability.patch", + "webrtc-sys_hermetic_darwin_sysroot.patch", "windows-link.patch", "xz_windows_stack_args.patch", "zstd-sys_windows_msvc_include_dirs.patch", diff --git a/patches/webrtc-sys_hermetic_darwin_sysroot.patch b/patches/webrtc-sys_hermetic_darwin_sysroot.patch new file mode 100644 index 000000000..c90edbd08 --- /dev/null +++ b/patches/webrtc-sys_hermetic_darwin_sysroot.patch @@ -0,0 +1,75 @@ +diff --git a/build.rs b/build.rs +index 3b4a24a..6aa06ff 100644 +--- a/build.rs ++++ b/build.rs +@@ -15,1 +15,2 @@ +-use std::path::Path; ++use std::fs; ++use std::path::Path; +@@ -118,1 +119,9 @@ +- println!("cargo:rustc-link-search=native={}", webrtc_lib.to_str().unwrap()); ++ let webrtc_link_lib = if env::var_os("WEBRTC_SYS_LINK_OUT_DIR").is_some() { ++ let out_lib = PathBuf::from(env::var_os("OUT_DIR").unwrap()).join("lib"); ++ fs::create_dir_all(&out_lib).unwrap(); ++ fs::copy(webrtc_lib.join("libwebrtc.a"), out_lib.join("libwebrtc.a")).unwrap(); ++ out_lib ++ } else { ++ webrtc_lib ++ }; ++ println!("cargo:rustc-link-search=native={}", webrtc_link_lib.to_str().unwrap()); +@@ -255,1 +264,1 @@ +- println!("cargo:rustc-link-lib=framework=Appkit"); ++ println!("cargo:rustc-link-lib=framework=AppKit"); +@@ -320,1 +329,18 @@ +- builder.warnings(false).compile("webrtcsys-cxx"); ++ builder.warnings(false).compile("webrtcsys-cxx"); ++ let cxxbridge_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()).join("cxxbridge"); ++ let cxx_header = cxxbridge_dir.join("include/rust/cxx.h"); ++ if fs::symlink_metadata(&cxx_header) ++ .is_ok_and(|metadata| metadata.file_type().is_symlink()) ++ { ++ if let Ok(header) = fs::read(&cxx_header) { ++ fs::remove_file(&cxx_header).unwrap(); ++ fs::write(&cxx_header, header).unwrap(); ++ } ++ } ++ let crate_link = cxxbridge_dir.join("crate/webrtc-sys"); ++ if fs::symlink_metadata(&crate_link) ++ .is_ok_and(|metadata| metadata.file_type().is_symlink()) ++ { ++ fs::remove_file(crate_link).unwrap(); ++ } ++ +@@ -375,1 +384,3 @@ +- println!("cargo:rustc-link-lib={}", clang_rt); ++ if env::var_os("WEBRTC_SYS_LINK_OUT_DIR").is_none() { ++ println!("cargo:rustc-link-lib={}", clang_rt); ++ } +@@ -378,6 +389,21 @@ +- let sysroot = Command::new("xcrun").args(["--sdk", sdk, "--show-sdk-path"]).output().unwrap(); +- +- let sysroot = String::from_utf8_lossy(&sysroot.stdout); +- let sysroot = sysroot.trim(); +- +- let search_dirs = Command::new("cc").arg("--print-search-dirs").output().unwrap(); ++ let sysroot = env::var("WEBRTC_SYS_DARWIN_SDK_PATH").unwrap_or_else(|_| { ++ let output = Command::new("xcrun") ++ .args(["--sdk", sdk, "--show-sdk-path"]) ++ .output() ++ .unwrap(); ++ String::from_utf8_lossy(&output.stdout).into_owned() ++ }); ++ ++ let sysroot = sysroot.as_str(); ++ let sysroot = sysroot.trim(); ++ builder.flag(format!("-F{sysroot}/System/Library/Frameworks")); ++ builder.define("__APPLICATIONSERVICES__", None); ++ builder.flag("-include"); ++ builder.flag("CoreGraphics/CoreGraphics.h"); ++ builder.include(format!("{sysroot}/usr/include")); ++ ++ let cc = env::var("CC").unwrap_or_else(|_| "cc".to_string()); ++ let search_dirs = Command::new(cc) ++ .arg("--print-search-dirs") ++ .output() ++ .unwrap();