Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow cargo_build_script to forward rustc args to build scripts #1165

Merged
merged 9 commits into from
Mar 4, 2022
30 changes: 23 additions & 7 deletions cargo/cargo_build_script.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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"

Expand All @@ -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,
)
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -262,6 +274,7 @@ def cargo_build_script(
tools = [],
links = None,
rustc_env = {},
rustc_flags = [],
visibility = None,
tags = None,
**kwargs):
Expand Down Expand Up @@ -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.
Expand All @@ -357,6 +371,7 @@ def cargo_build_script(
deps = deps,
data = data,
rustc_env = rustc_env,
rustc_flags = rustc_flags,
tags = binary_tags,
**kwargs
)
Expand All @@ -370,6 +385,7 @@ def cargo_build_script(
deps = deps,
data = data,
tools = tools,
rustc_flags = rustc_flags,
visibility = visibility,
tags = tags,
)
Expand Down
9 changes: 9 additions & 0 deletions cargo/cargo_build_script_runner/bin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,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"),
);
}

if let Some(ar_path) = env::var_os("AR") {
// The default OSX toolchain uses libtool as ar_executable not ar.
// This doesn't work when used as $AR, so simply don't set it - tools will probably fall back to
Expand Down
3 changes: 2 additions & 1 deletion docs/cargo.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ A rule for bootstrapping a Rust binary using [Cargo](https://doc.rust-lang.org/c

<pre>
cargo_build_script(<a href="#cargo_build_script-name">name</a>, <a href="#cargo_build_script-crate_features">crate_features</a>, <a href="#cargo_build_script-version">version</a>, <a href="#cargo_build_script-deps">deps</a>, <a href="#cargo_build_script-build_script_env">build_script_env</a>, <a href="#cargo_build_script-data">data</a>, <a href="#cargo_build_script-tools">tools</a>, <a href="#cargo_build_script-links">links</a>,
<a href="#cargo_build_script-rustc_env">rustc_env</a>, <a href="#cargo_build_script-visibility">visibility</a>, <a href="#cargo_build_script-tags">tags</a>, <a href="#cargo_build_script-kwargs">kwargs</a>)
<a href="#cargo_build_script-rustc_env">rustc_env</a>, <a href="#cargo_build_script-rustc_flags">rustc_flags</a>, <a href="#cargo_build_script-visibility">visibility</a>, <a href="#cargo_build_script-tags">tags</a>, <a href="#cargo_build_script-kwargs">kwargs</a>)
</pre>

Compile and execute a rust build script to generate build attributes
Expand Down Expand Up @@ -121,6 +121,7 @@ The `hello_lib` target will be build with the flags and the environment variable
| <a id="cargo_build_script-tools"></a>tools | Tools (executables) needed by the build script. | <code>[]</code> |
| <a id="cargo_build_script-links"></a>links | Name of the native library this crate links against. | <code>None</code> |
| <a id="cargo_build_script-rustc_env"></a>rustc_env | Environment variables to set in rustc when compiling the build script. | <code>{}</code> |
| <a id="cargo_build_script-rustc_flags"></a>rustc_flags | List of compiler flags passed to <code>rustc</code>. | <code>[]</code> |
| <a id="cargo_build_script-visibility"></a>visibility | Visibility to apply to the generated build script output. | <code>None</code> |
| <a id="cargo_build_script-tags"></a>tags | (list of str, optional): Tags to apply to the generated build script output. | <code>None</code> |
| <a id="cargo_build_script-kwargs"></a>kwargs | Forwards to the underlying <code>rust_binary</code> rule. | none |
Expand Down
3 changes: 2 additions & 1 deletion docs/flatten.md
Original file line number Diff line number Diff line change
Expand Up @@ -1389,7 +1389,7 @@ A collection of files either found within the `rust-stdlib` artifact or generate

<pre>
cargo_build_script(<a href="#cargo_build_script-name">name</a>, <a href="#cargo_build_script-crate_features">crate_features</a>, <a href="#cargo_build_script-version">version</a>, <a href="#cargo_build_script-deps">deps</a>, <a href="#cargo_build_script-build_script_env">build_script_env</a>, <a href="#cargo_build_script-data">data</a>, <a href="#cargo_build_script-tools">tools</a>, <a href="#cargo_build_script-links">links</a>,
<a href="#cargo_build_script-rustc_env">rustc_env</a>, <a href="#cargo_build_script-visibility">visibility</a>, <a href="#cargo_build_script-tags">tags</a>, <a href="#cargo_build_script-kwargs">kwargs</a>)
<a href="#cargo_build_script-rustc_env">rustc_env</a>, <a href="#cargo_build_script-rustc_flags">rustc_flags</a>, <a href="#cargo_build_script-visibility">visibility</a>, <a href="#cargo_build_script-tags">tags</a>, <a href="#cargo_build_script-kwargs">kwargs</a>)
</pre>

Compile and execute a rust build script to generate build attributes
Expand Down Expand Up @@ -1464,6 +1464,7 @@ The `hello_lib` target will be build with the flags and the environment variable
| <a id="cargo_build_script-tools"></a>tools | Tools (executables) needed by the build script. | <code>[]</code> |
| <a id="cargo_build_script-links"></a>links | Name of the native library this crate links against. | <code>None</code> |
| <a id="cargo_build_script-rustc_env"></a>rustc_env | Environment variables to set in rustc when compiling the build script. | <code>{}</code> |
| <a id="cargo_build_script-rustc_flags"></a>rustc_flags | List of compiler flags passed to <code>rustc</code>. | <code>[]</code> |
| <a id="cargo_build_script-visibility"></a>visibility | Visibility to apply to the generated build script output. | <code>None</code> |
| <a id="cargo_build_script-tags"></a>tags | (list of str, optional): Tags to apply to the generated build script output. | <code>None</code> |
| <a id="cargo_build_script-kwargs"></a>kwargs | Forwards to the underlying <code>rust_binary</code> rule. | none |
Expand Down
2 changes: 2 additions & 0 deletions test/cargo_build_script/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -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"],
)

Expand Down
20 changes: 20 additions & 0 deletions test/cargo_build_script/build.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,24 @@
//! 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<String> = encoded_rustflags
.split('\x1f')
.map(str::to_string)
.collect();
assert_eq!(flags.len(), 2);

assert!(flags[0].starts_with("--sysroot"));
assert!(flags[1].starts_with("--verbose"));
UebelAndre marked this conversation as resolved.
Show resolved Hide resolved
}

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={}",
Expand Down