diff --git a/.bazelignore b/.bazelignore index 5b70db9535..33830f966f 100644 --- a/.bazelignore +++ b/.bazelignore @@ -4,5 +4,10 @@ crate_universe/private/bootstrap crate_universe/tests/integration docs examples -extensions +extensions/bindgen +extensions/mdbook +extensions/prost/private/tests +extensions/pyo3/test +extensions/pyo3/tools +extensions/wasm_bindgen test/integration diff --git a/.bazelrc b/.bazelrc index 54dd449b55..26cfe95ea1 100644 --- a/.bazelrc +++ b/.bazelrc @@ -50,6 +50,22 @@ build:unpretty --output_groups=+rust_unpretty # https://github.com/rust-lang/rust/issues/43364 build:unpretty --config=nightly +# Use a shared repository cache location. GitHub Actions persists this path +# between runs, and it is also a reasonable local default. +common --repository_cache=~/.cache/bazel-repo +common --repo_contents_cache=~/.cache/bazel-repo/contents + +# BuildBuddy remote cache / BES settings used by CI via `--config=remote`. +common:remote --bes_backend=grpcs://remote.buildbuddy.io +common:remote --bes_results_url=https://app.buildbuddy.io/invocation/ +common:remote --remote_cache=grpcs://remote.buildbuddy.io +common:remote --remote_cache_compression +common:remote --experimental_remote_downloader=grpcs://remote.buildbuddy.io +common:remote --remote_download_outputs=minimal + +# Allows tests that shell out to Bazel/Bazelisk to find their cache directory. +test --test_env=XDG_CACHE_HOME + # Disable cc toolchains to test rust targets can be built without one. build:no_cc_toolchain --repo_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1 build:no_cc_toolchain --repo_env=BAZEL_NO_APPLE_CPP_TOOLCHAIN=1 diff --git a/.github/workflows/bazel_test.yaml b/.github/workflows/bazel_test.yaml new file mode 100644 index 0000000000..d513ce6a04 --- /dev/null +++ b/.github/workflows/bazel_test.yaml @@ -0,0 +1,79 @@ +name: Bazel Test + +on: + push: + branches: + - main + pull_request: + types: + - opened + - synchronize + - reopened + merge_group: + workflow_dispatch: + workflow_call: + secrets: + BUILDBUDDY_API_KEY: + required: false + +permissions: + contents: read + +concurrency: + group: bazel-test-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + +jobs: + test: + name: bazel test //... (${{ matrix.platform }}) + runs-on: ${{ matrix.os }} + timeout-minutes: 120 + strategy: + fail-fast: false + matrix: + include: + - platform: linux + os: ubuntu-latest + - platform: macos + os: macos-latest + - platform: windows + os: windows-latest + + steps: + - uses: actions/checkout@v6 + + - name: Mount Bazel repository cache + uses: actions/cache@v4 + with: + path: | + ~/.cache/bazel-repo + key: bazel-repo-${{ matrix.platform }}-${{ hashFiles('MODULE.bazel', 'MODULE.bazel.lock', '.bazelrc', '**/*.bzl', '**/BUILD', '**/BUILD.bazel') }} + restore-keys: | + bazel-repo-${{ matrix.platform }}- + + - name: Configure Windows Bazel + if: runner.os == 'Windows' + shell: pwsh + run: | + 'startup --output_user_root=C:/tmp/bazel' | Out-File -FilePath user.bazelrc -Encoding utf8 + 'startup --windows_enable_symlinks' | Out-File -FilePath user.bazelrc -Append -Encoding utf8 + + - name: bazel test //... + shell: bash + env: + USE_BAZEL_VERSION: 9.1.0 + BUILDBUDDY_API_KEY: ${{ secrets.BUILDBUDDY_API_KEY }} + run: | + REMOTE_ARGS=() + if [[ -n "${BUILDBUDDY_API_KEY:-}" ]]; then + REMOTE_ARGS+=(--remote_header="x-buildbuddy-api-key=${BUILDBUDDY_API_KEY}") + else + echo "BUILDBUDDY_API_KEY is not set; using BuildBuddy remote cache without an auth header." + fi + + bazel \ + --bazelrc="$GITHUB_WORKSPACE/.github/github.bazelrc" \ + test \ + --config=remote \ + "${REMOTE_ARGS[@]}" \ + //... diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml deleted file mode 100644 index 327c028e29..0000000000 --- a/.github/workflows/docs.yaml +++ /dev/null @@ -1,21 +0,0 @@ -name: Docs-CI/CD - -on: - push: - branches: - - main - -jobs: - docs: - name: Docs - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@master - - name: Run tests - run: bazel run --compilation_mode=opt --stamp //:publish_book - working-directory: docs - - name: Deploy to GitHub Pages - uses: JamesIves/github-pages-deploy-action@4.1.7 - with: - branch: gh-pages # The branch the action should deploy to. - folder: docs/book # The folder the action should deploy. diff --git a/.github/workflows/formatting.yaml b/.github/workflows/formatting.yaml deleted file mode 100644 index 289162f02f..0000000000 --- a/.github/workflows/formatting.yaml +++ /dev/null @@ -1,18 +0,0 @@ -name: Formatting - -on: - push: - branches: - - main - pull_request: - types: - - opened - - synchronize - merge_group: - -jobs: - code-format-checks: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: pre-commit/action@v3.0.1 diff --git a/MODULE.bazel b/MODULE.bazel index 02d34b8c3a..7d0856b0ae 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -9,13 +9,27 @@ module( ## Core ############################################################################### +bazel_dep(name = "bazel_lib", version = "3.0.0") bazel_dep(name = "bazel_features", version = "1.32.0") bazel_dep(name = "bazel_skylib", version = "1.8.2") bazel_dep(name = "platforms", version = "1.1.0") +bazel_dep(name = "protobuf", version = "28.3", repo_name = "com_google_protobuf") bazel_dep(name = "rules_cc", version = "0.2.4") bazel_dep(name = "rules_license", version = "1.0.0") +bazel_dep(name = "rules_proto", version = "7.1.0") +bazel_dep(name = "rules_python", version = "1.6.3") bazel_dep(name = "rules_shell", version = "0.6.1") bazel_dep(name = "apple_support", version = "1.24.1") +bazel_dep(name = "llvm", version = "0.7.7") + +############################################################################### +## Compatibility +############################################################################### + +bazel_dep(name = "rules_rs", version = "0.0.76") + +osx = use_extension("@llvm//extensions:osx.bzl", "osx") +use_repo(osx, "macos_sdk") internal_deps = use_extension("//rust/private:internal_extensions.bzl", "i") use_repo( @@ -86,7 +100,6 @@ use_repo( "rules_rust_toolchain_test_target_json", ) -bazel_dep(name = "rules_python", version = "1.5.1", dev_dependency = True) bazel_dep(name = "rules_testing", version = "0.7.0", dev_dependency = True) bazel_dep(name = "bazel_ci_rules", version = "1.0.0", dev_dependency = True) diff --git a/cargo/private/BUILD.bazel b/cargo/private/BUILD.bazel index fd60c4ff62..db04afa7b1 100644 --- a/cargo/private/BUILD.bazel +++ b/cargo/private/BUILD.bazel @@ -1,5 +1,5 @@ +load("@bazel_lib//lib:copy_file.bzl", "copy_file") load("@bazel_skylib//:bzl_library.bzl", "bzl_library") -load("@bazel_skylib//rules:copy_file.bzl", "copy_file") load("//rust:defs.bzl", "rust_binary") rust_binary( @@ -39,6 +39,9 @@ copy_file( bzl_library( name = "bzl_lib", + deps = [ + "//rust:bzl_lib", + ], srcs = glob(["**/*.bzl"]), - visibility = ["//:__subpackages__"], + visibility = ["//visibility:public"], ) diff --git a/cargo/private/cargo_build_script.bzl b/cargo/private/cargo_build_script.bzl index 301e2a8dce..25755f7afb 100644 --- a/cargo/private/cargo_build_script.bzl +++ b/cargo/private/cargo_build_script.bzl @@ -28,6 +28,9 @@ load( # Reexport for cargo_build_script_wrapper.bzl name_to_crate_name = _name_to_crate_name +# Keep this short: it is part of CARGO_MANIFEST_DIR on Windows. +_CARGO_MANIFEST_DIR = "m" + CargoBuildScriptRunfilesInfo = provider( doc = "Info about a `cargo_build_script.script` target.", fields = { @@ -293,13 +296,33 @@ def _feature_enabled(ctx, feature_name, default = False): return default +def _manifest_rlocation_prefix(workspace_name, package): + if package: + return "{}/{}".format(workspace_name, package) + + return workspace_name + def _rlocationpath(file, workspace_name): if file.short_path.startswith("../"): return file.short_path[len("../"):] return "{}/{}".format(workspace_name, file.short_path) -def _create_runfiles_dir(ctx, script, retain_list): +def _manifest_dir_rlocationpath(rlocationpath, manifest_rlocation_prefix): + prefix = manifest_rlocation_prefix + "/" + if rlocationpath == manifest_rlocation_prefix: + return _CARGO_MANIFEST_DIR + if rlocationpath.startswith(prefix): + return paths.join(_CARGO_MANIFEST_DIR, rlocationpath[len(prefix):]) + + return None + +def _create_runfiles_dir( + ctx, + script, + retain_list, + workspace_name, + manifest_rlocation_prefix): """Create a runfiles directory to represent `CARGO_MANIFEST_DIR`. Due to the inability to forcibly generate runfiles directories for use as inputs @@ -314,6 +337,8 @@ def _create_runfiles_dir(ctx, script, retain_list): ctx (ctx): The rule's context object script (Target): The `cargo_build_script.script` target. retain_list (list): A list of strings to keep in generated runfiles directories. + workspace_name (str): The runfiles workspace name for the current repository. + manifest_rlocation_prefix (str): The current package's runfiles path prefix. Returns: Tuple[File, Depset[File], Args]: @@ -321,13 +346,15 @@ def _create_runfiles_dir(ctx, script, retain_list): - Runfile inputs needed by the action. - The args required to create the directory. """ - runfiles_dir = ctx.actions.declare_directory("{}.cargo_runfiles".format(ctx.label.name)) - - # External repos always fall into the `../` branch of `_rlocationpath`. - workspace_name = ctx.workspace_name + runfiles_dir = ctx.actions.declare_directory(ctx.label.name + ".crf") def _runfiles_map(file): - return "{}={}".format(file.path, _rlocationpath(file, workspace_name)) + rlocationpath = _rlocationpath(file, workspace_name) + manifest_path = _manifest_dir_rlocationpath(rlocationpath, manifest_rlocation_prefix) + if not manifest_path: + return "{}={}".format(file.path, rlocationpath) + + return "{}={}".format(file.path, manifest_path) runfiles = script[DefaultInfo].default_runfiles @@ -382,8 +409,10 @@ def _cargo_build_script_impl(ctx): ctx = ctx, script = ctx.attr.script, retain_list = ctx.attr._cargo_manifest_dir_filename_suffixes_to_retain[BuildSettingInfo].value, + workspace_name = workspace_name, + manifest_rlocation_prefix = _manifest_rlocation_prefix(workspace_name, ctx.label.package), ) - manifest_dir = "{}/{}/{}".format(runfiles_dir.path, workspace_name, ctx.label.package) + manifest_dir = paths.join(runfiles_dir.path, _CARGO_MANIFEST_DIR) pkg_name = ctx.attr.pkg_name if pkg_name == "": @@ -538,6 +567,7 @@ def _cargo_build_script_impl(ctx): known_variables.update(variables) if ctx.attr.build_script_env: + _fail_on_rlocationpath_env(ctx.attr.build_script_env) _merge_env_dict(env, expand_dict_value_locations( ctx, ctx.attr.build_script_env, @@ -573,8 +603,6 @@ def _cargo_build_script_impl(ctx): args.add(link_flags, format = "--link_flags=%s") args.add(link_search_paths, format = "--link_search_paths=%s") args.add(dep_env_out, format = "--dep_env_out=%s") - args.add(ctx.attr.rundir, format = "--rundir=%s") - output_groups = { "out_dir": depset([out_dir]), } @@ -642,7 +670,7 @@ def _cargo_build_script_impl(ctx): tools = tools, inputs = depset(build_script_inputs, transitive = [runfiles_inputs]), mnemonic = "CargoBuildScriptRun", - progress_message = "Running Cargo build script {}".format(pkg_name), + progress_message = "Running Cargo build script %{label}", env = env, toolchain = None, use_default_shell_env = use_default_shell_env, @@ -660,7 +688,8 @@ def _cargo_build_script_impl(ctx): flags = flags_out, linker_flags = link_flags, link_search_paths = link_search_paths, - compile_data = depset([runfiles_dir] + extra_output, transitive = script_data), + build_script_data = depset(transitive = script_data), + compile_data = depset([runfiles_dir] + extra_output), ), OutputGroupInfo( **output_groups @@ -717,19 +746,6 @@ cargo_build_script = rule( "pkg_name": attr.string( doc = "The name of package being compiled, if not derived from `name`.", ), - "rundir": attr.string( - default = "", - doc = dedent("""\ - A directory to cd to before the cargo_build_script is run. - - This should be a pathrelative to the exec root. The default behaviour (and the - behaviour if rundir is set to the empty string) is to change to the relative - path corresponding to the cargo manifest directory, which replicates the - normal behaviour of cargo so it is easy to write compatible build scripts. - - If set to `.`, the cargo build script will run in the exec root. - """), - ), "rustc_flags": attr.string_list( doc = dedent("""\ List of compiler flags passed to `rustc`. @@ -818,6 +834,13 @@ def _merge_env_dict(prefix_dict, suffix_dict): prefix_dict[key] += " " + suffix_dict.pop(key) prefix_dict.update(suffix_dict) +def _fail_on_rlocationpath_env(env): + for key, value in env.items(): + if "$(rlocationpath" in value: + fail( + "cargo_build_script build_script_env does not support $(rlocationpath ...) in '{}'; use $(execpath ...) or $(location ...) for files needed while running the build script".format(key), + ) + def name_to_pkg_name(name): """Sanitize the name of cargo_build_script targets. diff --git a/cargo/private/cargo_build_script_runner/bin.rs b/cargo/private/cargo_build_script_runner/bin.rs index 579de21299..0653fe8134 100644 --- a/cargo/private/cargo_build_script_runner/bin.rs +++ b/cargo/private/cargo_build_script_runner/bin.rs @@ -18,7 +18,7 @@ use std::collections::BTreeMap; use std::env; use std::fs::{create_dir_all, read_dir, read_to_string, remove_file, write}; -use std::path::{Path, PathBuf}; +use std::path::Path; use std::process::Command; use cargo_build_script_runner::cargo_manifest_dir::{remove_symlink, symlink, RunfilesMaker}; @@ -46,7 +46,6 @@ fn run_buildrs() -> Result<(), String> { output_dep_env_path, stdout_path, stderr_path, - rundir, input_dep_env_paths, cargo_manifest_maker, } = Args::parse(); @@ -73,23 +72,33 @@ fn run_buildrs() -> Result<(), String> { let file_name = path .file_name() .ok_or_else(|| "Failed while getting file name".to_string())?; + + // Skip exposing the workspace's `.git` directory to build scripts. + // Some crates (notably `ring` ≤ 0.17.x) probe for `.git` to decide + // whether they are being built in a "local hacking" mode that + // requires extra build-time tooling (perl, nasm). Crate releases + // strip `.git` for exactly this reason; symlinking the workspace's + // `.git` back in breaks that contract. + if file_name == ".git" { + continue; + } let link = manifest_dir.join(file_name); - symlink_if_not_exists(&path, &link) + let created = symlink_if_not_exists(&path, &link) .map_err(|err| format!("Failed to symlink {path:?} to {link:?}: {err}"))?; - exec_root_links.push(link) + if created { + exec_root_links.push(link); + } } } let target_env_vars = get_target_env_vars(&rustc_env).expect("Error getting target env vars from rustc"); - let working_directory = resolve_rundir(&rundir, &exec_root, &manifest_dir)?; - let mut command = Command::new(exec_root.join(progname)); command - .current_dir(&working_directory) + .current_dir(&manifest_dir) .envs(target_env_vars) .env("OUT_DIR", &out_dir_abs) .env("CARGO_MANIFEST_DIR", manifest_dir) @@ -314,34 +323,16 @@ fn should_symlink_exec_root() -> bool { } /// Create a symlink from `link` to `original` if `link` doesn't already exist. -fn symlink_if_not_exists(original: &Path, link: &Path) -> Result<(), String> { - symlink(original, link) - .or_else(swallow_already_exists) - .map_err(|err| format!("Failed to create symlink: {err}")) -} - -fn resolve_rundir(rundir: &str, exec_root: &Path, manifest_dir: &Path) -> Result { - if rundir.is_empty() { - return Ok(manifest_dir.to_owned()); - } - let rundir_path = Path::new(rundir); - if rundir_path.is_absolute() { - return Err(format!("rundir must be empty (to run in manifest path) or relative path (relative to exec root), but was {:?}", rundir)); - } - if rundir_path - .components() - .any(|c| c == std::path::Component::ParentDir) - { - return Err(format!("rundir must not contain .. but was {:?}", rundir)); - } - Ok(exec_root.join(rundir_path)) -} - -fn swallow_already_exists(err: std::io::Error) -> std::io::Result<()> { - if err.kind() == std::io::ErrorKind::AlreadyExists { - Ok(()) - } else { - Err(err) +/// Create a symlink from `link` to `original` if `link` doesn't already exist. +/// Returns `Ok(true)` when the symlink was created, `Ok(false)` when `link` +/// already existed (the caller should not later try to remove it, since it +/// may be a real directory placed there by another step such as runfiles +/// staging — `remove_dir` on a non-empty real directory would fail). +fn symlink_if_not_exists(original: &Path, link: &Path) -> Result { + match symlink(original, link) { + Ok(()) => Ok(true), + Err(err) if err.kind() == std::io::ErrorKind::AlreadyExists => Ok(false), + Err(err) => Err(format!("Failed to create symlink: {err}")), } } @@ -357,7 +348,6 @@ struct Args { output_dep_env_path: String, stdout_path: Option, stderr_path: Option, - rundir: String, input_dep_env_paths: Vec, cargo_manifest_maker: RunfilesMaker, } @@ -381,7 +371,6 @@ impl Args { Err("Argument `output_dep_env_path` not provided".to_owned()); let mut stdout_path = None; let mut stderr_path = None; - let mut rundir: Result = Err("Argument `rundir` not provided".to_owned()); let mut input_dep_env_paths = Vec::new(); let mut cargo_manifest_maker: Result = Err("Argument `cargo_manifest_args` not provided".to_owned()); @@ -407,8 +396,6 @@ impl Args { stdout_path = Some(arg.split_off("--stdout=".len())); } else if arg.starts_with("--stderr=") { stderr_path = Some(arg.split_off("--stderr=".len())); - } else if arg.starts_with("--rundir=") { - rundir = Ok(arg.split_off("--rundir=".len())) } else if arg.starts_with("--input_dep_env_path=") { input_dep_env_paths.push(arg.split_off("--input_dep_env_path=".len())); } else if arg.starts_with("--cargo_manifest_args=") { @@ -429,7 +416,6 @@ impl Args { output_dep_env_path: output_dep_env_path.unwrap(), stdout_path, stderr_path, - rundir: rundir.unwrap(), input_dep_env_paths, cargo_manifest_maker: cargo_manifest_maker.unwrap(), } @@ -498,6 +484,7 @@ fn main() { mod test { use super::*; use std::fs::{create_dir_all, write}; + use std::path::PathBuf; fn make_temp_dir(label: &str) -> PathBuf { let nanos = std::time::SystemTime::now() diff --git a/cargo/private/cargo_build_script_runner/cargo_manifest_dir.rs b/cargo/private/cargo_build_script_runner/cargo_manifest_dir.rs index e38ce3c65d..74129b359e 100644 --- a/cargo/private/cargo_build_script_runner/cargo_manifest_dir.rs +++ b/cargo/private/cargo_build_script_runner/cargo_manifest_dir.rs @@ -27,10 +27,16 @@ pub fn remove_symlink(path: &Path) -> Result<(), std::io::Error> { std::fs::remove_file(path) } -/// Create a symlink file on windows systems +/// Remove a symlink on Windows. `Path::is_dir` follows symlinks, so it +/// misreports directory symlinks with missing targets (e.g. Bazel's +/// `local-spawn-runner.*` sandboxes that are cleaned up before this runs) +/// as non-directories, and `remove_file` on a directory reparse point fails +/// with ACCESS_DENIED. Use `symlink_metadata` to inspect the link itself. #[cfg(target_family = "windows")] pub fn remove_symlink(path: &Path) -> Result<(), std::io::Error> { - if path.is_dir() { + use std::os::windows::fs::FileTypeExt; + let file_type = std::fs::symlink_metadata(path)?.file_type(); + if file_type.is_dir() || file_type.is_symlink_dir() { std::fs::remove_dir(path) } else { std::fs::remove_file(path) @@ -112,8 +118,8 @@ pub struct RunfilesMaker { /// A list of file suffixes to retain when pruning runfiles. filename_suffixes_to_retain: BTreeSet, - /// Runfiles to include in `output_dir`. - runfiles: BTreeMap, + /// Runfiles to include in `output_dir`, keyed by destination path. + runfiles: BTreeMap, } impl RunfilesMaker { @@ -151,7 +157,7 @@ impl RunfilesMaker { let (src, dest) = s .split_once('=') .unwrap_or_else(|| panic!("Unexpected runfiles argument: {}", s)); - (PathBuf::from(src), RlocationPath::from(dest)) + (RlocationPath::from(dest), PathBuf::from(src)) }) .collect::>(); @@ -167,7 +173,7 @@ impl RunfilesMaker { /// Create a runfiles directory. #[cfg(target_family = "unix")] pub fn create_runfiles_dir(&self) -> Result<(), String> { - for (src, dest) in &self.runfiles { + for (dest, src) in &self.runfiles { let abs_dest = self.output_dir.join(dest); if let Some(parent) = abs_dest.parent() { @@ -213,7 +219,7 @@ impl RunfilesMaker { let supports_symlinks = system_supports_symlinks(&self.output_dir)?; - for (src, dest) in &self.runfiles { + for (dest, src) in &self.runfiles { let abs_dest = self.output_dir.join(dest); if let Some(parent) = abs_dest.parent() { if !parent.exists() { @@ -258,7 +264,7 @@ impl RunfilesMaker { /// The Unix implementation assumes symlinks are supported and that the runfiles directory /// was created using symlinks. fn drain_runfiles_dir_unix(&self) -> Result<(), String> { - for (src, dest) in &self.runfiles { + for (dest, src) in &self.runfiles { let abs_dest = self.output_dir.join(dest); remove_symlink(&abs_dest).map_err(|e| { @@ -315,19 +321,17 @@ impl RunfilesMaker { /// The Windows implementation assumes symlinks are not supported and real files will have /// been copied into the runfiles directory. fn drain_runfiles_dir_windows(&self) -> Result<(), String> { - for dest in self.runfiles.values() { + for dest in self.runfiles.keys() { if !self .filename_suffixes_to_retain .iter() .any(|suffix| dest.ends_with(suffix)) { - continue; + let abs_dest = self.output_dir.join(dest); + std::fs::remove_file(&abs_dest).map_err(|e| { + format!("Failed to remove file {} with {:?}", abs_dest.display(), e) + })?; } - - let abs_dest = self.output_dir.join(dest); - std::fs::remove_file(&abs_dest).map_err(|e| { - format!("Failed to remove file {} with {:?}", abs_dest.display(), e) - })?; } Ok(()) } diff --git a/cargo/private/cargo_build_script_wrapper.bzl b/cargo/private/cargo_build_script_wrapper.bzl index bec53cf465..4823a20409 100644 --- a/cargo/private/cargo_build_script_wrapper.bzl +++ b/cargo/private/cargo_build_script_wrapper.bzl @@ -28,7 +28,6 @@ def cargo_build_script( compile_data = [], tools = [], links = None, - rundir = None, rustc_env = {}, rustc_env_files = [], rustc_flags = [], @@ -118,11 +117,6 @@ def cargo_build_script( compile_data (list, optional): Files needed for the compilation of the build script. tools (list, optional): Tools (executables) needed by the build script. links (str, optional): Name of the native library this crate links against. - rundir (str, optional): A directory to `cd` to before the cargo_build_script is run. This should be a path relative to the exec root. - - The default behaviour (and the behaviour if rundir is set to the empty string) is to change to the relative path corresponding to the cargo manifest directory, which replicates the normal behaviour of cargo so it is easy to write compatible build scripts. - - If set to `.`, the cargo build script will run in the exec root. rustc_env (dict, optional): Environment variables to set in rustc when compiling the build script. rustc_env_files (list of label, optional): Files containing additional environment variables to set for rustc when building the build script. @@ -137,6 +131,10 @@ def cargo_build_script( target. """ + rundir = kwargs.pop("rundir", None) + if rundir != None: + fail("cargo_build_script.rundir is no longer supported; build scripts always run in CARGO_MANIFEST_DIR") + # This duplicates the code in _cargo_build_script_impl because we need to make these # available both when we invoke rustc (this code) and when we run the compiled build # script (_cargo_build_script_impl). https://github.com/bazelbuild/rules_rust/issues/661 @@ -225,7 +223,6 @@ def cargo_build_script( links = links, deps = deps, link_deps = link_deps, - rundir = rundir, rustc_flags = rustc_flags, visibility = visibility, tags = tags, diff --git a/cargo/private/cargo_dep_env.bzl b/cargo/private/cargo_dep_env.bzl index 2fd0ab6bf4..728de77ec2 100644 --- a/cargo/private/cargo_dep_env.bzl +++ b/cargo/private/cargo_dep_env.bzl @@ -35,6 +35,7 @@ def _cargo_dep_env_impl(ctx): link_search_paths = empty_file, out_dir = out_dir, rustc_env = empty_file, + build_script_data = depset([]), compile_data = depset([]), )) return [ @@ -54,6 +55,7 @@ def _cargo_dep_env_impl(ctx): link_search_paths = empty_file, out_dir = None, rustc_env = empty_file, + build_script_data = depset([]), compile_data = depset([]), ), # Information here is used directly by dependencies, and it is an error to have more than diff --git a/cargo/tests/cargo_build_script/location_expansion/BUILD.bazel b/cargo/tests/cargo_build_script/location_expansion/BUILD.bazel index d6c0683b1b..79f1315662 100644 --- a/cargo/tests/cargo_build_script/location_expansion/BUILD.bazel +++ b/cargo/tests/cargo_build_script/location_expansion/BUILD.bazel @@ -1,6 +1,7 @@ load("@bazel_skylib//rules:write_file.bzl", "write_file") load("//cargo:defs.bzl", "cargo_build_script") load("//rust:defs.bzl", "rust_test") +load(":rlocationpath_failure_test.bzl", "rlocationpath_failure_test") write_file( name = "target_data", @@ -19,10 +20,8 @@ cargo_build_script( srcs = ["build.rs"], build_script_env = { "DATA_EXECPATH": "$(execpath target_data.txt)", - "DATA_RLOCATIONPATH": "$(rlocationpath target_data.txt)", "DATA_ROOTPATH": "$(rootpath target_data.txt)", "TOOL_EXECPATH": "$(execpath exec_data.txt)", - "TOOL_RLOCATIONPATH": "$(rlocationpath exec_data.txt)", "TOOL_ROOTPATH": "$(rootpath exec_data.txt)", }, data = ["target_data.txt"], @@ -36,3 +35,19 @@ rust_test( edition = "2018", deps = [":build_rs"], ) + +cargo_build_script( + name = "rlocationpath_build_rs", + srcs = ["build.rs"], + build_script_env = { + "DATA_RLOCATIONPATH": "$(rlocationpath target_data.txt)", + }, + data = ["target_data.txt"], + edition = "2018", + tags = ["manual"], +) + +rlocationpath_failure_test( + name = "rlocationpath_failure_test", + target_under_test = ":rlocationpath_build_rs", +) diff --git a/cargo/tests/cargo_build_script/location_expansion/build.rs b/cargo/tests/cargo_build_script/location_expansion/build.rs index 0f72a81488..2fa48547d2 100644 --- a/cargo/tests/cargo_build_script/location_expansion/build.rs +++ b/cargo/tests/cargo_build_script/location_expansion/build.rs @@ -7,10 +7,6 @@ fn main() { "cargo:rustc-env=DATA_EXECPATH={}", std::env::var("DATA_EXECPATH").expect("Environment variable not set") ); - println!( - "cargo:rustc-env=DATA_RLOCATIONPATH={}", - std::env::var("DATA_RLOCATIONPATH").expect("Environment variable not set") - ); println!( "cargo:rustc-env=TOOL_ROOTPATH={}", std::env::var("TOOL_ROOTPATH").expect("Environment variable not set") @@ -19,8 +15,4 @@ fn main() { "cargo:rustc-env=TOOL_EXECPATH={}", std::env::var("TOOL_EXECPATH").expect("Environment variable not set") ); - println!( - "cargo:rustc-env=TOOL_RLOCATIONPATH={}", - std::env::var("TOOL_RLOCATIONPATH").expect("Environment variable not set") - ); } diff --git a/cargo/tests/cargo_build_script/location_expansion/rlocationpath_failure_test.bzl b/cargo/tests/cargo_build_script/location_expansion/rlocationpath_failure_test.bzl new file mode 100644 index 0000000000..346802a7c1 --- /dev/null +++ b/cargo/tests/cargo_build_script/location_expansion/rlocationpath_failure_test.bzl @@ -0,0 +1,13 @@ +"""Analysis test for unsupported cargo_build_script location expansion.""" + +load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts") + +def _rlocationpath_failure_test_impl(ctx): + env = analysistest.begin(ctx) + asserts.expect_failure(env, "cargo_build_script build_script_env does not support $(rlocationpath ...) in 'DATA_RLOCATIONPATH'") + return analysistest.end(env) + +rlocationpath_failure_test = analysistest.make( + _rlocationpath_failure_test_impl, + expect_failure = True, +) diff --git a/cargo/tests/cargo_build_script/location_expansion/test.rs b/cargo/tests/cargo_build_script/location_expansion/test.rs index 6b324da038..62a36030c0 100644 --- a/cargo/tests/cargo_build_script/location_expansion/test.rs +++ b/cargo/tests/cargo_build_script/location_expansion/test.rs @@ -6,20 +6,6 @@ pub fn test_data_rootpath() { ); } -#[test] -pub fn test_data_rlocation() { - assert!( - [ - // workspace - "rules_rust/cargo/tests/cargo_build_script/location_expansion/target_data.txt", - // bzlmod - "_main/cargo/tests/cargo_build_script/location_expansion/target_data.txt", - ] - .contains(&env!("DATA_RLOCATIONPATH")), - concat!("Unexpected rlocationpath: ", env!("DATA_RLOCATIONPATH")) - ); -} - #[test] pub fn test_tool_rootpath() { assert_eq!( @@ -28,20 +14,6 @@ pub fn test_tool_rootpath() { ); } -#[test] -pub fn test_tool_rlocationpath() { - assert!( - [ - // workspace - "rules_rust/cargo/tests/cargo_build_script/location_expansion/exec_data.txt", - // bzlmod - "_main/cargo/tests/cargo_build_script/location_expansion/exec_data.txt", - ] - .contains(&env!("TOOL_RLOCATIONPATH")), - concat!("Unexpected rlocationpath: ", env!("TOOL_RLOCATIONPATH")) - ); -} - #[test] pub fn test_execpath() { // Replace `\` to ensure paths are consistent on Windows.` diff --git a/cargo/tests/cargo_build_script/run_from_exec_root/BUILD.bazel b/cargo/tests/cargo_build_script/run_from_exec_root/BUILD.bazel deleted file mode 100644 index b0ae7728db..0000000000 --- a/cargo/tests/cargo_build_script/run_from_exec_root/BUILD.bazel +++ /dev/null @@ -1,17 +0,0 @@ -load("//cargo:defs.bzl", "cargo_build_script") -load("//rust:defs.bzl", "rust_test") - -cargo_build_script( - name = "rundir_build_rs", - srcs = ["build.rs"], - data = ["data.txt"], - edition = "2018", - rundir = ".", -) - -rust_test( - name = "test", - srcs = ["test.rs"], - edition = "2018", - deps = [":rundir_build_rs"], -) diff --git a/cargo/tests/cargo_build_script/run_from_exec_root/build.rs b/cargo/tests/cargo_build_script/run_from_exec_root/build.rs deleted file mode 100644 index ee2465dba7..0000000000 --- a/cargo/tests/cargo_build_script/run_from_exec_root/build.rs +++ /dev/null @@ -1,6 +0,0 @@ -fn main() { - let contents = - std::fs::read_to_string("cargo/tests/cargo_build_script/run_from_exec_root/data.txt") - .expect("Failed to read data file"); - println!("cargo:rustc-env=DATA={}", contents); -} diff --git a/cargo/tests/cargo_build_script/run_from_exec_root/data.txt b/cargo/tests/cargo_build_script/run_from_exec_root/data.txt deleted file mode 100644 index e965047ad7..0000000000 --- a/cargo/tests/cargo_build_script/run_from_exec_root/data.txt +++ /dev/null @@ -1 +0,0 @@ -Hello diff --git a/cargo/tests/cargo_build_script/run_from_exec_root/test.rs b/cargo/tests/cargo_build_script/run_from_exec_root/test.rs deleted file mode 100644 index c688fb6a5b..0000000000 --- a/cargo/tests/cargo_build_script/run_from_exec_root/test.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[test] -pub fn test_tool_exec() { - assert_eq!("Hello", env!("DATA")); -} diff --git a/cargo/tests/cargo_build_script/transitive_data/transitive_data_test.bzl b/cargo/tests/cargo_build_script/transitive_data/transitive_data_test.bzl index 1740c30921..c2512baa91 100644 --- a/cargo/tests/cargo_build_script/transitive_data/transitive_data_test.bzl +++ b/cargo/tests/cargo_build_script/transitive_data/transitive_data_test.bzl @@ -1,6 +1,4 @@ -"""Tests documenting that cargo_build_script `data` files currently act as both -compile_data and runtime data -- they appear in Rustc compile action inputs for -both the direct library and transitive dependents. +"""Tests for cargo_build_script `data` propagation into Rustc compile actions. See https://github.com/bazelbuild/rules_rust/issues/3609 for context.""" @@ -21,21 +19,20 @@ def _cbs_data_in_rustc_inputs_impl(ctx): asserts.false(env, rustc_action == None, "Expected a Rustc action") - # cargo_build_script `data` currently flows into BuildInfo.compile_data - # via script_data, so it appears in Rustc action inputs for both the - # direct dependent and transitive dependents. This documents that - # CBS `data` effectively acts as both compile_data and data today. data_inputs = [i for i in rustc_action.inputs.to_list() if "cbs_data_dep.txt" in i.path] - asserts.true( + asserts.equals( env, + ctx.attr.expected_present, len(data_inputs) > 0, - "Expected CBS data file to appear in Rustc action inputs (CBS data currently acts as compile_data)", ) return analysistest.end(env) cbs_data_in_rustc_inputs_test = analysistest.make( _cbs_data_in_rustc_inputs_impl, + attrs = { + "expected_present": attr.bool(), + }, ) def _define_test_targets(): @@ -98,11 +95,13 @@ def transitive_cbs_data_test_suite(name): cbs_data_in_rustc_inputs_test( name = "cbs_data_in_lib_compile_inputs_test", + expected_present = True, target_under_test = ":lib", ) cbs_data_in_rustc_inputs_test( name = "cbs_data_in_bin_compile_inputs_test", + expected_present = False, target_under_test = ":bin", ) diff --git a/crate_universe/extensions.bzl b/crate_universe/extensions.bzl index aa024737e5..c4610d2334 100644 --- a/crate_universe/extensions.bzl +++ b/crate_universe/extensions.bzl @@ -1360,9 +1360,6 @@ _ANNOTATION_SELECT_ATTRS = { "build_script_proc_macro_deps": _relative_label_list( doc = "A list of labels to add to a crate's `cargo_build_script::proc_macro_deps` attribute.", ), - "build_script_rundir": attr.string( - doc = "An override for the build script's rundir attribute.", - ), "build_script_rustc_env": attr.string_dict( doc = "Additional environment variables to set on a crate's `cargo_build_script::env` attribute.", ), diff --git a/crate_universe/private/crate.bzl b/crate_universe/private/crate.bzl index e79f8e4a1c..56fece558c 100644 --- a/crate_universe/private/crate.bzl +++ b/crate_universe/private/crate.bzl @@ -99,7 +99,6 @@ def _annotation( build_script_exec_properties = None, build_script_link_deps = None, build_script_proc_macro_deps = None, - build_script_rundir = None, build_script_rustc_env = None, build_script_toolchains = None, build_script_use_default_shell_env = None, @@ -144,7 +143,6 @@ def _annotation( build_script_link_deps: A list of labels to add to a crate's `cargo_build_script::link_deps` attribute. build_script_proc_macro_deps (list, optional): A list of labels to add to a crate's `cargo_build_script::proc_macro_deps` attribute. - build_script_rundir (str, optional): An override for the build script's rundir attribute. build_script_rustc_env (dict, optional): Additional environment variables to set when compiling the crate's `cargo_build_script` - sets that target's `rustc_env` attribute. build_script_toolchains (list, optional): A list of labels to set on a crates's `cargo_build_script::toolchains` attribute. build_script_use_default_shell_env (int, optional): Whether or not to include the default shell environment for the build @@ -207,7 +205,6 @@ def _annotation( build_script_exec_properties = build_script_exec_properties, build_script_link_deps = build_script_link_deps, build_script_proc_macro_deps = _stringify_list(build_script_proc_macro_deps), - build_script_rundir = build_script_rundir, build_script_rustc_env = build_script_rustc_env, build_script_toolchains = _stringify_list(build_script_toolchains), build_script_use_default_shell_env = build_script_use_default_shell_env, diff --git a/crate_universe/src/config.rs b/crate_universe/src/config.rs index 3f6564f7d3..54947e09b0 100644 --- a/crate_universe/src/config.rs +++ b/crate_universe/src/config.rs @@ -338,9 +338,6 @@ pub(crate) struct CrateAnnotations { /// [use_default_shell_env](https://bazelbuild.github.io/rules_rust/cargo.html#cargo_build_script-use_default_shell_env) attribute. pub(crate) build_script_use_default_shell_env: Option, - /// Directory to run the crate's build script in. If not set, will run in the manifest directory, otherwise a directory relative to the exec root. - pub(crate) build_script_rundir: Option>, - /// A scratch pad used to write arbitrary text to target BUILD files. pub(crate) additive_build_file_content: Option, @@ -437,7 +434,6 @@ impl Add for CrateAnnotations { build_script_exec_properties: select_merge(self.build_script_exec_properties, rhs.build_script_exec_properties), build_script_toolchains: joined_extra_member!(self.build_script_toolchains, rhs.build_script_toolchains, BTreeSet::new, BTreeSet::extend), build_script_use_default_shell_env: self.build_script_use_default_shell_env.or(rhs.build_script_use_default_shell_env), - build_script_rundir: self.build_script_rundir.or(rhs.build_script_rundir), additive_build_file_content: joined_extra_member!(self.additive_build_file_content, rhs.additive_build_file_content, String::new, concat_string), shallow_since: self.shallow_since.or(rhs.shallow_since), patch_args: joined_extra_member!(self.patch_args, rhs.patch_args, Vec::new, Vec::extend), @@ -488,7 +484,6 @@ pub(crate) struct AnnotationsProvidedByPackage { pub(crate) rustc_flags: Option>>, pub(crate) build_script_env: Option>>, pub(crate) build_script_rustc_env: Option>>, - pub(crate) build_script_rundir: Option>, pub(crate) additive_build_file_content: Option, pub(crate) extra_aliased_targets: Option>, } @@ -512,7 +507,6 @@ impl CrateAnnotations { rustc_flags, build_script_env, build_script_rustc_env, - build_script_rundir, additive_build_file_content, extra_aliased_targets, } = match AnnotationsProvidedByPackage::deserialize(&pkg_metadata["bazel"]) { @@ -547,7 +541,6 @@ impl CrateAnnotations { default(&mut self.rustc_flags, rustc_flags); default(&mut self.build_script_env, build_script_env); default(&mut self.build_script_rustc_env, build_script_rustc_env); - default(&mut self.build_script_rundir, build_script_rundir); default( &mut self.additive_build_file_content, additive_build_file_content, diff --git a/crate_universe/src/context/crate_context.rs b/crate_universe/src/context/crate_context.rs index 8fdda79dc2..d03b9ad5a6 100644 --- a/crate_universe/src/context/crate_context.rs +++ b/crate_universe/src/context/crate_context.rs @@ -235,9 +235,6 @@ pub(crate) struct BuildScriptAttributes { #[serde(skip_serializing_if = "Select::is_empty")] pub(crate) exec_properties: Select>, - #[serde(skip_serializing_if = "Select::is_empty")] - pub(crate) rundir: Select, - #[serde(skip_serializing_if = "Select::is_empty")] pub(crate) extra_proc_macro_deps: Select>, @@ -284,7 +281,6 @@ impl Default for BuildScriptAttributes { build_script_env: Default::default(), build_script_env_files: Default::default(), exec_properties: Default::default(), - rundir: Default::default(), extra_proc_macro_deps: Default::default(), proc_macro_deps: Default::default(), rustc_env: Default::default(), @@ -714,9 +710,6 @@ impl CrateContext { attrs.use_default_shell_env = Some(*extra); } - if let Some(rundir) = &crate_extra.build_script_rundir { - attrs.rundir = Select::merge(attrs.rundir.clone(), rundir.clone()); - } } // Extra build contents diff --git a/crate_universe/src/lockfile.rs b/crate_universe/src/lockfile.rs index b0d76428ab..fd17c7a6ab 100644 --- a/crate_universe/src/lockfile.rs +++ b/crate_universe/src/lockfile.rs @@ -292,7 +292,7 @@ mod test { ); assert_eq!( - Digest("8a4c1b3bb4c2d6c36e27565e71a13d54cff9490696a492c66a3a37bdd3893edf".to_owned()), + Digest("3aea6884bba019a96aeee55213f930c8210f1028043d1084d2bd49de67e64f3f".to_owned()), digest, ); } diff --git a/crate_universe/src/rendering.rs b/crate_universe/src/rendering.rs index 49360d78ce..401328b8a8 100644 --- a/crate_universe/src/rendering.rs +++ b/crate_universe/src/rendering.rs @@ -21,7 +21,7 @@ use crate::splicing::default_splicing_package_crate_id; use crate::utils::starlark::{ self, Alias, CargoBuildScript, CargoTomlEnvVars, CommonAttrs, Data, ExportsFiles, Filegroup, Glob, Label, Load, Package, RustBinary, RustLibrary, RustProcMacro, SelectDict, SelectList, - SelectScalar, SelectSet, Starlark, TargetCompatibleWith, + SelectSet, Starlark, TargetCompatibleWith, }; use crate::utils::target_triple::TargetTriple; use crate::utils::{self, sanitize_repository_name}; @@ -625,10 +625,6 @@ impl Renderer { ), platforms, ), - rundir: SelectScalar::new( - attrs.map(|attrs| attrs.rundir.clone()).unwrap_or_default(), - platforms, - ), rustc_env: SelectDict::new( attrs .map(|attrs| attrs.rustc_env.clone()) diff --git a/crate_universe/src/utils/starlark.rs b/crate_universe/src/utils/starlark.rs index 14ff5f8c23..b3afe8b94f 100644 --- a/crate_universe/src/utils/starlark.rs +++ b/crate_universe/src/utils/starlark.rs @@ -20,7 +20,6 @@ pub(crate) use label::*; pub(crate) use select::*; pub(crate) use select_dict::*; pub(crate) use select_list::*; -pub(crate) use select_scalar::*; pub(crate) use select_set::*; pub(crate) use target_compatible_with::*; @@ -122,8 +121,6 @@ pub(crate) struct CargoBuildScript { pub(crate) pkg_name: Option, #[serde(skip_serializing_if = "SelectSet::is_empty")] pub(crate) proc_macro_deps: SelectSet