diff --git a/cargo/cargo_build_script.bzl b/cargo/cargo_build_script.bzl index 80384d7204..69450a283e 100644 --- a/cargo/cargo_build_script.bzl +++ b/cargo/cargo_build_script.bzl @@ -7,7 +7,7 @@ load("//rust:defs.bzl", "rust_binary", "rust_common") load("//rust/private:rustc.bzl", "BuildInfo", "get_compilation_mode_opts", "get_linker_and_args") # buildifier: disable=bzl-visibility -load("//rust/private:utils.bzl", "expand_dict_value_locations", "find_cc_toolchain", "find_toolchain", "name_to_crate_name") +load("//rust/private:utils.bzl", "dedent", "expand_dict_value_locations", "find_cc_toolchain", "find_toolchain", "name_to_crate_name") def get_cc_compile_env(cc_toolchain, feature_configuration): """Gather cc environment variables from the given `cc_toolchain` @@ -56,11 +56,7 @@ def _build_script_impl(ctx): pkg_name = _name_to_pkg_name(ctx.label.name) - toolchain_tools = [ - # Needed for rustc to function. - toolchain.rustc_lib, - toolchain.rust_std, - ] + toolchain_tools = [toolchain.all_files] cc_toolchain = find_cpp_toolchain(ctx) @@ -121,6 +117,13 @@ def _build_script_impl(ctx): if cc_toolchain.sysroot: env["SYSROOT"] = cc_toolchain.sysroot + # Inform build scripts of rustc flags + # https://github.com/rust-lang/cargo/issues/9600 + env["CARGO_ENCODED_RUSTFLAGS"] = "\\x1f".join([ + # Allow build scripts to locate the generated sysroot + "--sysroot=${{pwd}}/{}".format(toolchain.sysroot), + ] + ctx.attr.rustc_flags) + for f in ctx.attr.crate_features: env["CARGO_FEATURE_" + f.upper().replace("-", "_")] = "1" @@ -136,7 +139,6 @@ def _build_script_impl(ctx): direct = [ script, ctx.executable._cargo_build_script_runner, - toolchain.rustc, ] + ctx.files.data + ctx.files.tools + ([toolchain.target_json] if toolchain.target_json else []), transitive = toolchain_tools, ) @@ -217,6 +219,16 @@ _build_script_run = rule( "links": attr.string( doc = "The name of the native library this crate links against.", ), + "rustc_flags": attr.string_list( + doc = dedent("""\ + List of compiler flags passed to `rustc`. + + These strings are subject to Make variable expansion for predefined + source/output path variables like `$location`, `$execpath`, and + `$rootpath`. This expansion is useful if you wish to pass a generated + file of arguments to rustc: `@$(location //package:target)`. + """), + ), # The source of truth will be the `cargo_build_script` macro until stardoc # implements documentation inheritence. See https://github.com/bazelbuild/stardoc/issues/27 "script": attr.label( @@ -262,6 +274,7 @@ def cargo_build_script( tools = [], links = None, rustc_env = {}, + rustc_flags = [], visibility = None, tags = None, **kwargs): @@ -333,6 +346,7 @@ def cargo_build_script( tools (list, optional): Tools (executables) needed by the build script. links (str, optional): Name of the native library this crate links against. rustc_env (dict, optional): Environment variables to set in rustc when compiling the build script. + rustc_flags (list, optional): List of compiler flags passed to `rustc`. visibility (list of label, optional): Visibility to apply to the generated build script output. tags: (list of str, optional): Tags to apply to the generated build script output. **kwargs: Forwards to the underlying `rust_binary` rule. @@ -357,6 +371,7 @@ def cargo_build_script( deps = deps, data = data, rustc_env = rustc_env, + rustc_flags = rustc_flags, tags = binary_tags, **kwargs ) @@ -370,6 +385,7 @@ def cargo_build_script( deps = deps, data = data, tools = tools, + rustc_flags = rustc_flags, visibility = visibility, tags = tags, ) diff --git a/cargo/cargo_build_script_runner/bin.rs b/cargo/cargo_build_script_runner/bin.rs index 2f305e053f..58f0363831 100644 --- a/cargo/cargo_build_script_runner/bin.rs +++ b/cargo/cargo_build_script_runner/bin.rs @@ -123,6 +123,15 @@ fn run_buildrs() -> Result<(), String> { } } + // Bazel does not support byte strings so in order to correctly represent `CARGO_ENCODED_RUSTFLAGS` + // the escaped `\x1f` sequences need to be unescaped + if let Ok(encoded_rustflags) = env::var("CARGO_ENCODED_RUSTFLAGS") { + command.env( + "CARGO_ENCODED_RUSTFLAGS", + encoded_rustflags.replace("\\x1f", "\x1f"), + ); + } + let (buildrs_outputs, process_output) = BuildScriptOutput::outputs_from_command(&mut command) .map_err(|process_output| { format!( diff --git a/docs/cargo.md b/docs/cargo.md index bd1dc273b5..146e9e1133 100644 --- a/docs/cargo.md +++ b/docs/cargo.md @@ -46,7 +46,7 @@ A rule for bootstrapping a Rust binary using [Cargo](https://doc.rust-lang.org/c
 cargo_build_script(name, crate_features, version, deps, build_script_env, data, tools, links,
-                   rustc_env, visibility, tags, kwargs)
+                   rustc_env, rustc_flags, visibility, tags, kwargs)
 
