[bazel] Improve runfiles handling (#10098)

we can't use runfiles directory on Windows due to path lengths, so swap
to manifest strategy. Parsing the manifest is a bit complex and the
format is changing in Bazel upstream, so pull in the official Rust
library (via a small hack to make it importable...) and cleanup all the
associated logic to work cleanly in both bazel and cargo without extra
confusion
This commit is contained in:
zbarsky-openai
2026-01-28 19:15:44 -05:00
committed by GitHub
parent 83d7c44500
commit 8497163363
17 changed files with 203 additions and 103 deletions

View File

@@ -1,3 +1,4 @@
# Without this, Bazel will consider BUILD.bazel files in # Without this, Bazel will consider BUILD.bazel files in
# .git/sl/origbackups (which can be populated by Sapling SCM). # .git/sl/origbackups (which can be populated by Sapling SCM).
.git .git
codex-rs/target

View File

@@ -1,5 +1,7 @@
common --repo_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1 common --repo_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1
common --repo_env=BAZEL_NO_APPLE_CPP_TOOLCHAIN=1 common --repo_env=BAZEL_NO_APPLE_CPP_TOOLCHAIN=1
# Dummy xcode config so we don't need to build xcode_locator in repo rule.
common --xcode_version_config=//:disable_xcode
common --disk_cache=~/.cache/bazel-disk-cache common --disk_cache=~/.cache/bazel-disk-cache
common --repo_contents_cache=~/.cache/bazel-repo-contents-cache common --repo_contents_cache=~/.cache/bazel-repo-contents-cache
@@ -9,6 +11,9 @@ startup --experimental_remote_repo_contents_cache
common --experimental_platform_in_output_dir common --experimental_platform_in_output_dir
# Runfiles strategy rationale: codex-rs/utils/cargo-bin/README.md
common --noenable_runfiles
common --enable_platform_specific_config common --enable_platform_specific_config
# TODO(zbarsky): We need to untangle these libc constraints to get linux remote builds working. # TODO(zbarsky): We need to untangle these libc constraints to get linux remote builds working.
common:linux --host_platform=//:local common:linux --host_platform=//:local
@@ -44,4 +49,3 @@ common --jobs=30
common:remote --extra_execution_platforms=//:rbe common:remote --extra_execution_platforms=//:rbe
common:remote --remote_executor=grpcs://remote.buildbuddy.io common:remote --remote_executor=grpcs://remote.buildbuddy.io
common:remote --jobs=800 common:remote --jobs=800

View File

@@ -1,3 +1,7 @@
load("@apple_support//xcode:xcode_config.bzl", "xcode_config")
xcode_config(name = "disable_xcode")
# We mark the local platform as glibc-compatible so that rust can grab a toolchain for us. # We mark the local platform as glibc-compatible so that rust can grab a toolchain for us.
# TODO(zbarsky): Upstream a better libc constraint into rules_rust. # TODO(zbarsky): Upstream a better libc constraint into rules_rust.
# We only enable this on linux though for sanity, and because it breaks remote execution. # We only enable this on linux though for sanity, and because it breaks remote execution.

View File

@@ -27,6 +27,8 @@ register_toolchains(
"@toolchains_llvm_bootstrapped//toolchain:all", "@toolchains_llvm_bootstrapped//toolchain:all",
) )
# Needed to disable xcode...
bazel_dep(name = "apple_support", version = "2.1.0")
bazel_dep(name = "rules_cc", version = "0.2.16") bazel_dep(name = "rules_cc", version = "0.2.16")
bazel_dep(name = "rules_platform", version = "0.1.0") bazel_dep(name = "rules_platform", version = "0.1.0")
bazel_dep(name = "rules_rust", version = "0.68.1") bazel_dep(name = "rules_rust", version = "0.68.1")
@@ -90,6 +92,11 @@ crate.annotation(
inject_repo(crate, "openssl") inject_repo(crate, "openssl")
crate.annotation(
crate = "runfiles",
workspace_cargo_toml = "rust/runfiles/Cargo.toml",
)
# Fix readme inclusions # Fix readme inclusions
crate.annotation( crate.annotation(
crate = "windows-link", crate = "windows-link",

4
MODULE.bazel.lock generated
View File

@@ -21,7 +21,8 @@
"https://bcr.bazel.build/modules/apple_support/1.23.0/MODULE.bazel": "317d47e3f65b580e7fb4221c160797fda48e32f07d2dfff63d754ef2316dcd25", "https://bcr.bazel.build/modules/apple_support/1.23.0/MODULE.bazel": "317d47e3f65b580e7fb4221c160797fda48e32f07d2dfff63d754ef2316dcd25",
"https://bcr.bazel.build/modules/apple_support/1.24.1/MODULE.bazel": "f46e8ddad60aef170ee92b2f3d00ef66c147ceafea68b6877cb45bd91737f5f8", "https://bcr.bazel.build/modules/apple_support/1.24.1/MODULE.bazel": "f46e8ddad60aef170ee92b2f3d00ef66c147ceafea68b6877cb45bd91737f5f8",
"https://bcr.bazel.build/modules/apple_support/1.24.2/MODULE.bazel": "0e62471818affb9f0b26f128831d5c40b074d32e6dda5a0d3852847215a41ca4", "https://bcr.bazel.build/modules/apple_support/1.24.2/MODULE.bazel": "0e62471818affb9f0b26f128831d5c40b074d32e6dda5a0d3852847215a41ca4",
"https://bcr.bazel.build/modules/apple_support/1.24.2/source.json": "2c22c9827093250406c5568da6c54e6fdf0ef06238def3d99c71b12feb057a8d", "https://bcr.bazel.build/modules/apple_support/2.1.0/MODULE.bazel": "b15c125dabed01b6803c129cd384de4997759f02f8ec90dc5136bcf6dfc5086a",
"https://bcr.bazel.build/modules/apple_support/2.1.0/source.json": "78064cfefe18dee4faaf51893661e0d403784f3efe88671d727cdcdc67ed8fb3",
"https://bcr.bazel.build/modules/aspect_bazel_lib/2.14.0/MODULE.bazel": "2b31ffcc9bdc8295b2167e07a757dbbc9ac8906e7028e5170a3708cecaac119f", "https://bcr.bazel.build/modules/aspect_bazel_lib/2.14.0/MODULE.bazel": "2b31ffcc9bdc8295b2167e07a757dbbc9ac8906e7028e5170a3708cecaac119f",
"https://bcr.bazel.build/modules/aspect_bazel_lib/2.19.3/MODULE.bazel": "253d739ba126f62a5767d832765b12b59e9f8d2bc88cc1572f4a73e46eb298ca", "https://bcr.bazel.build/modules/aspect_bazel_lib/2.19.3/MODULE.bazel": "253d739ba126f62a5767d832765b12b59e9f8d2bc88cc1572f4a73e46eb298ca",
"https://bcr.bazel.build/modules/aspect_bazel_lib/2.19.3/source.json": "ffab9254c65ba945f8369297ad97ca0dec213d3adc6e07877e23a48624a8b456", "https://bcr.bazel.build/modules/aspect_bazel_lib/2.19.3/source.json": "ffab9254c65ba945f8369297ad97ca0dec213d3adc6e07877e23a48624a8b456",
@@ -790,6 +791,7 @@
"gimli_0.31.1": "{\"dependencies\":[{\"name\":\"alloc\",\"optional\":true,\"package\":\"rustc-std-workspace-alloc\",\"req\":\"^1.0.0\"},{\"name\":\"compiler_builtins\",\"optional\":true,\"req\":\"^0.1.2\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"default_features\":false,\"name\":\"fallible-iterator\",\"optional\":true,\"req\":\"^0.3.0\"},{\"name\":\"indexmap\",\"optional\":true,\"req\":\"^2.0.0\"},{\"default_features\":false,\"name\":\"stable_deref_trait\",\"optional\":true,\"req\":\"^1.1.0\"},{\"kind\":\"dev\",\"name\":\"test-assembler\",\"req\":\"^0.1.3\"}],\"features\":{\"default\":[\"read-all\",\"write\"],\"endian-reader\":[\"read\",\"dep:stable_deref_trait\"],\"fallible-iterator\":[\"dep:fallible-iterator\"],\"read\":[\"read-core\"],\"read-all\":[\"read\",\"std\",\"fallible-iterator\",\"endian-reader\"],\"read-core\":[],\"rustc-dep-of-std\":[\"dep:core\",\"dep:alloc\",\"dep:compiler_builtins\"],\"std\":[\"fallible-iterator?/std\",\"stable_deref_trait?/std\"],\"write\":[\"dep:indexmap\"]}}", "gimli_0.31.1": "{\"dependencies\":[{\"name\":\"alloc\",\"optional\":true,\"package\":\"rustc-std-workspace-alloc\",\"req\":\"^1.0.0\"},{\"name\":\"compiler_builtins\",\"optional\":true,\"req\":\"^0.1.2\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"default_features\":false,\"name\":\"fallible-iterator\",\"optional\":true,\"req\":\"^0.3.0\"},{\"name\":\"indexmap\",\"optional\":true,\"req\":\"^2.0.0\"},{\"default_features\":false,\"name\":\"stable_deref_trait\",\"optional\":true,\"req\":\"^1.1.0\"},{\"kind\":\"dev\",\"name\":\"test-assembler\",\"req\":\"^0.1.3\"}],\"features\":{\"default\":[\"read-all\",\"write\"],\"endian-reader\":[\"read\",\"dep:stable_deref_trait\"],\"fallible-iterator\":[\"dep:fallible-iterator\"],\"read\":[\"read-core\"],\"read-all\":[\"read\",\"std\",\"fallible-iterator\",\"endian-reader\"],\"read-core\":[],\"rustc-dep-of-std\":[\"dep:core\",\"dep:alloc\",\"dep:compiler_builtins\"],\"std\":[\"fallible-iterator?/std\",\"stable_deref_trait?/std\"],\"write\":[\"dep:indexmap\"]}}",
"git+https://github.com/JakkuSakura/tokio-tungstenite?rev=2ae536b0de793f3ddf31fc2f22d445bf1ef2023d#2ae536b0de793f3ddf31fc2f22d445bf1ef2023d_tokio-tungstenite": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"sink\",\"std\"],\"name\":\"futures-util\",\"optional\":false},{\"name\":\"log\"},{\"default_features\":true,\"features\":[],\"name\":\"native-tls-crate\",\"optional\":true,\"package\":\"native-tls\"},{\"default_features\":false,\"features\":[],\"name\":\"rustls\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"rustls-native-certs\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"rustls-pki-types\",\"optional\":true},{\"default_features\":false,\"features\":[\"io-util\"],\"name\":\"tokio\",\"optional\":false},{\"default_features\":true,\"features\":[],\"name\":\"tokio-native-tls\",\"optional\":true},{\"default_features\":false,\"features\":[],\"name\":\"tokio-rustls\",\"optional\":true},{\"default_features\":false,\"features\":[],\"name\":\"tungstenite\",\"optional\":false},{\"default_features\":true,\"features\":[],\"name\":\"webpki-roots\",\"optional\":true}],\"features\":{\"__rustls-tls\":[\"rustls\",\"rustls-pki-types\",\"tokio-rustls\",\"stream\",\"tungstenite/__rustls-tls\",\"handshake\"],\"connect\":[\"stream\",\"tokio/net\",\"handshake\"],\"default\":[\"connect\",\"handshake\"],\"handshake\":[\"tungstenite/handshake\"],\"native-tls\":[\"native-tls-crate\",\"tokio-native-tls\",\"stream\",\"tungstenite/native-tls\",\"handshake\"],\"native-tls-vendored\":[\"native-tls\",\"native-tls-crate/vendored\",\"tungstenite/native-tls-vendored\"],\"proxy\":[\"tungstenite/proxy\",\"tokio/net\",\"handshake\"],\"rustls-tls-native-roots\":[\"__rustls-tls\",\"rustls-native-certs\"],\"rustls-tls-webpki-roots\":[\"__rustls-tls\",\"webpki-roots\"],\"stream\":[],\"url\":[\"tungstenite/url\"]},\"strip_prefix\":\"\"}", "git+https://github.com/JakkuSakura/tokio-tungstenite?rev=2ae536b0de793f3ddf31fc2f22d445bf1ef2023d#2ae536b0de793f3ddf31fc2f22d445bf1ef2023d_tokio-tungstenite": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"sink\",\"std\"],\"name\":\"futures-util\",\"optional\":false},{\"name\":\"log\"},{\"default_features\":true,\"features\":[],\"name\":\"native-tls-crate\",\"optional\":true,\"package\":\"native-tls\"},{\"default_features\":false,\"features\":[],\"name\":\"rustls\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"rustls-native-certs\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"rustls-pki-types\",\"optional\":true},{\"default_features\":false,\"features\":[\"io-util\"],\"name\":\"tokio\",\"optional\":false},{\"default_features\":true,\"features\":[],\"name\":\"tokio-native-tls\",\"optional\":true},{\"default_features\":false,\"features\":[],\"name\":\"tokio-rustls\",\"optional\":true},{\"default_features\":false,\"features\":[],\"name\":\"tungstenite\",\"optional\":false},{\"default_features\":true,\"features\":[],\"name\":\"webpki-roots\",\"optional\":true}],\"features\":{\"__rustls-tls\":[\"rustls\",\"rustls-pki-types\",\"tokio-rustls\",\"stream\",\"tungstenite/__rustls-tls\",\"handshake\"],\"connect\":[\"stream\",\"tokio/net\",\"handshake\"],\"default\":[\"connect\",\"handshake\"],\"handshake\":[\"tungstenite/handshake\"],\"native-tls\":[\"native-tls-crate\",\"tokio-native-tls\",\"stream\",\"tungstenite/native-tls\",\"handshake\"],\"native-tls-vendored\":[\"native-tls\",\"native-tls-crate/vendored\",\"tungstenite/native-tls-vendored\"],\"proxy\":[\"tungstenite/proxy\",\"tokio/net\",\"handshake\"],\"rustls-tls-native-roots\":[\"__rustls-tls\",\"rustls-native-certs\"],\"rustls-tls-webpki-roots\":[\"__rustls-tls\",\"webpki-roots\"],\"stream\":[],\"url\":[\"tungstenite/url\"]},\"strip_prefix\":\"\"}",
"git+https://github.com/JakkuSakura/tungstenite-rs?rev=f514de8644821113e5d18a027d6d28a5c8cc0a6e#f514de8644821113e5d18a027d6d28a5c8cc0a6e_tungstenite": "{\"dependencies\":[{\"name\":\"bytes\"},{\"default_features\":true,\"features\":[],\"name\":\"data-encoding\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"http\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"httparse\",\"optional\":true},{\"name\":\"log\"},{\"default_features\":true,\"features\":[],\"name\":\"native-tls-crate\",\"optional\":true,\"package\":\"native-tls\"},{\"name\":\"rand\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"rustls\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"rustls-native-certs\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"rustls-pki-types\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"sha1\",\"optional\":true},{\"name\":\"thiserror\"},{\"default_features\":true,\"features\":[],\"name\":\"url\",\"optional\":true},{\"name\":\"utf-8\"},{\"default_features\":true,\"features\":[],\"name\":\"webpki-roots\",\"optional\":true}],\"features\":{\"__rustls-tls\":[\"rustls\",\"rustls-pki-types\"],\"default\":[\"handshake\"],\"handshake\":[\"data-encoding\",\"http\",\"httparse\",\"sha1\"],\"native-tls\":[\"native-tls-crate\"],\"native-tls-vendored\":[\"native-tls\",\"native-tls-crate/vendored\"],\"proxy\":[\"handshake\"],\"rustls-tls-native-roots\":[\"__rustls-tls\",\"rustls-native-certs\"],\"rustls-tls-webpki-roots\":[\"__rustls-tls\",\"webpki-roots\"],\"url\":[\"dep:url\"]},\"strip_prefix\":\"\"}", "git+https://github.com/JakkuSakura/tungstenite-rs?rev=f514de8644821113e5d18a027d6d28a5c8cc0a6e#f514de8644821113e5d18a027d6d28a5c8cc0a6e_tungstenite": "{\"dependencies\":[{\"name\":\"bytes\"},{\"default_features\":true,\"features\":[],\"name\":\"data-encoding\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"http\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"httparse\",\"optional\":true},{\"name\":\"log\"},{\"default_features\":true,\"features\":[],\"name\":\"native-tls-crate\",\"optional\":true,\"package\":\"native-tls\"},{\"name\":\"rand\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"rustls\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"rustls-native-certs\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"rustls-pki-types\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"sha1\",\"optional\":true},{\"name\":\"thiserror\"},{\"default_features\":true,\"features\":[],\"name\":\"url\",\"optional\":true},{\"name\":\"utf-8\"},{\"default_features\":true,\"features\":[],\"name\":\"webpki-roots\",\"optional\":true}],\"features\":{\"__rustls-tls\":[\"rustls\",\"rustls-pki-types\"],\"default\":[\"handshake\"],\"handshake\":[\"data-encoding\",\"http\",\"httparse\",\"sha1\"],\"native-tls\":[\"native-tls-crate\"],\"native-tls-vendored\":[\"native-tls\",\"native-tls-crate/vendored\"],\"proxy\":[\"handshake\"],\"rustls-tls-native-roots\":[\"__rustls-tls\",\"rustls-native-certs\"],\"rustls-tls-webpki-roots\":[\"__rustls-tls\",\"webpki-roots\"],\"url\":[\"dep:url\"]},\"strip_prefix\":\"\"}",
"git+https://github.com/dzbarsky/rules_rust?rev=b56cbaa8465e74127f1ea216f813cd377295ad81#b56cbaa8465e74127f1ea216f813cd377295ad81_runfiles": "{\"dependencies\":[],\"features\":{},\"strip_prefix\":\"\"}",
"git+https://github.com/helix-editor/nucleo.git?rev=4253de9faabb4e5c6d81d946a5e35a90f87347ee#4253de9faabb4e5c6d81d946a5e35a90f87347ee_nucleo": "{\"dependencies\":[{\"default_features\":true,\"features\":[],\"name\":\"nucleo-matcher\",\"optional\":false},{\"default_features\":true,\"features\":[\"send_guard\",\"arc_lock\"],\"name\":\"parking_lot\",\"optional\":false},{\"name\":\"rayon\"}],\"features\":{},\"strip_prefix\":\"\"}", "git+https://github.com/helix-editor/nucleo.git?rev=4253de9faabb4e5c6d81d946a5e35a90f87347ee#4253de9faabb4e5c6d81d946a5e35a90f87347ee_nucleo": "{\"dependencies\":[{\"default_features\":true,\"features\":[],\"name\":\"nucleo-matcher\",\"optional\":false},{\"default_features\":true,\"features\":[\"send_guard\",\"arc_lock\"],\"name\":\"parking_lot\",\"optional\":false},{\"name\":\"rayon\"}],\"features\":{},\"strip_prefix\":\"\"}",
"git+https://github.com/helix-editor/nucleo.git?rev=4253de9faabb4e5c6d81d946a5e35a90f87347ee#4253de9faabb4e5c6d81d946a5e35a90f87347ee_nucleo-matcher": "{\"dependencies\":[{\"name\":\"memchr\"},{\"default_features\":true,\"features\":[],\"name\":\"unicode-segmentation\",\"optional\":true}],\"features\":{\"default\":[\"unicode-normalization\",\"unicode-casefold\",\"unicode-segmentation\"],\"unicode-casefold\":[],\"unicode-normalization\":[],\"unicode-segmentation\":[\"dep:unicode-segmentation\"]},\"strip_prefix\":\"matcher\"}", "git+https://github.com/helix-editor/nucleo.git?rev=4253de9faabb4e5c6d81d946a5e35a90f87347ee#4253de9faabb4e5c6d81d946a5e35a90f87347ee_nucleo-matcher": "{\"dependencies\":[{\"name\":\"memchr\"},{\"default_features\":true,\"features\":[],\"name\":\"unicode-segmentation\",\"optional\":true}],\"features\":{\"default\":[\"unicode-normalization\",\"unicode-casefold\",\"unicode-segmentation\"],\"unicode-casefold\":[],\"unicode-normalization\":[],\"unicode-segmentation\":[\"dep:unicode-segmentation\"]},\"strip_prefix\":\"matcher\"}",
"git+https://github.com/nornagon/crossterm?branch=nornagon%2Fcolor-query#87db8bfa6dc99427fd3b071681b07fc31c6ce995_crossterm": "{\"dependencies\":[{\"default_features\":true,\"features\":[],\"name\":\"bitflags\",\"optional\":false},{\"default_features\":false,\"features\":[],\"name\":\"futures-core\",\"optional\":true},{\"name\":\"parking_lot\"},{\"default_features\":true,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"filedescriptor\",\"optional\":true,\"target\":\"cfg(unix)\"},{\"default_features\":false,\"features\":[],\"name\":\"libc\",\"optional\":true,\"target\":\"cfg(unix)\"},{\"default_features\":true,\"features\":[\"os-poll\"],\"name\":\"mio\",\"optional\":true,\"target\":\"cfg(unix)\"},{\"default_features\":false,\"features\":[\"std\",\"stdio\",\"termios\"],\"name\":\"rustix\",\"optional\":false,\"target\":\"cfg(unix)\"},{\"default_features\":true,\"features\":[],\"name\":\"signal-hook\",\"optional\":true,\"target\":\"cfg(unix)\"},{\"default_features\":true,\"features\":[\"support-v1_0\"],\"name\":\"signal-hook-mio\",\"optional\":true,\"target\":\"cfg(unix)\"},{\"default_features\":true,\"features\":[],\"name\":\"crossterm_winapi\",\"optional\":true,\"target\":\"cfg(windows)\"},{\"default_features\":true,\"features\":[\"winuser\",\"winerror\"],\"name\":\"winapi\",\"optional\":true,\"target\":\"cfg(windows)\"}],\"features\":{\"bracketed-paste\":[],\"default\":[\"bracketed-paste\",\"windows\",\"events\"],\"event-stream\":[\"dep:futures-core\",\"events\"],\"events\":[\"dep:mio\",\"dep:signal-hook\",\"dep:signal-hook-mio\"],\"serde\":[\"dep:serde\",\"bitflags/serde\"],\"use-dev-tty\":[\"filedescriptor\",\"rustix/process\"],\"windows\":[\"dep:winapi\",\"dep:crossterm_winapi\"]},\"strip_prefix\":\"\"}", "git+https://github.com/nornagon/crossterm?branch=nornagon%2Fcolor-query#87db8bfa6dc99427fd3b071681b07fc31c6ce995_crossterm": "{\"dependencies\":[{\"default_features\":true,\"features\":[],\"name\":\"bitflags\",\"optional\":false},{\"default_features\":false,\"features\":[],\"name\":\"futures-core\",\"optional\":true},{\"name\":\"parking_lot\"},{\"default_features\":true,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"filedescriptor\",\"optional\":true,\"target\":\"cfg(unix)\"},{\"default_features\":false,\"features\":[],\"name\":\"libc\",\"optional\":true,\"target\":\"cfg(unix)\"},{\"default_features\":true,\"features\":[\"os-poll\"],\"name\":\"mio\",\"optional\":true,\"target\":\"cfg(unix)\"},{\"default_features\":false,\"features\":[\"std\",\"stdio\",\"termios\"],\"name\":\"rustix\",\"optional\":false,\"target\":\"cfg(unix)\"},{\"default_features\":true,\"features\":[],\"name\":\"signal-hook\",\"optional\":true,\"target\":\"cfg(unix)\"},{\"default_features\":true,\"features\":[\"support-v1_0\"],\"name\":\"signal-hook-mio\",\"optional\":true,\"target\":\"cfg(unix)\"},{\"default_features\":true,\"features\":[],\"name\":\"crossterm_winapi\",\"optional\":true,\"target\":\"cfg(windows)\"},{\"default_features\":true,\"features\":[\"winuser\",\"winerror\"],\"name\":\"winapi\",\"optional\":true,\"target\":\"cfg(windows)\"}],\"features\":{\"bracketed-paste\":[],\"default\":[\"bracketed-paste\",\"windows\",\"events\"],\"event-stream\":[\"dep:futures-core\",\"events\"],\"events\":[\"dep:mio\",\"dep:signal-hook\",\"dep:signal-hook-mio\"],\"serde\":[\"dep:serde\",\"bitflags/serde\"],\"use-dev-tty\":[\"filedescriptor\",\"rustix/process\"],\"windows\":[\"dep:winapi\",\"dep:crossterm_winapi\"]},\"strip_prefix\":\"\"}",

7
codex-rs/Cargo.lock generated
View File

@@ -1975,7 +1975,7 @@ name = "codex-utils-cargo-bin"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"assert_cmd", "assert_cmd",
"path-absolutize", "runfiles",
"thiserror 2.0.17", "thiserror 2.0.17",
] ]
@@ -6592,6 +6592,11 @@ dependencies = [
"zeroize", "zeroize",
] ]
[[package]]
name = "runfiles"
version = "0.1.0"
source = "git+https://github.com/dzbarsky/rules_rust?rev=b56cbaa8465e74127f1ea216f813cd377295ad81#b56cbaa8465e74127f1ea216f813cd377295ad81"
[[package]] [[package]]
name = "rustc-demangle" name = "rustc-demangle"
version = "0.1.25" version = "0.1.25"

