Skip to content

Commit 6450253

Browse files
authored
Moved cargo_dep_env into it's own file. (#2823)
I've also added some additional tests for `cargo_build_script`.
1 parent 73b1594 commit 6450253

File tree

10 files changed

+258
-110
lines changed

10 files changed

+258
-110
lines changed

cargo/defs.bzl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ load(
55
_cargo_bootstrap_repository = "cargo_bootstrap_repository",
66
_cargo_env = "cargo_env",
77
)
8-
load(
9-
"//cargo/private:cargo_build_script.bzl",
10-
_cargo_dep_env = "cargo_dep_env",
11-
)
128
load(
139
"//cargo/private:cargo_build_script_wrapper.bzl",
1410
_cargo_build_script = "cargo_build_script",
1511
)
12+
load(
13+
"//cargo/private:cargo_dep_env.bzl",
14+
_cargo_dep_env = "cargo_dep_env",
15+
)
1616

1717
cargo_bootstrap_repository = _cargo_bootstrap_repository
1818
cargo_env = _cargo_env

cargo/private/cargo_build_script.bzl

Lines changed: 1 addition & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo")
55
load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
66
load("@rules_cc//cc:action_names.bzl", "ACTION_NAMES")
77
load("//rust:defs.bzl", "rust_common")
8-
load("//rust:rust_common.bzl", "BuildInfo", "DepInfo")
8+
load("//rust:rust_common.bzl", "BuildInfo")
99