Compile and execute a rust build script to generate build attributes @@ -121,6 +121,7 @@ The `hello_lib` target will be build with the flags and the environment variable | tools | Tools (executables) needed by the build script. | [] | | links | Name of the native library this crate links against. | None | | rustc_env | Environment variables to set in rustc when compiling the build script. | {} | +| rustc_flags | List of compiler flags passed to rustc. | [] | | visibility | Visibility to apply to the generated build script output. | None | | tags | (list of str, optional): Tags to apply to the generated build script output. | None | | kwargs | Forwards to the underlying rust_binary rule. | none | diff --git a/docs/flatten.md b/docs/flatten.md index 928b8b6564..88c7388878 100644 --- a/docs/flatten.md +++ b/docs/flatten.md @@ -1389,7 +1389,7 @@ A collection of files either found within the `rust-stdlib` artifact or generate
 cargo_build_script(name, crate_features, version, deps, build_script_env, data, tools, links,
-                   rustc_env, visibility, tags, kwargs)
+                   rustc_env, rustc_flags, visibility, tags, kwargs)
 
Compile and execute a rust build script to generate build attributes @@ -1464,6 +1464,7 @@ The `hello_lib` target will be build with the flags and the environment variable | tools | Tools (executables) needed by the build script. | [] | | links | Name of the native library this crate links against. | None | | rustc_env | Environment variables to set in rustc when compiling the build script. | {} | +| rustc_flags | List of compiler flags passed to rustc. | [] | | visibility | Visibility to apply to the generated build script output. | None | | tags | (list of str, optional): Tags to apply to the generated build script output. | None | | kwargs | Forwards to the underlying rust_binary rule. | none | diff --git a/test/cargo_build_script/BUILD.bazel b/test/cargo_build_script/BUILD.bazel index 84fc960be2..34744cbabd 100644 --- a/test/cargo_build_script/BUILD.bazel +++ b/test/cargo_build_script/BUILD.bazel @@ -8,6 +8,8 @@ cargo_build_script( name = "tools_exec_build_rs", srcs = ["build.rs"], build_script_env = {"TOOL": "$(execpath :tool)"}, + # Add a flag to test that they're exposed to the build script + rustc_flags = ["--verbose"], tools = [":tool"], ) diff --git a/test/cargo_build_script/build.rs b/test/cargo_build_script/build.rs index 68cef72321..12d1b53d6e 100644 --- a/test/cargo_build_script/build.rs +++ b/test/cargo_build_script/build.rs @@ -1,4 +1,27 @@ +//! A Cargo build script binary used in unit tests for the Bazel `cargo_build_script` rule + +/// `cargo_build_script` should always set `CARGO_ENCODED_RUSTFLAGS` +fn test_encoded_rustflags() { + let encoded_rustflags = std::env::var("CARGO_ENCODED_RUSTFLAGS").unwrap(); + + let flags: Vec = encoded_rustflags + .split('\x1f') + .map(str::to_string) + .collect(); + assert_eq!(flags.len(), 2); + + assert!(flags[0].starts_with("--sysroot")); + + // Ensure the `pwd` template has been resolved + assert!(!flags[0].contains("${pwd}")); + + assert_eq!(flags[1], "--verbose"); +} + fn main() { + // Perform some unit testing + test_encoded_rustflags(); + // Pass the TOOL_PATH along to the rust_test so we can assert on it. println!( "cargo:rustc-env=TOOL_PATH={}",