View File

@@ -186,6 +186,7 @@ regex = "1.12.2"
regex-lite = "0.1.8" regex-lite = "0.1.8"
reqwest = "0.12" reqwest = "0.12"
rmcp = { version = "0.12.0", default-features = false } rmcp = { version = "0.12.0", default-features = false }
runfiles = { git = "https://github.com/dzbarsky/rules_rust", rev = "b56cbaa8465e74127f1ea216f813cd377295ad81" }
schemars = "0.8.22" schemars = "0.8.22"
seccompiler = "0.5.0" seccompiler = "0.5.0"
sentry = "0.46.0" sentry = "0.46.0"

View File

@@ -16,7 +16,7 @@ use wiremock::matchers::path;
fn repo_root() -> std::path::PathBuf { fn repo_root() -> std::path::PathBuf {
#[expect(clippy::expect_used)] #[expect(clippy::expect_used)]
find_resource!(".").expect("failed to resolve repo root") codex_utils_cargo_bin::repo_root().expect("failed to resolve repo root")
} }
fn cli_responses_fixture() -> std::path::PathBuf { fn cli_responses_fixture() -> std::path::PathBuf {

View File

@@ -1,5 +1,4 @@
#![allow(clippy::unwrap_used, clippy::expect_used)] #![allow(clippy::unwrap_used, clippy::expect_used)]
use codex_utils_cargo_bin::find_resource;
use core_test_support::responses::ev_completed; use core_test_support::responses::ev_completed;
use core_test_support::responses::mount_sse_once_match; use core_test_support::responses::mount_sse_once_match;
use core_test_support::responses::sse; use core_test_support::responses::sse;
@@ -11,7 +10,7 @@ use wiremock::matchers::header;
async fn exec_uses_codex_api_key_env_var() -> anyhow::Result<()> { async fn exec_uses_codex_api_key_env_var() -> anyhow::Result<()> {
let test = test_codex_exec(); let test = test_codex_exec();
let server = start_mock_server().await; let server = start_mock_server().await;
let repo_root = find_resource!(".")?; let repo_root = codex_utils_cargo_bin::repo_root()?;
mount_sse_once_match( mount_sse_once_match(
&server, &server,

View File

@@ -113,7 +113,7 @@ fn exec_fixture() -> anyhow::Result<std::path::PathBuf> {
} }
fn exec_repo_root() -> anyhow::Result<std::path::PathBuf> { fn exec_repo_root() -> anyhow::Result<std::path::PathBuf> {
Ok(find_resource!(".")?) Ok(codex_utils_cargo_bin::repo_root()?)
} }
#[test] #[test]

View File

@@ -3,4 +3,10 @@ load("//:defs.bzl", "codex_rust_crate")
codex_rust_crate( codex_rust_crate(
name = "cargo-bin", name = "cargo-bin",
crate_name = "codex_utils_cargo_bin", crate_name = "codex_utils_cargo_bin",
compile_data = ["repo_root.marker"],
lib_data_extra = ["repo_root.marker"],
test_data_extra = ["repo_root.marker"],
rustc_env = {
"CODEX_REPO_ROOT_MARKER": "$(rlocationpath :repo_root.marker)",
},
) )

View File

@@ -9,5 +9,5 @@ workspace = true
[dependencies] [dependencies]
assert_cmd = { workspace = true } assert_cmd = { workspace = true }
path-absolutize = { workspace = true } runfiles = { workspace = true }
thiserror = { workspace = true } thiserror = { workspace = true }

View File

@@ -0,0 +1,20 @@
# codex-utils-cargo-bin runfiles strategy
We disable the directory-based runfiles strategy and rely on the manifest
strategy across all platforms. This avoids Windows path length issues and keeps
behavior consistent in local and remote builds on all platforms. Bazel sets
`RUNFILES_MANIFEST_FILE`, and the `codex-utils-cargo-bin` helpers use the
`runfiles` crate to resolve runfiles via that manifest.
Function behavior:
- `cargo_bin`: reads `CARGO_BIN_EXE_*` environment variables (set by Cargo or
Bazel) and resolves them via the runfiles manifest when `RUNFILES_MANIFEST_FILE`
is present. When not under runfiles, it only accepts absolute paths from
`CARGO_BIN_EXE_*` and returns an error otherwise.
- `find_resource!`: used by tests to locate fixtures. It chooses the Bazel
runfiles resolution path when `RUNFILES_MANIFEST_FILE` is set, otherwise it
falls back to a `CARGO_MANIFEST_DIR`-relative path for Cargo runs.
Background:
- https://bazel.build/docs/runfiles
- https://bazel.build/docs/runfiles#runfiles-manifest

View File

@@ -0,0 +1 @@

View File

@@ -1,7 +1,12 @@
use std::ffi::OsString; use std::ffi::OsString;
use std::io;
use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
pub use path_absolutize; pub use runfiles;
/// Bazel sets this when runfiles directories are disabled, which we do on all platforms for consistency.
const RUNFILES_MANIFEST_ONLY_ENV: &str = "RUNFILES_MANIFEST_ONLY";
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum CargoBinError { pub enum CargoBinError {
@@ -27,10 +32,9 @@ pub enum CargoBinError {
/// Returns an absolute path to a binary target built for the current test run. /// Returns an absolute path to a binary target built for the current test run.
/// ///
/// In `cargo test`, `CARGO_BIN_EXE_*` env vars are absolute, but Buck2 may set /// In `cargo test`, `CARGO_BIN_EXE_*` env vars are absolute.
/// them to project-relative paths (e.g. `buck-out/...`). Those paths break if a /// In `bazel test`, `CARGO_BIN_EXE_*` env vars are rlocationpaths, intended to be consumed by `rlocation`.
/// test later changes its working directory. This helper makes the path /// This helper allows callers to transparently support both.
/// absolute up-front so callers can safely `chdir` afterwards.
pub fn cargo_bin(name: &str) -> Result<PathBuf, CargoBinError> { pub fn cargo_bin(name: &str) -> Result<PathBuf, CargoBinError> {
let env_keys = cargo_bin_env_keys(name); let env_keys = cargo_bin_env_keys(name);
for key in &env_keys { for key in &env_keys {
@@ -38,16 +42,20 @@ pub fn cargo_bin(name: &str) -> Result<PathBuf, CargoBinError> {
return resolve_bin_from_env(key, value); return resolve_bin_from_env(key, value);
} }
} }
match assert_cmd::Command::cargo_bin(name) { match assert_cmd::Command::cargo_bin(name) {
Ok(cmd) => { Ok(cmd) => {
let abs = absolutize_from_buck_or_cwd(PathBuf::from(cmd.get_program()))?; let mut path = PathBuf::from(cmd.get_program());
if abs.exists() { if !path.is_absolute() {
Ok(abs) path = std::env::current_dir()
.map_err(|source| CargoBinError::CurrentDir { source })?
.join(path);
}
if path.exists() {
Ok(path)
} else { } else {
Err(CargoBinError::ResolvedPathDoesNotExist { Err(CargoBinError::ResolvedPathDoesNotExist {
key: "assert_cmd::Command::cargo_bin".to_owned(), key: "assert_cmd::Command::cargo_bin".to_owned(),
path: abs, path,
}) })
} }
} }
@@ -72,6 +80,31 @@ fn cargo_bin_env_keys(name: &str) -> Vec<String> {
keys keys
} }
pub fn runfiles_available() -> bool {
std::env::var_os(RUNFILES_MANIFEST_ONLY_ENV).is_some()
}
fn resolve_bin_from_env(key: &str, value: OsString) -> Result<PathBuf, CargoBinError> {
let raw = PathBuf::from(&value);
if runfiles_available() {
let runfiles = runfiles::Runfiles::create().map_err(|err| CargoBinError::CurrentExe {
source: std::io::Error::other(err),
})?;
if let Some(resolved) = runfiles::rlocation!(runfiles, &raw)
&& resolved.exists()
{
return Ok(resolved);
}
} else if raw.is_absolute() && raw.exists() {
return Ok(raw);
}
Err(CargoBinError::ResolvedPathDoesNotExist {
key: key.to_owned(),
path: raw,
})
}
/// Macro that derives the path to a test resource at runtime, the value of /// Macro that derives the path to a test resource at runtime, the value of
/// which depends on whether Cargo or Bazel is being used to build and run a /// which depends on whether Cargo or Bazel is being used to build and run a
/// test. Note the return value may be a relative or absolute path. /// test. Note the return value may be a relative or absolute path.
@@ -84,97 +117,109 @@ fn cargo_bin_env_keys(name: &str) -> Vec<String> {
#[macro_export] #[macro_export]
macro_rules! find_resource { macro_rules! find_resource {
($resource:expr) => {{ ($resource:expr) => {{
// When this code is built and run with Bazel:
// - we inject `BAZEL_PACKAGE` as a compile-time environment variable
// that points to native.package_name()
// - at runtime, Bazel will set `RUNFILES_DIR` to the runfiles directory
//
// Therefore, the compile-time value of `BAZEL_PACKAGE` will always be
// included in the compiled binary (even if it is built with Cargo), but
// we only check it at runtime if `RUNFILES_DIR` is set.
let resource = std::path::Path::new(&$resource); let resource = std::path::Path::new(&$resource);
match std::env::var("RUNFILES_DIR") { if $crate::runfiles_available() {
Ok(bazel_runtime_files) => match option_env!("BAZEL_PACKAGE") { // When this code is built and run with Bazel:
Some(bazel_package) => { // - we inject `BAZEL_PACKAGE` as a compile-time environment variable
use $crate::path_absolutize::Absolutize; // that points to native.package_name()
// - at runtime, Bazel will set runfiles-related env vars
let manifest_dir = std::path::PathBuf::from(bazel_runtime_files) $crate::resolve_bazel_runfile(option_env!("BAZEL_PACKAGE"), resource)
.join("_main") } else {
.join(bazel_package) let manifest_dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
.join(resource); Ok(manifest_dir.join(resource))
// Note we also have to normalize (but not canonicalize!)
// the path for _Bazel_ because the original value ends with
// `codex-rs/exec-server/tests/common/../suite/bash`, but
// the `tests/common` folder will not exist at runtime under
// Bazel. As such, we have to normalize it before passing it
// to `dotslash fetch`.
manifest_dir.absolutize().map(|p| p.to_path_buf())
}
None => Err(std::io::Error::new(
std::io::ErrorKind::NotFound,
"BAZEL_PACKAGE not set in Bazel build",
)),
},
Err(_) => {
let manifest_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
Ok(manifest_dir.join(resource))
}
} }
}}; }};
} }
fn resolve_bin_from_env(key: &str, value: OsString) -> Result<PathBuf, CargoBinError> { pub fn resolve_bazel_runfile(
let abs = absolutize_from_buck_or_cwd(PathBuf::from(value))?; bazel_package: Option<&str>,
resource: &Path,
if abs.exists() { ) -> std::io::Result<PathBuf> {
Ok(abs) let runfiles = runfiles::Runfiles::create()
} else { .map_err(|err| std::io::Error::other(format!("failed to create runfiles: {err}")))?;
Err(CargoBinError::ResolvedPathDoesNotExist { let runfile_path = match bazel_package {
key: key.to_owned(), Some(bazel_package) => PathBuf::from("_main").join(bazel_package).join(resource),
path: abs, None => {
}) return Err(std::io::Error::new(
} std::io::ErrorKind::NotFound,
} "BAZEL_PACKAGE was not set at compile time",
));
fn absolutize_from_buck_or_cwd(path: PathBuf) -> Result<PathBuf, CargoBinError> { }
if path.is_absolute() { };
return Ok(path); let runfile_path = normalize_runfile_path(&runfile_path);
} if let Some(resolved) = runfiles::rlocation!(runfiles, &runfile_path)
&& resolved.exists()
if let Some(root) =
buck_project_root().map_err(|source| CargoBinError::CurrentExe { source })?
{ {
return Ok(root.join(path)); return Ok(resolved);
} }
let runfile_path_display = runfile_path.display();
Ok(std::env::current_dir() Err(std::io::Error::new(
.map_err(|source| CargoBinError::CurrentDir { source })? std::io::ErrorKind::NotFound,
.join(path)) format!("runfile does not exist at: {runfile_path_display}"),
))
} }
/// Best-effort attempt to find the Buck project root for the currently running pub fn resolve_cargo_runfile(resource: &Path) -> std::io::Result<PathBuf> {
/// process. let manifest_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
/// Ok(manifest_dir.join(resource))
/// Prefer this over `env!("CARGO_MANIFEST_DIR")` when running under Buck2: our }
/// Buck generator sets `CARGO_MANIFEST_DIR="."` for compilation, which makes
/// `env!("CARGO_MANIFEST_DIR")` unusable for locating workspace files. pub fn repo_root() -> io::Result<PathBuf> {
pub fn buck_project_root() -> Result<Option<PathBuf>, std::io::Error> { let marker = if runfiles_available() {
if let Some(root) = std::env::var_os("BUCK_PROJECT_ROOT") { let runfiles = runfiles::Runfiles::create()
let root = PathBuf::from(root); .map_err(|err| io::Error::other(format!("failed to create runfiles: {err}")))?;
if root.is_absolute() { let marker_path = option_env!("CODEX_REPO_ROOT_MARKER")
return Ok(Some(root)); .map(PathBuf::from)
.ok_or_else(|| {
io::Error::new(
io::ErrorKind::NotFound,
"CODEX_REPO_ROOT_MARKER was not set at compile time",
)
})?;
runfiles::rlocation!(runfiles, &marker_path).ok_or_else(|| {
io::Error::new(
io::ErrorKind::NotFound,
"repo_root.marker not available in runfiles",
)
})?
} else {
resolve_cargo_runfile(Path::new("repo_root.marker"))?
};
let mut root = marker;
for _ in 0..4 {
root = root
.parent()
.ok_or_else(|| {
io::Error::new(
io::ErrorKind::NotFound,
"repo_root.marker did not have expected parent depth",
)
})?
.to_path_buf();
}
Ok(root)
}
fn normalize_runfile_path(path: &Path) -> PathBuf {
let mut components = Vec::new();
for component in path.components() {
match component {
std::path::Component::CurDir => {}
std::path::Component::ParentDir => {
if matches!(components.last(), Some(std::path::Component::Normal(_))) {
components.pop();
} else {
components.push(component);
}
}
_ => components.push(component),
} }
} }
// Fall back to deriving the project root from the location of the test components
// runner executable: .into_iter()
// <project>/buck-out/v2/gen/.../__tests__/test-binary .fold(PathBuf::new(), |mut acc, component| {
let exe = std::env::current_exe()?; acc.push(component.as_os_str());
for ancestor in exe.ancestors() { acc
if ancestor.file_name().is_some_and(|name| name == "buck-out") { })
return Ok(ancestor.parent().map(PathBuf::from));
}
}
Ok(None)
} }

View File

@@ -36,6 +36,8 @@ def codex_rust_crate(
crate_edition = None, crate_edition = None,
build_script_data = [], build_script_data = [],
compile_data = [], compile_data = [],
lib_data_extra = [],
rustc_env = {},
deps_extra = [], deps_extra = [],
integration_deps_extra = [], integration_deps_extra = [],
integration_compile_data_extra = [], integration_compile_data_extra = [],
@@ -63,6 +65,8 @@ def codex_rust_crate(
You probably don't want this, it's only here for a single caller. You probably don't want this, it's only here for a single caller.
build_script_data: Data files exposed to the build script at runtime. build_script_data: Data files exposed to the build script at runtime.
compile_data: Non-Rust compile-time data for the library target. compile_data: Non-Rust compile-time data for the library target.
lib_data_extra: Extra runtime data for the library target.
rustc_env: Extra rustc_env entries to merge with defaults.
deps_extra: Extra normal deps beyond @crates resolution. deps_extra: Extra normal deps beyond @crates resolution.
Typically only needed when features add additional deps. Typically only needed when features add additional deps.
integration_deps_extra: Extra deps for integration tests only. integration_deps_extra: Extra deps for integration tests only.
@@ -85,7 +89,7 @@ def codex_rust_crate(
rustc_env = { rustc_env = {
"BAZEL_PACKAGE": native.package_name(), "BAZEL_PACKAGE": native.package_name(),
} } | rustc_env
binaries = DEP_DATA.get(native.package_name())["binaries"] binaries = DEP_DATA.get(native.package_name())["binaries"]
@@ -112,6 +116,7 @@ def codex_rust_crate(
deps = deps, deps = deps,
proc_macro_deps = proc_macro_deps, proc_macro_deps = proc_macro_deps,
compile_data = compile_data, compile_data = compile_data,
data = lib_data_extra,
srcs = lib_srcs, srcs = lib_srcs,
edition = crate_edition, edition = crate_edition,
rustc_env = rustc_env, rustc_env = rustc_env,
@@ -138,7 +143,7 @@ def codex_rust_crate(
for binary, main in binaries.items(): for binary, main in binaries.items():
#binary = binary.replace("-", "_") #binary = binary.replace("-", "_")
sanitized_binaries.append(binary) sanitized_binaries.append(binary)
cargo_env["CARGO_BIN_EXE_" + binary] = "$(rootpath :%s)" % binary cargo_env["CARGO_BIN_EXE_" + binary] = "$(rlocationpath :%s)" % binary
rust_binary( rust_binary(
name = binary, name = binary,
@@ -154,7 +159,7 @@ def codex_rust_crate(
for binary_label in extra_binaries: for binary_label in extra_binaries:
sanitized_binaries.append(binary_label) sanitized_binaries.append(binary_label)
binary = Label(binary_label).name binary = Label(binary_label).name
cargo_env["CARGO_BIN_EXE_" + binary] = "$(rootpath %s)" % binary_label cargo_env["CARGO_BIN_EXE_" + binary] = "$(rlocationpath %s)" % binary_label
for test in native.glob(["tests/*.rs"], allow_empty = True): for test in native.glob(["tests/*.rs"], allow_empty = True):
test_name = name + "-" + test.removeprefix("tests/").removesuffix(".rs").replace("/", "-") test_name = name + "-" + test.removeprefix("tests/").removesuffix(".rs").replace("/", "-")

View File

@@ -31,4 +31,4 @@ index a28ad50b7..af627fe50 100644
+ make_link_flags = _make_link_flags_default_direct if use_direct_link_driver else _make_link_flags_default_indirect + make_link_flags = _make_link_flags_default_direct if use_direct_link_driver else _make_link_flags_default_indirect
return (make_link_flags, get_lib_name) return (make_link_flags, get_lib_name)