mirror of
https://github.com/openai/codex.git
synced 2026-05-14 00:02:33 +00:00
## Why #21255 added the standalone `codex-bwrap` binary. In the Cargo build, [`pkg_config::probe("libcap")`](a736cb55a2/codex-rs/bwrap/build.rs (L37-L39)) emits `-lcap` before [`cc::Build::compile("standalone_bwrap")`](a736cb55a2/codex-rs/bwrap/build.rs (L50-L67)) adds the static bwrap archive. The Linux musl link then sees `-lcap -lstandalone_bwrap`; because static archives are resolved left-to-right, `cap_from_name` is still undefined once `standalone_bwrap` introduces that reference. The musl setup already builds `libcap.a` and exposes it through [`libcap.pc`](a736cb55a2/.github/scripts/install-musl-build-tools.sh (L78-L88)), so the failure is link ordering rather than a missing dependency. ## What changed - probe `libcap` with `cargo_metadata(false)` so `pkg-config` does not emit its link flags early - emit the discovered `libcap` search paths and libraries after `standalone_bwrap` is compiled, preserving the needed static-link order ## Verification - `cargo test -p codex-bwrap` - `cargo clippy -p codex-bwrap --all-targets` The affected Linux musl release link is exercised by CI, which is the path this fix targets.
107 lines
3.8 KiB
Rust
107 lines
3.8 KiB
Rust
use std::env;
|
|
use std::path::Path;
|
|
use std::path::PathBuf;
|
|
|
|
fn main() {
|
|
println!("cargo:rustc-check-cfg=cfg(bwrap_available)");
|
|
println!("cargo:rerun-if-env-changed=CODEX_BWRAP_SOURCE_DIR");
|
|
println!("cargo:rerun-if-env-changed=PKG_CONFIG_ALLOW_CROSS");
|
|
println!("cargo:rerun-if-env-changed=PKG_CONFIG_PATH");
|
|
println!("cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR");
|
|
println!("cargo:rerun-if-env-changed=CODEX_SKIP_BWRAP_BUILD");
|
|
|
|
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap_or_default());
|
|
let vendor_dir = manifest_dir.join("../vendor/bubblewrap");
|
|
for source in ["bubblewrap.c", "bind-mount.c", "network.c", "utils.c"] {
|
|
println!(
|
|
"cargo:rerun-if-changed={}",
|
|
vendor_dir.join(source).display()
|
|
);
|
|
}
|
|
|
|
let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap_or_default();
|
|
if target_os != "linux" || env::var_os("CODEX_SKIP_BWRAP_BUILD").is_some() {
|
|
return;
|
|
}
|
|
|
|
if let Err(err) = try_build_bwrap() {
|
|
panic!("failed to compile bubblewrap for Linux target: {err}");
|
|
}
|
|
}
|
|
|
|
fn try_build_bwrap() -> Result<(), String> {
|
|
let manifest_dir =
|
|
PathBuf::from(env::var("CARGO_MANIFEST_DIR").map_err(|err| err.to_string())?);
|
|
let out_dir = PathBuf::from(env::var("OUT_DIR").map_err(|err| err.to_string())?);
|
|
let src_dir = resolve_bwrap_source_dir(&manifest_dir)?;
|
|
let libcap = pkg_config::Config::new()
|
|
.cargo_metadata(false)
|
|
.probe("libcap")
|
|
.map_err(|err| format!("libcap not available via pkg-config: {err}"))?;
|
|
|
|
let config_h = out_dir.join("config.h");
|
|
std::fs::write(
|
|
&config_h,
|
|
r#"#pragma once
|
|
#define PACKAGE_STRING "bubblewrap built for Codex"
|
|
"#,
|
|
)
|
|
.map_err(|err| format!("failed to write {}: {err}", config_h.display()))?;
|
|
|
|
let mut build = cc::Build::new();
|
|
build
|
|
.file(src_dir.join("bubblewrap.c"))
|
|
.file(src_dir.join("bind-mount.c"))
|
|
.file(src_dir.join("network.c"))
|
|
.file(src_dir.join("utils.c"))
|
|
.include(&out_dir)
|
|
.include(&src_dir)
|
|
.define("_GNU_SOURCE", None)
|
|
// Rename `main` so the Rust wrapper can expose the Cargo-built binary.
|
|
.define("main", Some("bwrap_main"));
|
|
for include_path in libcap.include_paths {
|
|
// Use -idirafter so target sysroot headers win (musl cross builds),
|
|
// while still allowing libcap headers from the host toolchain.
|
|
build.flag(format!("-idirafter{}", include_path.display()));
|
|
}
|
|
|
|
build.compile("standalone_bwrap");
|
|
for link_path in libcap.link_paths {
|
|
println!("cargo:rustc-link-search=native={}", link_path.display());
|
|
}
|
|
for lib in libcap.libs {
|
|
println!("cargo:rustc-link-lib={lib}");
|
|
}
|
|
println!("cargo:rustc-cfg=bwrap_available");
|
|
Ok(())
|
|
}
|
|
|
|
/// Resolve the bubblewrap source directory used for build-time compilation.
|
|
///
|
|
/// Priority:
|
|
/// 1. `CODEX_BWRAP_SOURCE_DIR` points at an existing bubblewrap checkout.
|
|
/// 2. The vendored bubblewrap tree under `codex-rs/vendor/bubblewrap`.
|
|
fn resolve_bwrap_source_dir(manifest_dir: &Path) -> Result<PathBuf, String> {
|
|
if let Ok(path) = env::var("CODEX_BWRAP_SOURCE_DIR") {
|
|
let src_dir = PathBuf::from(path);
|
|
if src_dir.exists() {
|
|
return Ok(src_dir);
|
|
}
|
|
return Err(format!(
|
|
"CODEX_BWRAP_SOURCE_DIR was set but does not exist: {}",
|
|
src_dir.display()
|
|
));
|
|
}
|
|
|
|
let vendor_dir = manifest_dir.join("../vendor/bubblewrap");
|
|
if vendor_dir.exists() {
|
|
return Ok(vendor_dir);
|
|
}
|
|
|
|
Err(format!(
|
|
"expected vendored bubblewrap at {}, but it was not found.\n\
|
|
Set CODEX_BWRAP_SOURCE_DIR to an existing checkout or vendor bubblewrap under codex-rs/vendor.",
|
|
vendor_dir.display()
|
|
))
|
|
}
|