diff --git a/.bazelrc b/.bazelrc index ea06d44080c0..d0a1e2b89c6e 100644 --- a/.bazelrc +++ b/.bazelrc @@ -11,6 +11,12 @@ startup --experimental_remote_repo_contents_cache common --experimental_platform_in_output_dir +# Match Cargo's MSVC static CRT policy and V8's allocator linkage. Only the +# MSVC C/C++ toolchain consumes this feature; other toolchains ignore it. +# Include host dependencies so native build tools use the same runtime. +build --features=static_link_msvcrt +build --host_features=static_link_msvcrt + build --workspace_status_command=./scripts/workspace-status.sh build:windows --workspace_status_command=./scripts/workspace-status.cmd @@ -225,5 +231,29 @@ common:v8-target-arm64 --@v8//bazel/config:v8_target_cpu=arm64 # the matching runtime objects. common:rusty-v8-upstream-libcxx --@v8//:v8_use_rusty_v8_custom_libcxx=True +# Release profile settings are also defined in codex-rs/Cargo.toml. +# Packaging extracts symbols before stripping; the Rust toolchains retain +# line tables and use split-debuginfo=off. opt mode selects Rust opt-level=3; +# Cargo release disables assertions/checks even if a smoke build overrides +# opt-level to 0, so these are explicit rather than inferred from optimization. +build:release --compilation_mode=opt +build:release --@rules_rust//rust/settings:lto=thin +build:release --@rules_rust//rust/settings:codegen_units=4 +build:release --@rules_rust//rust/settings:extra_rustc_flag=-Cdebug-assertions=no +build:release --@rules_rust//rust/settings:extra_rustc_flag=-Coverflow-checks=no +# Match observed Cargo 1.95 build-tool commands: opt-level=0, assertions off, +# and rustc's non-incremental default of 16 codegen units (not target's 4). +build:release --@rules_rust//rust/settings:extra_exec_rustc_flag=-Copt-level=0 +build:release --@rules_rust//rust/settings:extra_exec_rustc_flag=-Ccodegen-units=16 +build:release --@rules_rust//rust/settings:extra_exec_rustc_flag=-Cdebug-assertions=no +build:release --@rules_rust//rust/settings:extra_exec_rustc_flag=-Coverflow-checks=no + +# Compatibility: Cargo build scripts consume the Rust profile, including debug +# info, and choose their native optimization. Preserve explicit user C/C++ flags. +# Opt in for target and host dependencies; normal Bazel builds keep defaults. +build:release --features=cargo-release-profile +build:release --host_features=cargo-release-profile +# Bubblewrap and voice set release options on their own native rules. + # Optional per-user local overrides. try-import %workspace%/user.bazelrc diff --git a/MODULE.bazel b/MODULE.bazel index c7cbfee19dec..ed8303b1d90d 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -207,14 +207,16 @@ rules_rust.patch( # Carry the OpenAI setup fix that makes build-script tools available # through their runfiles after the rules_rs upgrade. "//patches:rules_rust_build_script_tools_transition.patch", + # Opt-in release profile compatibility for native Cargo build scripts. + "//patches:rules_rust_release_build_script_profile.patch", # Prefer Rust's direct linker for Windows/MSVC and keep hermetic # LLVM's non-.lib runtime artifacts compatible with it. "//patches:rules_rust_windows_msvc_direct_link_args.patch", # Skip transient native-Windows linker outputs while consolidating # dependency search paths. "//patches:rules_rust_windows_process_wrapper_skip_temp_outputs.patch", - # Group build-script argument files to avoid Windows command-line limits. - "//patches:rules_rust_group_build_script_arg_files.patch", + # Spill wrapper arguments to a params file to avoid Windows command-line limits. + "//patches:rules_rust_process_wrapper_param_file.patch", "//patches:rules_rust_windows_execroot_separators.patch", "//patches:rules_rust_compiler_thp.patch", ], @@ -292,9 +294,19 @@ nightly_rust.repository_set( ) use_repo(nightly_rust, "rust_toolchains") +# Match Cargo's MSVC static CRT policy for target and host dependencies. V8's +# allocator shim must not also import the dynamic UCRT. Selecting by target +# triple applies to cross builds without affecting Windows GNU, Linux or macOS. +MSVC_RUSTC_FLAGS = { + "aarch64-pc-windows-msvc": ["-Ctarget-feature=+crt-static"], + "x86_64-pc-windows-msvc": ["-Ctarget-feature=+crt-static"], +} + toolchains = use_extension("@rules_rs//rs/toolchains:module_extension.bzl", "toolchains") toolchains.toolchain( edition = "2024", + extra_exec_rustc_flags = MSVC_RUSTC_FLAGS, + extra_rustc_flags = MSVC_RUSTC_FLAGS, version = "1.95.0", ) use_repo(toolchains, "default_rust_toolchains") @@ -592,6 +604,13 @@ inject_repo(crate, "v8_targets") llvm = use_extension("@llvm//extensions:llvm.bzl", "llvm") use_repo(llvm, "llvm-project") +crate.annotation( + # Disable SQLite intrinsics that can crash at startup on older x64 Windows CPUs. + build_script_env_select = { + "x86_64-pc-windows-msvc": '{"LIBSQLITE3_FLAGS": "SQLITE_DISABLE_INTRINSIC"}', + }, + crate = "libsqlite3-sys", +) crate.annotation( # Provide the hermetic SDK path so the build script doesn't try to invoke an unhermetic `xcrun --show-sdk-path`. build_script_data = [ diff --git a/codex-rs/app-server-client/src/lib.rs b/codex-rs/app-server-client/src/lib.rs index df5dc3e99f75..ca41cb0037b8 100644 --- a/codex-rs/app-server-client/src/lib.rs +++ b/codex-rs/app-server-client/src/lib.rs @@ -1,3 +1,7 @@ +// Release builds exceed rustc's default query depth when laying out the async +// MessageProcessor::handle_initialized_client_request future. +#![recursion_limit = "256"] + //! Shared in-process app-server client facade for CLI surfaces. //! //! This crate wraps [`codex_app_server::in_process`] behind a single async API diff --git a/codex-rs/bwrap/BUILD.bazel b/codex-rs/bwrap/BUILD.bazel index f58d703ef9ec..b1b932ac4885 100644 --- a/codex-rs/bwrap/BUILD.bazel +++ b/codex-rs/bwrap/BUILD.bazel @@ -35,6 +35,11 @@ genrule( visibility = ["//codex-rs/linux-sandbox:__pkg__"], ) +config_setting( + name = "optimized", + values = {"compilation_mode": "opt"}, +) + cc_library( name = "bwrap-ffi", srcs = ["//codex-rs/vendor:bubblewrap_c_sources"], @@ -45,7 +50,16 @@ cc_library( copts = [ "-D_GNU_SOURCE", "-Dmain=bwrap_main", - ], + ] + select({ + # Cargo cc-rs uses release OPT_LEVEL=3 and DEBUG=true, without + # the C toolchain's default NDEBUG; retain native symbols for packaging. + ":optimized": [ + "-O3", + "-g", + "-UNDEBUG", + ], + "//conditions:default": [], + }), includes = ["."], target_compatible_with = ["@platforms//os:linux"], visibility = ["//visibility:private"], diff --git a/codex-rs/exec/src/main.rs b/codex-rs/exec/src/main.rs index 61eaecdd0a85..69d432acc090 100644 --- a/codex-rs/exec/src/main.rs +++ b/codex-rs/exec/src/main.rs @@ -1,3 +1,7 @@ +// Release builds exceed rustc's default query depth when laying out the async +// MessageProcessor::handle_initialized_client_request future. +#![recursion_limit = "256"] + //! Entry-point for the `codex-exec` binary. //! //! When this CLI is invoked normally, it parses the standard `codex-exec` CLI diff --git a/codex-rs/tui/src/main.rs b/codex-rs/tui/src/main.rs index 5a196d614a92..789c7f15f208 100644 --- a/codex-rs/tui/src/main.rs +++ b/codex-rs/tui/src/main.rs @@ -1,3 +1,7 @@ +// Release builds exceed rustc's default query depth when laying out the async +// MessageProcessor::handle_initialized_client_request future. +#![recursion_limit = "256"] + use clap::Parser; use codex_arg0::Arg0DispatchPaths; use codex_arg0::arg0_dispatch_or_else; diff --git a/defs.bzl b/defs.bzl index 8d1b1a378fe6..a297207b8662 100644 --- a/defs.bzl +++ b/defs.bzl @@ -5,8 +5,9 @@ load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_library", "rust_proc_mac load("//bazel/rules/testing:foreign_platform_binary.bzl", "foreign_platform_binary") load("//bazel/rules/testing/wine:wine_runtime.bzl", "WINE_TEST_TARGET_COMPATIBLE_WITH", "wine_test_runtime") -# Match Cargo's Windows linker behavior so Bazel-built binaries and tests use -# the same stack reserve on both Windows ABIs and resolve UCRT imports on MSVC. +# Reserve 8 MiB of stack on Windows and statically link the CRT on MSVC. +# V8's x64 allocator shim defines malloc/free; importing them from dynamic UCRT +# as well replaces the import thunks during linking. WINDOWS_GNULLVM_RUSTC_LINK_FLAGS = [ "-C", "link-arg=-Wl,--stack,8388608", # 8 MiB @@ -18,9 +19,7 @@ WINDOWS_RUSTC_LINK_FLAGS = select({ "-C", "link-arg=/STACK:8388608", # 8 MiB "-C", - "link-arg=/NODEFAULTLIB:libucrt.lib", - "-C", - "link-arg=ucrt.lib", + "target-feature=+crt-static", ], "//conditions:default": [], }) @@ -414,8 +413,8 @@ def codex_rust_crate( crate_root = main, deps = all_crate_deps() + maybe_deps + deps_extra, edition = crate_edition, - # Keep per-binary Cargo link behavior scoped to the matching - # generated rust_binary instead of leaking it to sibling binaries. + # Scope each binary's compile data and linker flags to its generated + # rust_binary so they do not affect sibling binaries. compile_data = binary_compile_data_extra.get(binary, []), rustc_flags = rustc_flags_extra + binary_rustc_flags_extra.get(binary, []) + WINDOWS_RUSTC_LINK_FLAGS, rustc_env = rustc_env, diff --git a/patches/BUILD.bazel b/patches/BUILD.bazel index 6fd6aded05a4..13ea7919ebff 100644 --- a/patches/BUILD.bazel +++ b/patches/BUILD.bazel @@ -6,7 +6,8 @@ exports_files([ "llvm_windows_mingw_compat.patch", "rules_rust_build_script_tools_transition.patch", "rules_rust_compiler_thp.patch", - "rules_rust_group_build_script_arg_files.patch", + "rules_rust_process_wrapper_param_file.patch", + "rules_rust_release_build_script_profile.patch", "rules_rust_windows_execroot_separators.patch", "rules_rust_windows_msvc_direct_link_args.patch", "rules_rust_windows_process_wrapper_skip_temp_outputs.patch", diff --git a/patches/rules_rust_group_build_script_arg_files.patch b/patches/rules_rust_group_build_script_arg_files.patch deleted file mode 100644 index 5e65873ba529..000000000000 --- a/patches/rules_rust_group_build_script_arg_files.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/rust/private/rustc.bzl b/rust/private/rustc.bzl ---- a/rust/private/rustc.bzl -+++ b/rust/private/rustc.bzl -@@ -1125,5 +1125,7 @@ - for build_env_file in build_env_files: - process_wrapper_flags.add("--env-file", build_env_file) - -- process_wrapper_flags.add_all(build_flags_files, before_each = "--arg-file") -+ # The wrapper accepts multiple files per flag. Reduce native Windows -+ # command-line length without changing the files or their order. -+ process_wrapper_flags.add_all("--arg-file", build_flags_files) - diff --git a/patches/rules_rust_process_wrapper_param_file.patch b/patches/rules_rust_process_wrapper_param_file.patch new file mode 100644 index 000000000000..969357eaf1f7 --- /dev/null +++ b/patches/rules_rust_process_wrapper_param_file.patch @@ -0,0 +1,38 @@ +diff --git a/rust/private/rustc.bzl b/rust/private/rustc.bzl +--- a/rust/private/rustc.bzl ++++ b/rust/private/rustc.bzl +@@ -1121,6 +1121,9 @@ + + # Wrapper args first + process_wrapper_flags = ctx.actions.args() ++ # Build-script file paths can exceed Windows' command-line limit by themselves. ++ process_wrapper_flags.set_param_file_format("multiline") ++ process_wrapper_flags.use_param_file("@%s") + + for build_env_file in build_env_files: + process_wrapper_flags.add("--env-file", build_env_file) +diff --git a/util/process_wrapper/options.rs b/util/process_wrapper/options.rs +--- a/util/process_wrapper/options.rs ++++ b/util/process_wrapper/options.rs +@@ -136,10 +136,17 @@ + &mut require_explicit_unstable_features, + ); + +- let mut child_args = match flags +- .parse(env::args().collect()) +- .map_err(OptionError::FlagError)? +- { ++ let mut args: Vec = env::args().collect(); ++ // Bazel may spill the leading wrapper arguments to a multiline params file. ++ // Read them verbatim; child rustc @files after `--` are handled separately. ++ if let Some(path) = args.get(1).and_then(|arg| arg.strip_prefix('@')) { ++ let contents = std::fs::read_to_string(path).map_err(|err| { ++ OptionError::Generic(format!("reading wrapper arguments from {path:?}: {err}")) ++ })?; ++ args.splice(1..2, contents.lines().map(str::to_owned)); ++ } ++ ++ let mut child_args = match flags.parse(args).map_err(OptionError::FlagError)? { + ParseOutcome::Help(help) => { + eprintln!("{help}"); + exit(0); diff --git a/patches/rules_rust_release_build_script_profile.patch b/patches/rules_rust_release_build_script_profile.patch new file mode 100644 index 000000000000..a849512e9a38 --- /dev/null +++ b/patches/rules_rust_release_build_script_profile.patch @@ -0,0 +1,118 @@ +--- a/cargo/private/cargo_build_script.bzl ++++ b/cargo/private/cargo_build_script.bzl +@@ -3,6 +3,7 @@ + load("@apple_support//lib:apple_support.bzl", "apple_support") + load("@bazel_skylib//lib:paths.bzl", "paths") + load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo") ++load("@platforms//host:constraints.bzl", "HOST_CONSTRAINTS") + load("@rules_cc//cc:action_names.bzl", "ACTION_NAMES") + load("@rules_cc//cc/common:cc_common.bzl", "cc_common") + load("//rust:defs.bzl", "rust_common") +@@ -11,6 +12,7 @@ + # buildifier: disable=bzl-visibility + load( + "//rust/private:rustc.bzl", ++ "collect_extra_rustc_flags", + "get_compilation_mode_opts", + "get_linker_and_args", + ) +@@ -23,6 +25,7 @@ + "expand_dict_value_locations", + "find_cc_toolchain", + "find_toolchain", ++ "is_exec_configuration", + _name_to_crate_name = "name_to_crate_name", + ) + +@@ -66,6 +69,43 @@ + }, + executable = True, + ) ++ ++def _release_user_opts(ctx, flags): ++ # Bazel 9.2's default exec transition appends -g0 to host copts/cxxopts on ++ # non-Windows servers. Remove only that suffix; preserve explicit -g0. ++ # https://github.com/bazelbuild/bazel/blob/9.2.0/src/main/starlark/builtins_bzl/common/builtin_exec_platforms.bzl ++ if is_exec_configuration(ctx) and "@platforms//os:windows" not in HOST_CONSTRAINTS and flags and flags[-1] == "-g0": ++ return flags[:-1] ++ return flags ++ ++def _cargo_profile_native_flags(flags): ++ # Let cc-rs/cmake derive optimization and debug info from Cargo's profile. ++ # Filter toolchain defaults only; explicit user flags are appended afterwards. ++ profile_defaults = [ ++ "-O0", ++ "-O1", ++ "-O2", ++ "-O3", ++ "-Og", ++ "-Os", ++ "-Oz", ++ "-Ofast", ++ "-g0", ++ "-DNDEBUG", ++ "-DNDEBUG=1", ++ "/Od", ++ "/O1", ++ "/O2", ++ "/Ox", ++ "/Ob0", ++ "/Ob1", ++ "/Ob2", ++ "/Ob3", ++ "/Oi", ++ "/DNDEBUG", ++ "/DNDEBUG=1", ++ ] ++ return [flag for flag in flags if flag not in profile_defaults] + + def get_cc_compile_args_and_env(cc_toolchain, feature_configuration): + """Gather cc environment variables from the given `cc_toolchain` +@@ -469,6 +509,22 @@ + env["CARGO_PKG_VERSION_PRE"] = patch[1] if len(patch) > 1 else "" + env["CARGO_PKG_VERSION"] = ctx.attr.version + ++ cargo_release_profile = _feature_enabled(ctx, "cargo-release-profile") ++ if cargo_release_profile: ++ # Compatibility with Cargo release profiles that retain debug info: ++ # DEBUG describes symbol generation, not debug assertions. Read the ++ # consuming crate's configuration, not the build-script executable's. ++ debug_info = get_compilation_mode_opts(ctx, toolchain).debug_info ++ flags = collect_extra_rustc_flags(ctx, toolchain, None, "rlib") ++ for flag in flags: ++ # Accept both -Copt-level=N and the split -C opt-level=N spelling. ++ codegen = flag.removeprefix("-C").removeprefix("--codegen=") ++ if codegen.startswith("opt-level="): ++ env["OPT_LEVEL"] = codegen.removeprefix("opt-level=") ++ elif codegen.startswith("debuginfo="): ++ debug_info = codegen.removeprefix("debuginfo=") ++ env["DEBUG"] = "false" if debug_info in ["0", "none"] else "true" ++ + # Pull in env vars which may be required for the cc_toolchain to work (e.g. on OSX, the SDK version). + # We hope that the linker env is sufficient for the whole cc_toolchain. + cc_toolchain, feature_configuration = find_cc_toolchain(ctx) +@@ -484,6 +540,13 @@ + if cc_toolchain: + # MSVC requires INCLUDE to be set + cc_c_args, cc_cxx_args, cc_env = get_cc_compile_args_and_env(cc_toolchain, feature_configuration) ++ if cargo_release_profile: ++ # Preserve SDK, ABI, CRT and security options. User copts and crate ++ # build_script_env overrides retain precedence over these defaults. ++ copts = _release_user_opts(ctx, ctx.fragments.cpp.copts) ++ cxxopts = _release_user_opts(ctx, ctx.fragments.cpp.cxxopts) ++ cc_c_args = _cargo_profile_native_flags(cc_c_args) + copts + ctx.fragments.cpp.conlyopts ++ cc_cxx_args = _cargo_profile_native_flags(cc_cxx_args) + copts + cxxopts + include = cc_env.get("INCLUDE") + if include: + if toolchain.exec_triple.str.find("windows") > 0: +@@ -837,6 +900,10 @@ + "_cargo_manifest_dir_filename_suffixes_to_retain": attr.label( + default = Label("//cargo/settings:cargo_manifest_dir_filename_suffixes_to_retain"), + ), ++ "_extra_exec_rustc_flag": attr.label(default = Label("//rust/settings:extra_exec_rustc_flag")), ++ "_extra_exec_rustc_flags": attr.label(default = Label("//rust/settings:extra_exec_rustc_flags")), ++ "_extra_rustc_flag": attr.label(default = Label("//rust/settings:extra_rustc_flag")), ++ "_extra_rustc_flags": attr.label(default = Label("//rust/settings:extra_rustc_flags")), + "_debug_std_streams_output_group": attr.label( + default = Label("//cargo/settings:debug_std_streams_output_group"), + ), diff --git a/third_party/v8/BUILD.bazel b/third_party/v8/BUILD.bazel index 7f764c625561..6b6f8449d836 100644 --- a/third_party/v8/BUILD.bazel +++ b/third_party/v8/BUILD.bazel @@ -134,7 +134,9 @@ alias( "@rules_rs//rs/platforms/config:aarch64-pc-windows-gnullvm": ":v8_150_4_0_aarch64_pc_windows_gnullvm", "@rules_rs//rs/platforms/config:aarch64-pc-windows-msvc": ":v8_150_4_0_aarch64_pc_windows_msvc", "@rules_rs//rs/platforms/config:aarch64-unknown-linux-gnu": ":v8_150_4_0_aarch64_unknown_linux_gnu_bazel", - ":platform_aarch64_unknown_linux_musl": ":v8_150_4_0_aarch64_unknown_linux_musl_release_base", + # Rust's compiler-builtins archive does not supply V8's __clear_cache. + # Use the merged archive containing the ARM64 compiler-rt builtins. + ":platform_aarch64_unknown_linux_musl": ":v8_150_4_0_aarch64_unknown_linux_musl_release", "@rules_rs//rs/platforms/config:x86_64-apple-darwin": ":v8_150_4_0_x86_64_apple_darwin_bazel", "@rules_rs//rs/platforms/config:x86_64-pc-windows-gnullvm": ":v8_150_4_0_x86_64_pc_windows_gnullvm", "@rules_rs//rs/platforms/config:x86_64-pc-windows-msvc": ":v8_150_4_0_x86_64_pc_windows_msvc", diff --git a/third_party/voice/BUILD.bazel b/third_party/voice/BUILD.bazel index b3c5f0930e49..94adba1b5e3b 100644 --- a/third_party/voice/BUILD.bazel +++ b/third_party/voice/BUILD.bazel @@ -175,6 +175,11 @@ filegroup( tags = ["manual"], ) +config_setting( + name = "optimized", + values = {"compilation_mode": "opt"}, +) + # Configure probes execute target binaries: constrain each action's host too. _NATIVE_PLATFORMS = [ ("macos", "aarch64", "apple-darwin"), @@ -198,6 +203,12 @@ _NATIVE_PLATFORMS = [ native_prefix( name = "native_prefix_" + os + "_" + cpu, archives = [":archives"], + # Preserve the native recipe's Meson/CMake release optimization after + # toolchain flags, without optimizing unrelated native targets or tools. + copts = select({ + ":optimized": ["-O3"], + "//conditions:default": [], + }), exec_compatible_with = [ "@platforms//os:" + os, "@platforms//cpu:" + cpu, diff --git a/third_party/voice/native.bzl b/third_party/voice/native.bzl index b70c6b8cc2ef..5dacbcaf229e 100644 --- a/third_party/voice/native.bzl +++ b/third_party/voice/native.bzl @@ -92,6 +92,7 @@ native_prefix = rule( implementation = _native_prefix_impl, attrs = { "archives": attr.label_list(allow_files = True, mandatory = True), + "copts": attr.string_list(), "target": attr.string(mandatory = True), "_driver": attr.label(default = "//third_party/voice:bazel_native.py", allow_single_file = True), "_recipe": attr.label(default = "//third_party/voice:native_recipe"),