1010
# buildifier: disable=bzl-visibility
1111
load(
@@ -402,8 +402,6 @@ cargo_build_script = rule(
402402
file of arguments to rustc: `@$(location //package:target)`.
403403
"""),
404404
),
405-
# The source of truth will be the `cargo_build_script` macro until stardoc
406-
# implements documentation inheritence. See https://github.com/bazelbuild/stardoc/issues/27
407405
"script": attr.label(
408406
doc = "The binary script to run, generally a `rust_binary` target.",
409407
executable = True,
@@ -458,104 +456,3 @@ def name_to_pkg_name(name):
458456
if name.endswith("_bs"):
459457
return name[:-len("_bs")]
460458
return name
461-
462-
def _cargo_dep_env_implementation(ctx):
463-
empty_file = ctx.actions.declare_file(ctx.label.name + ".empty_file")
464-
empty_dir = ctx.actions.declare_directory(ctx.label.name + ".empty_dir")
465-
ctx.actions.write(
466-
output = empty_file,
467-
content = "",
468-
)
469-
ctx.actions.run(
470-
outputs = [empty_dir],
471-
executable = "true",
472-
)
473-
474-
build_infos = []
475-
out_dir = ctx.file.out_dir
476-
if out_dir:
477-
if not out_dir.is_directory:
478-
fail("out_dir must be a directory artifact")
479-
480-
# BuildInfos in this list are collected up for all transitive cargo_build_script
481-
# dependencies. This is important for any flags set in `dep_env` which reference this
482-
# `out_dir`.
483-
#
484-
# TLDR: This BuildInfo propagates up build script dependencies.
485-
build_infos.append(BuildInfo(
486-
dep_env = empty_file,
487-
flags = empty_file,
488-
linker_flags = empty_file,
489-
link_search_paths = empty_file,
490-
out_dir = out_dir,
491-
rustc_env = empty_file,
492-
compile_data = depset([]),
493-
))
494-
return [
495-
DefaultInfo(files = depset(ctx.files.src)),
496-
# Parts of this BuildInfo is used when building all transitive dependencies
497-
# (cargo_build_script and otherwise), alongside the DepInfo. This is how other rules
498-
# identify this one as a valid dependency, but we don't otherwise have a use for it.
499-
#
500-
# TLDR: This BuildInfo propagates up normal (non build script) depenencies.
501-
#
502-
# In the future, we could consider setting rustc_env here, and also propagating dep_dir
503-
# so files in it can be referenced there.
504-
BuildInfo(
505-
dep_env = empty_file,
506-
flags = empty_file,
507-
linker_flags = empty_file,
508-
link_search_paths = empty_file,
509-
out_dir = None,
510-
rustc_env = empty_file,
511-
compile_data = depset([]),
512-
),
513-
# Information here is used directly by dependencies, and it is an error to have more than
514-
# one dependency which sets this. This is the main way to specify information from build
515-
# scripts, which is what we're looking to do.
516-
DepInfo(
517-
dep_env = ctx.file.src,
518-
direct_crates = depset(),
519-
link_search_path_files = depset(),
520-
transitive_build_infos = depset(direct = build_infos),
521-
transitive_crate_outputs = depset(),
522-
transitive_crates = depset(),
523-
transitive_noncrates = depset(),
524-
),
525-
]
526-
527-
cargo_dep_env = rule(
528-
implementation = _cargo_dep_env_implementation,
529-
doc = (
530-
"A rule for generating variables for dependent `cargo_build_script`s " +
531-
"without a build script. This is useful for using Bazel rules instead " +
532-
"of a build script, while also generating configuration information " +
533-
"for build scripts which depend on this crate."
534-
),
535-
attrs = {
536-
"out_dir": attr.label(
537-
doc = dedent("""\
538-
Folder containing additional inputs when building all direct dependencies.
539-
540-
This has the same effect as a `cargo_build_script` which prints
541-
puts files into `$OUT_DIR`, but without requiring a build script.
542-
"""),
543-
allow_single_file = True,
544-
mandatory = False,
545-
),
546-
"src": attr.label(
547-
doc = dedent("""\
548-
File containing additional environment variables to set for build scripts of direct dependencies.
549-
550-
This has the same effect as a `cargo_build_script` which prints
551-
`cargo:VAR=VALUE` lines, but without requiring a build script.
552-
553-
This files should contain a single variable per line, of format
554-
`NAME=value`, and newlines may be included in a value by ending a
555-
line with a trailing back-slash (`\\\\`).
556-
"""),
557-
allow_single_file = True,
558-
mandatory = True,
559-
),
560-
},
561-
)

cargo/private/cargo_dep_env.bzl

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
"""Rules for Cargo build scripts (`build.rs` files)"""
2+
3+
load("//rust:rust_common.bzl", "BuildInfo", "DepInfo")
4+
5+
# buildifier: disable=bzl-visibility
6+
load("//rust/private:utils.bzl", "dedent")
7+
8+
def _cargo_dep_env_impl(ctx):
9+
empty_file = ctx.actions.declare_file(ctx.label.name + ".empty_file")
10+
empty_dir = ctx.actions.declare_directory(ctx.label.name + ".empty_dir")
11+
ctx.actions.write(
12+
output = empty_file,
13+
content = "",
14+
)
15+
ctx.actions.run(
16+
outputs = [empty_dir],
17+
executable = "true",
18+
)
19+
20+
build_infos = []
21+
out_dir = ctx.file.out_dir
22+
if out_dir:
23+
if not out_dir.is_directory:
24+
fail("out_dir must be a directory artifact")
25+
26+
# BuildInfos in this list are collected up for all transitive cargo_build_script
27+
# dependencies. This is important for any flags set in `dep_env` which reference this
28+
# `out_dir`.
29+
#
30+
# TLDR: This BuildInfo propagates up build script dependencies.
31+
build_infos.append(BuildInfo(
32+
dep_env = empty_file,
33+
flags = empty_file,
34+
linker_flags = empty_file,
35+
link_search_paths = empty_file,
36+
out_dir = out_dir,
37+
rustc_env = empty_file,
38+
compile_data = depset([]),
39+
))
40+
return [
41+
DefaultInfo(files = depset(ctx.files.src)),
42+
# Parts of this BuildInfo is used when building all transitive dependencies
43+
# (cargo_build_script and otherwise), alongside the DepInfo. This is how other rules
44+
# identify this one as a valid dependency, but we don't otherwise have a use for it.
45+
#
46+
# TLDR: This BuildInfo propagates up normal (non build script) depenencies.
47+
#
48+
# In the future, we could consider setting rustc_env here, and also propagating dep_dir
49+
# so files in it can be referenced there.
50+
BuildInfo(
51+
dep_env = empty_file,
52+
flags = empty_file,
53+
linker_flags = empty_file,
54+
link_search_paths = empty_file,
55+
out_dir = None,
56+
rustc_env = empty_file,
57+
compile_data = depset([]),
58+
),
59+
# Information here is used directly by dependencies, and it is an error to have more than
60+
# one dependency which sets this. This is the main way to specify information from build
61+
# scripts, which is what we're looking to do.
62+
DepInfo(
63+
dep_env = ctx.file.src,
64+
direct_crates = depset(),
65+
link_search_path_files = depset(),
66+
transitive_build_infos = depset(direct = build_infos),
67+
transitive_crate_outputs = depset(),
68+
transitive_crates = depset(),
69+
transitive_noncrates = depset(),
70+
),
71+
]
72+
73+
cargo_dep_env = rule(
74+
implementation = _cargo_dep_env_impl,
75+
doc = (
76+
"A rule for generating variables for dependent `cargo_build_script`s " +
77+
"without a build script. This is useful for using Bazel rules instead " +
78+
"of a build script, while also generating configuration information " +
79+
"for build scripts which depend on this crate."
80+
),
81+
attrs = {
82+
"out_dir": attr.label(
83+
doc = dedent("""\
84+
Folder containing additional inputs when building all direct dependencies.
85+
86+
This has the same effect as a `cargo_build_script` which prints
87+
puts files into `$OUT_DIR`, but without requiring a build script.
88+
"""),
89+
allow_single_file = True,
90+
mandatory = False,
91+
),
92+
"src": attr.label(
93+
doc = dedent("""\
94+
File containing additional environment variables to set for build scripts of direct dependencies.
95+
96+
This has the same effect as a `cargo_build_script` which prints
97+
`cargo:VAR=VALUE` lines, but without requiring a build script.
98+
99+
This files should contain a single variable per line, of format
100+
`NAME=value`, and newlines may be included in a value by ending a
101+
line with a trailing back-slash (`\\\\`).
102+
"""),
103+
allow_single_file = True,
104+
mandatory = True,
105+
),
106+
},
107+
)
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
load("@bazel_skylib//rules:write_file.bzl", "write_file")
2+
load("//cargo:defs.bzl", "cargo_build_script")
3+
load("//rust:defs.bzl", "rust_test")
4+
5+
write_file(
6+
name = "target_data",
7+
out = "target_data.txt",
8+
content = ["la-li-lu-le-lo"],
9+
)
10+
11+
write_file(
12+
name = "exec_data",
13+
out = "exec_data.txt",
14+
content = ["la-li-lu-le-lo"],
15+
)
16+
17+
cargo_build_script(
18+
name = "build_rs",
19+
srcs = ["build.rs"],
20+
build_script_env = {
21+
"DATA_EXECPATH": "$(execpath target_data.txt)",
22+
"DATA_RLOCATIONPATH": "$(rlocationpath target_data.txt)",
23+
"DATA_ROOTPATH": "$(rootpath target_data.txt)",
24+
"TOOL_EXECPATH": "$(execpath exec_data.txt)",
25+
"TOOL_RLOCATIONPATH": "$(rlocationpath exec_data.txt)",
26+
"TOOL_ROOTPATH": "$(rootpath exec_data.txt)",
27+
},
28+
data = ["target_data.txt"],
29+
edition = "2018",
30+
tools = ["exec_data.txt"],
31+
)
32+
33+
rust_test(
34+
name = "test",
35+
srcs = ["test.rs"],
36+
edition = "2018",
37+
deps = [":build_rs"],
38+
)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
fn main() {
2+
println!(
3+
"cargo:rustc-env=DATA_ROOTPATH={}",
4+
std::env::var("DATA_ROOTPATH").expect("Environment variable not set")
5+
);
6+
println!(
7+
"cargo:rustc-env=DATA_EXECPATH={}",
8+
std::env::var("DATA_EXECPATH").expect("Environment variable not set")
9+
);
10+
println!(
11+
"cargo:rustc-env=DATA_RLOCATIONPATH={}",
12+
std::env::var("DATA_RLOCATIONPATH").expect("Environment variable not set")
13+
);
14+
println!(
15+
"cargo:rustc-env=TOOL_ROOTPATH={}",
16+
std::env::var("TOOL_ROOTPATH").expect("Environment variable not set")
17+
);
18+
println!(
19+
"cargo:rustc-env=TOOL_EXECPATH={}",
20+
std::env::var("TOOL_EXECPATH").expect("Environment variable not set")
21+
);
22+
println!(
23+
"cargo:rustc-env=TOOL_RLOCATIONPATH={}",
24+
std::env::var("TOOL_RLOCATIONPATH").expect("Environment variable not set")
25+
);
26+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#[test]
2+
pub fn test_data_rootpath() {
3+
assert_eq!(
4+
"test/cargo_build_script/location_expansion/target_data.txt",
5+
env!("DATA_ROOTPATH")
6+
);
7+
}
8+
9+
#[test]
10+
pub fn test_data_rlocation() {
11+
assert_eq!(
12+
"rules_rust/test/cargo_build_script/location_expansion/target_data.txt",
13+
env!("DATA_RLOCATIONPATH")
14+
);
15+
}
16+
17+
#[test]
18+
pub fn test_tool_rootpath() {
19+
assert_eq!(
20+
"test/cargo_build_script/location_expansion/exec_data.txt",
21+
env!("TOOL_ROOTPATH")
22+
);
23+
}
24+
25+
#[test]
26+
pub fn test_tool_rlocationpath() {
27+
assert_eq!(
28+
"rules_rust/test/cargo_build_script/location_expansion/exec_data.txt",
29+
env!("TOOL_RLOCATIONPATH")
30+
);
31+
}
32+
33+
#[test]
34+
pub fn test_execpath() {
35+
// Replace `\` to ensure paths are consistent on Windows.`
36+
let data_execpath = env!("DATA_EXECPATH").replace('\\', "/");
37+
let tool_execpath = env!("TOOL_EXECPATH").replace('\\', "/");
38+
39+
let data_path = data_execpath
40+
.split_at(
41+
data_execpath
42+
.find("/bazel-out/")
43+
.unwrap_or_else(|| panic!("Failed to parse execroot from: {}", data_execpath)),
44+
)
45+
.1;
46+
let tool_path = tool_execpath
47+
.split_at(
48+
tool_execpath
49+
.find("/bazel-out/")
50+
.unwrap_or_else(|| panic!("Failed to parse execroot from: {}", tool_execpath)),
51+
)
52+
.1;
53+
54+
let (data_cfg, data_short_path) = data_path.split_at(
55+
data_path
56+
.find("/bin/")
57+
.unwrap_or_else(|| panic!("Failed to find bin in {}", data_path))
58+
+ "/bin/".len(),
59+
);
60+
let (tool_cfg, tool_short_path) = tool_path.split_at(
61+
tool_path
62+
.find("/bin/")
63+
.unwrap_or_else(|| panic!("Failed to find bin in {}", tool_path))
64+
+ "/bin/".len(),
65+
);
66+
67+
assert_ne!(
68+
data_cfg, tool_cfg,
69+
"Data and tools should not be from the same configuration."
70+
);
71+
72+
assert_eq!(
73+
data_short_path,
74+
"test/cargo_build_script/location_expansion/target_data.txt"
75+
);
76+
assert_eq!(
77+
tool_short_path,
78+
"test/cargo_build_script/location_expansion/exec_data.txt"
79+
);
80+
}

test/cargo_build_script/out_dir/BUILD.bazel

Whitespace-only changes.

0 commit comments

Comments
 (0)