From 144d6962118ff02c6e7b2bb19f43e2b5a443741c Mon Sep 17 00:00:00 2001 From: UebelAndre Date: Sat, 14 Sep 2024 08:13:26 -0700 Subject: [PATCH] Update `cargo_build_script` to work without runfiles support. --- .bazelrc | 7 -- .github/github.bazelrc | 4 - cargo/cargo_build_script_runner/lib.rs | 4 +- cargo/private/BUILD.bazel | 6 ++ cargo/private/cargo_build_script.bzl | 54 +++++++++++++- cargo/private/runfiles_enabled.bzl | 74 +++++++++++++++++++ cargo/private/runfiles_maker/BUILD.bazel | 8 ++ .../private/runfiles_maker/runfiles_maker.rs | 50 +++++++++++++ examples/crate_universe/.bazelrc | 6 -- .../crate_universe/cargo_aliases/.bazelrc | 25 ------- examples/crate_universe/cargo_remote/.bazelrc | 25 ------- .../crate_universe/cargo_workspace/.bazelrc | 25 ------- .../crate_universe/multi_package/.bazelrc | 25 ------- .../no_cargo_manifests/.bazelrc | 25 ------- 14 files changed, 192 insertions(+), 146 deletions(-) create mode 100644 cargo/private/runfiles_enabled.bzl create mode 100644 cargo/private/runfiles_maker/BUILD.bazel create mode 100644 cargo/private/runfiles_maker/runfiles_maker.rs delete mode 100644 examples/crate_universe/cargo_aliases/.bazelrc delete mode 100644 examples/crate_universe/cargo_remote/.bazelrc delete mode 100644 examples/crate_universe/cargo_workspace/.bazelrc delete mode 100644 examples/crate_universe/multi_package/.bazelrc delete mode 100644 examples/crate_universe/no_cargo_manifests/.bazelrc diff --git a/.bazelrc b/.bazelrc index 2b404c601c..2127c77d53 100644 --- a/.bazelrc +++ b/.bazelrc @@ -5,13 +5,6 @@ ## https://bazel.build/docs/best-practices#bazelrc-file ############################################################################### -# https://bazel.build/reference/command-line-reference#flag--enable_platform_specific_config -common --enable_platform_specific_config - -# https://bazel.build/docs/windows#symlink -startup --windows_enable_symlinks -build:windows --enable_runfiles - # Enable the only currently supported report type # https://bazel.build/reference/command-line-reference#flag--combined_report coverage --combined_report=lcov diff --git a/.github/github.bazelrc b/.github/github.bazelrc index 9e89572dd3..d9d0f5acae 100644 --- a/.github/github.bazelrc +++ b/.github/github.bazelrc @@ -3,10 +3,6 @@ # Always display the flags being used common --announce_rc -# These settings make the windows workers behave similarly to unix workers -startup --windows_enable_symlinks -build --enable_runfiles - # Show errors in CI test --test_output=errors diff --git a/cargo/cargo_build_script_runner/lib.rs b/cargo/cargo_build_script_runner/lib.rs index 3739a1778d..c0c4ea4dc7 100644 --- a/cargo/cargo_build_script_runner/lib.rs +++ b/cargo/cargo_build_script_runner/lib.rs @@ -124,7 +124,9 @@ impl BuildScriptOutput { pub fn outputs_from_command( cmd: &mut Command, ) -> Result<(Vec, Output), Output> { - let child_output = cmd.output().expect("Unable to start binary"); + let child_output = cmd + .output() + .unwrap_or_else(|_| panic!("Unable to start command:\n{:#?}", cmd)); if child_output.status.success() { let reader = BufReader::new(child_output.stdout.as_slice()); let output = Self::outputs_from_reader(reader); diff --git a/cargo/private/BUILD.bazel b/cargo/private/BUILD.bazel index 6a1aab653c..2b7e6de7dd 100644 --- a/cargo/private/BUILD.bazel +++ b/cargo/private/BUILD.bazel @@ -1,7 +1,13 @@ load("@bazel_skylib//:bzl_library.bzl", "bzl_library") +load(":runfiles_enabled.bzl", "runfiles_enabled_build_setting") bzl_library( name = "bzl_lib", srcs = glob(["**/*.bzl"]), visibility = ["//:__subpackages__"], ) + +runfiles_enabled_build_setting( + name = "runfiles_enabled", + visibility = ["//visibility:public"], +) diff --git a/cargo/private/cargo_build_script.bzl b/cargo/private/cargo_build_script.bzl index 56f64994af..4ae22d8a90 100644 --- a/cargo/private/cargo_build_script.bzl +++ b/cargo/private/cargo_build_script.bzl @@ -23,6 +23,7 @@ load( "find_toolchain", _name_to_crate_name = "name_to_crate_name", ) +load(":runfiles_enabled.bzl", "is_runfiles_enabled", "runfiles_enabled_attr") # Reexport for cargo_build_script_wrapper.bzl name_to_crate_name = _name_to_crate_name @@ -198,6 +199,38 @@ def _feature_enabled(ctx, feature_name, default = False): return default +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): + runfiles_dir = ctx.actions.declare_directory("{}.cargo_runfiles".format(ctx.label.name)) + + workspace_name = ctx.label.workspace_name + if not workspace_name: + workspace_name = ctx.workspace_name + + def _runfiles_map(file): + return "{}={}".format(file.path, _rlocationpath(file, workspace_name)) + + runfiles = script[DefaultInfo].default_runfiles + + args = ctx.actions.args() + args.add(runfiles_dir.path) + args.add_all(runfiles.files, map_each = _runfiles_map, allow_closure = True) + + ctx.actions.run( + mnemonic = "CargoBuildScriptRunfilesDir", + executable = ctx.executable._runfiles_maker, + arguments = [args], + inputs = runfiles.files, + outputs = [runfiles_dir], + ) + + return runfiles_dir + def _cargo_build_script_impl(ctx): """The implementation for the `cargo_build_script` rule. @@ -215,9 +248,20 @@ def _cargo_build_script_impl(ctx): flags_out = ctx.actions.declare_file(ctx.label.name + ".flags") link_flags = ctx.actions.declare_file(ctx.label.name + ".linkflags") link_search_paths = ctx.actions.declare_file(ctx.label.name + ".linksearchpaths") # rustc-link-search, propagated from transitive dependencies - manifest_dir = "%s.runfiles/%s/%s" % (script.path, ctx.label.workspace_name or ctx.workspace_name, ctx.label.package) compilation_mode_opt_level = get_compilation_mode_opts(ctx, toolchain).opt_level + build_script_inputs = [] + + workspace_name = ctx.label.workspace_name + if not workspace_name: + workspace_name = ctx.workspace_name + + manifest_dir = "{}.runfiles/{}/{}".format(script.path, workspace_name, ctx.label.package) + if not is_runfiles_enabled(ctx.attr): + runfiles_dir = _create_runfiles_dir(ctx, ctx.attr.script) + build_script_inputs.append(runfiles_dir) + manifest_dir = "{}/{}/{}".format(runfiles_dir.path, workspace_name, ctx.label.package) + streams = struct( stdout = ctx.actions.declare_file(ctx.label.name + ".stdout.log"), stderr = ctx.actions.declare_file(ctx.label.name + ".stderr.log"), @@ -378,7 +422,6 @@ def _cargo_build_script_impl(ctx): args.add(streams.stderr) args.add(ctx.attr.rundir) - build_script_inputs = [] for dep in ctx.attr.link_deps: if rust_common.dep_info in dep and dep[rust_common.dep_info].dep_env: dep_env_file = dep[rust_common.dep_info].dep_env @@ -520,7 +563,12 @@ cargo_build_script = rule( "_experimental_symlink_execroot": attr.label( default = Label("//cargo/settings:experimental_symlink_execroot"), ), - }, + "_runfiles_maker": attr.label( + cfg = "exec", + executable = True, + default = Label("//cargo/private/runfiles_maker"), + ), + } | runfiles_enabled_attr(), fragments = ["cpp"], toolchains = [ str(Label("//rust:toolchain_type")), diff --git a/cargo/private/runfiles_enabled.bzl b/cargo/private/runfiles_enabled.bzl new file mode 100644 index 0000000000..0e5c3c5150 --- /dev/null +++ b/cargo/private/runfiles_enabled.bzl @@ -0,0 +1,74 @@ +"""A small utility module dedicated to detecting whether or not the `--enable_runfiles` and `--windows_enable_symlinks` flag are enabled +""" + +RunfilesEnabledInfo = provider( + doc = "A singleton provider that contains the raw value of a build setting", + fields = { + "value": "The value of the build setting in the current configuration. " + + "This value may come from the command line or an upstream transition, " + + "or else it will be the build setting's default.", + }, +) + +def _runfiles_enabled_setting_impl(ctx): + return RunfilesEnabledInfo(value = ctx.attr.value) + +runfiles_enabled_setting = rule( + implementation = _runfiles_enabled_setting_impl, + doc = "A bool-typed build setting that cannot be set on the command line", + attrs = { + "value": attr.bool( + doc = "A boolean value", + mandatory = True, + ), + }, +) + +_RUNFILES_ENABLED_ATTR_NAME = "_runfiles_enabled" + +def runfiles_enabled_attr(default = Label("//cargo/private:runfiles_enabled")): + return { + _RUNFILES_ENABLED_ATTR_NAME: attr.label( + doc = "A flag representing whether or not runfiles are enabled.", + providers = [RunfilesEnabledInfo], + default = default, + cfg = "exec", + ), + } + +def runfiles_enabled_build_setting(name, **kwargs): + native.config_setting( + name = "{}_enable_runfiles".format(name), + values = {"enable_runfiles": "true"}, + ) + + native.config_setting( + name = "{}_disable_runfiles".format(name), + values = {"enable_runfiles": "false"}, + ) + + runfiles_enabled_setting( + name = name, + value = select({ + # If either of the runfiles are set, use the flag + ":{}_enable_runfiles".format(name): True, + ":{}_disable_runfiles".format(name): False, + # Otherwise fall back to the system default. + "@platforms//os:windows": False, + "//conditions:default": True, + }), + **kwargs + ) + +def is_runfiles_enabled(attr): + """Determine whether or not runfiles are enabled. + + Args: + attr (struct): A rule's struct of attributes (`ctx.attr`) + Returns: + bool: The enable_runfiles value. + """ + + runfiles_enabled = getattr(attr, _RUNFILES_ENABLED_ATTR_NAME, None) + + return runfiles_enabled[RunfilesEnabledInfo].value if runfiles_enabled else True diff --git a/cargo/private/runfiles_maker/BUILD.bazel b/cargo/private/runfiles_maker/BUILD.bazel new file mode 100644 index 0000000000..3b3df766c2 --- /dev/null +++ b/cargo/private/runfiles_maker/BUILD.bazel @@ -0,0 +1,8 @@ +load("//rust:defs.bzl", "rust_binary") + +rust_binary( + name = "runfiles_maker", + srcs = ["runfiles_maker.rs"], + edition = "2021", + visibility = ["//visibility:public"], +) diff --git a/cargo/private/runfiles_maker/runfiles_maker.rs b/cargo/private/runfiles_maker/runfiles_maker.rs new file mode 100644 index 0000000000..0fd165d08d --- /dev/null +++ b/cargo/private/runfiles_maker/runfiles_maker.rs @@ -0,0 +1,50 @@ +//! A tool for building runfiles directories for Bazel environments that don't +//! support runfiles or have runfiles enabled. + +use std::collections::BTreeMap; +use std::path::PathBuf; + +struct Args { + pub output_dir: PathBuf, + pub runfiles: BTreeMap, +} + +impl Args { + fn parse() -> Self { + let mut args = std::env::args().skip(1); + let output_dir = PathBuf::from( + args.next() + .unwrap_or_else(|| panic!("Not enough arguments provided.")), + ); + let runfiles = args + .map(|s| { + let (src, dest) = s + .split_once('=') + .unwrap_or_else(|| panic!("Unexpected runfiles argument: {}", s)); + (PathBuf::from(src), PathBuf::from(dest)) + }) + .collect::>(); + + assert!(!runfiles.is_empty(), "No runfiles found"); + + Args { + output_dir, + runfiles, + } + } +} + +fn main() { + let args = Args::parse(); + + for (src, dest) in args.runfiles.iter() { + let out_dest = args.output_dir.join(dest); + std::fs::create_dir_all( + out_dest + .parent() + .expect("The output location should have a valid parent."), + ) + .expect("Failed to create output directory"); + std::fs::copy(src, out_dest).expect("Failed to copy file"); + } +} diff --git a/examples/crate_universe/.bazelrc b/examples/crate_universe/.bazelrc index b19f06e58b..bc6cde90e1 100644 --- a/examples/crate_universe/.bazelrc +++ b/examples/crate_universe/.bazelrc @@ -1,11 +1,6 @@ # `.bazelrc` is a Bazel configuration file. # https://bazel.build/docs/best-practices#bazelrc-file -# Required on windows -common --enable_platform_specific_config -startup --windows_enable_symlinks -build:windows --enable_runfiles - # Enable rustfmt for all targets in the workspace build:rustfmt --aspects=@rules_rust//rust:defs.bzl%rustfmt_aspect build:rustfmt --output_groups=+rustfmt_checks @@ -31,4 +26,3 @@ build --incompatible_merge_fixed_and_default_shell_env # This import should always be last to allow users to override # settings for local development. try-import %workspace%/user.bazelrc - diff --git a/examples/crate_universe/cargo_aliases/.bazelrc b/examples/crate_universe/cargo_aliases/.bazelrc deleted file mode 100644 index a67f1baf7f..0000000000 --- a/examples/crate_universe/cargo_aliases/.bazelrc +++ /dev/null @@ -1,25 +0,0 @@ -# A config file containing Bazel settings - -# Required on windows -common --enable_platform_specific_config -startup --windows_enable_symlinks -build:windows --enable_runfiles - -# Enable rustfmt -build:strict --aspects=@rules_rust//rust:defs.bzl%rustfmt_aspect -build:strict --output_groups=+rustfmt_checks - -# Enable clippy -build:strict --aspects=@rules_rust//rust:defs.bzl%rust_clippy_aspect -build:strict --output_groups=+clippy_checks - -# TODO: migrate all dependencies from WORKSPACE to MODULE.bazel -# https://github.com/bazelbuild/rules_rust/issues/2181 -common --noenable_bzlmod - -# This isn't currently the defaut in Bazel, but we enable it to test we'll be ready if/when it flips. -build --incompatible_disallow_empty_glob - -# This import should always be last to allow users to override -# settings for local development. -try-import %workspace%/user.bazelrc diff --git a/examples/crate_universe/cargo_remote/.bazelrc b/examples/crate_universe/cargo_remote/.bazelrc deleted file mode 100644 index a67f1baf7f..0000000000 --- a/examples/crate_universe/cargo_remote/.bazelrc +++ /dev/null @@ -1,25 +0,0 @@ -# A config file containing Bazel settings - -# Required on windows -common --enable_platform_specific_config -startup --windows_enable_symlinks -build:windows --enable_runfiles - -# Enable rustfmt -build:strict --aspects=@rules_rust//rust:defs.bzl%rustfmt_aspect -build:strict --output_groups=+rustfmt_checks - -# Enable clippy -build:strict --aspects=@rules_rust//rust:defs.bzl%rust_clippy_aspect -build:strict --output_groups=+clippy_checks - -# TODO: migrate all dependencies from WORKSPACE to MODULE.bazel -# https://github.com/bazelbuild/rules_rust/issues/2181 -common --noenable_bzlmod - -# This isn't currently the defaut in Bazel, but we enable it to test we'll be ready if/when it flips. -build --incompatible_disallow_empty_glob - -# This import should always be last to allow users to override -# settings for local development. -try-import %workspace%/user.bazelrc diff --git a/examples/crate_universe/cargo_workspace/.bazelrc b/examples/crate_universe/cargo_workspace/.bazelrc deleted file mode 100644 index a67f1baf7f..0000000000 --- a/examples/crate_universe/cargo_workspace/.bazelrc +++ /dev/null @@ -1,25 +0,0 @@ -# A config file containing Bazel settings - -# Required on windows -common --enable_platform_specific_config -startup --windows_enable_symlinks -build:windows --enable_runfiles - -# Enable rustfmt -build:strict --aspects=@rules_rust//rust:defs.bzl%rustfmt_aspect -build:strict --output_groups=+rustfmt_checks - -# Enable clippy -build:strict --aspects=@rules_rust//rust:defs.bzl%rust_clippy_aspect -build:strict --output_groups=+clippy_checks - -# TODO: migrate all dependencies from WORKSPACE to MODULE.bazel -# https://github.com/bazelbuild/rules_rust/issues/2181 -common --noenable_bzlmod - -# This isn't currently the defaut in Bazel, but we enable it to test we'll be ready if/when it flips. -build --incompatible_disallow_empty_glob - -# This import should always be last to allow users to override -# settings for local development. -try-import %workspace%/user.bazelrc diff --git a/examples/crate_universe/multi_package/.bazelrc b/examples/crate_universe/multi_package/.bazelrc deleted file mode 100644 index a67f1baf7f..0000000000 --- a/examples/crate_universe/multi_package/.bazelrc +++ /dev/null @@ -1,25 +0,0 @@ -# A config file containing Bazel settings - -# Required on windows -common --enable_platform_specific_config -startup --windows_enable_symlinks -build:windows --enable_runfiles - -# Enable rustfmt -build:strict --aspects=@rules_rust//rust:defs.bzl%rustfmt_aspect -build:strict --output_groups=+rustfmt_checks - -# Enable clippy -build:strict --aspects=@rules_rust//rust:defs.bzl%rust_clippy_aspect -build:strict --output_groups=+clippy_checks - -# TODO: migrate all dependencies from WORKSPACE to MODULE.bazel -# https://github.com/bazelbuild/rules_rust/issues/2181 -common --noenable_bzlmod - -# This isn't currently the defaut in Bazel, but we enable it to test we'll be ready if/when it flips. -build --incompatible_disallow_empty_glob - -# This import should always be last to allow users to override -# settings for local development. -try-import %workspace%/user.bazelrc diff --git a/examples/crate_universe/no_cargo_manifests/.bazelrc b/examples/crate_universe/no_cargo_manifests/.bazelrc deleted file mode 100644 index a67f1baf7f..0000000000 --- a/examples/crate_universe/no_cargo_manifests/.bazelrc +++ /dev/null @@ -1,25 +0,0 @@ -# A config file containing Bazel settings - -# Required on windows -common --enable_platform_specific_config -startup --windows_enable_symlinks -build:windows --enable_runfiles - -# Enable rustfmt -build:strict --aspects=@rules_rust//rust:defs.bzl%rustfmt_aspect -build:strict --output_groups=+rustfmt_checks - -# Enable clippy -build:strict --aspects=@rules_rust//rust:defs.bzl%rust_clippy_aspect -build:strict --output_groups=+clippy_checks - -# TODO: migrate all dependencies from WORKSPACE to MODULE.bazel -# https://github.com/bazelbuild/rules_rust/issues/2181 -common --noenable_bzlmod - -# This isn't currently the defaut in Bazel, but we enable it to test we'll be ready if/when it flips. -build --incompatible_disallow_empty_glob - -# This import should always be last to allow users to override -# settings for local development. -try-import %workspace%/user.bazelrc