Skip to content

Commit c067415

Browse files
committed
[feat] Add a build setting to announce crate scope
This build setting is not used internally, but provides a way for dependencies to be aware that they are being compiled for a rust crate. Examples of complex scenarios allowed by this change: 1. Build with a mac-x86_64 toolchain on mac-aarch64 platforms (rosetta) - everything (including host tools) is compiled for aarch64 while proc_macros must be compiled for x86_64. 2. A `cc_library` linked to both a `cc_binary` and a `rust_binary`, but needs slightly different build flags when used for rust crates.
1 parent 8de8f2b commit c067415

File tree

10 files changed

+186
-31
lines changed

10 files changed

+186
-31
lines changed

rust/private/BUILD.bazel

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
2+
load("@bazel_skylib//rules:common_settings.bzl", "string_setting")
23
load("//rust/private:rust_analyzer.bzl", "rust_analyzer_detect_sysroot")
34
load("//rust/private:rustc.bzl", "is_proc_macro_dep", "is_proc_macro_dep_enabled")
45
load("//rust/private:stamp.bzl", "stamp_build_setting")
@@ -52,6 +53,24 @@ is_proc_macro_dep_enabled(
5253
visibility = ["//visibility:public"],
5354
)
5455

56+
# The scope of the crate being built.
57+
#
58+
# This setting is not used internally. It announces to the dependencies of rust crates
59+
# (including toolchains) how their outputs are being used, to allow e.g. passing different
60+
# copts to a cc_library when it is part of a crate or a procedure macro.
61+
#
62+
# We specialize proc macro, because it must be ABI compatible with rustc itself.
63+
string_setting(
64+
name = "crate_scope",
65+
build_setting_default = "none",
66+
values = [
67+
"none", # Not building a rust crate or a dep of rust crate
68+
"proc_macro", # Building a proc macro or a dep of proc macro
69+
"regular", # Building a regular crate or a (non-proc-macro) dep of such
70+
],
71+
visibility = ["//rust/settings:__pkg__"],
72+
)
73+
5574
rust_analyzer_detect_sysroot(
5675
name = "rust_analyzer_detect_sysroot",
5776
visibility = ["//visibility:public"],

rust/private/rust.bzl

Lines changed: 55 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,34 @@ def _stamp_attribute(default_value):
526526
values = [1, 0, -1],
527527
)
528528

529+
def _crate_scope_transition_impl(settings, attr):
530+
if hasattr(attr, "_change_crate_scope"):
531+
return {"//rust/private:crate_scope": attr._change_crate_scope}
532+
if settings["//rust/private:crate_scope"] == "proc_macro":
533+
# the whole transitive closure of a proc_macro should be the proc_macro scope,
534+
# except that it is reset by either the _change_crate_scope attr above or the
535+
# _crate_scope_reset_transition below.
536+
return {"//rust/private:crate_scope": "proc_macro"}
537+
return {"//rust/private:crate_scope": "regular"}
538+
539+
_crate_scope_transition_inputs = ["//rust/private:crate_scope"]
540+
_crate_scope_transition_outputs = ["//rust/private:crate_scope"]
541+
542+
_crate_scope_transition = transition(
543+
implementation = _crate_scope_transition_impl,
544+
inputs = _crate_scope_transition_inputs,
545+
outputs = _crate_scope_transition_outputs,
546+
)
547+
548+
def _crate_scope_reset_transition_impl(_settings, _attr):
549+
return {"//rust/private:crate_scope": "none"}
550+
551+
_crate_scope_reset_transition = transition(
552+
implementation = _crate_scope_reset_transition_impl,
553+
inputs = [],
554+
outputs = _crate_scope_transition_outputs,
555+
)
556+
529557
# Internal attributes core to Rustc actions.
530558
RUSTC_ATTRS = {
531559
"_error_format": attr.label(
@@ -591,6 +619,7 @@ _common_attrs = {
591619
macro.
592620
"""),
593621
allow_files = True,
622+
cfg = _crate_scope_reset_transition,
594623
),
595624
"crate_features": attr.string_list(
596625
doc = dedent("""\
@@ -617,6 +646,7 @@ _common_attrs = {
617646
or the single file in `srcs` if `srcs` contains only one file.
618647
"""),
619648
allow_single_file = [".rs"],
649+
cfg = _crate_scope_reset_transition,
620650
),
621651
"data": attr.label_list(
622652
doc = dedent("""\
@@ -627,6 +657,7 @@ _common_attrs = {
627657
in the runfiles.
628658
"""),
629659
allow_files = True,
660+
cfg = _crate_scope_reset_transition,
630661
),
631662
"deps": attr.label_list(
632663
doc = dedent("""\
@@ -723,6 +754,9 @@ _common_attrs = {
723754
doc = "A setting used to determine whether or not the `--stamp` flag is enabled",
724755
default = Label("//rust/private:stamp"),
725756
),
757+
"_allowlist_function_transition": attr.label(
758+
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
759+
),
726760
} | RUSTC_ATTRS
727761

728762
_coverage_attrs = {
@@ -828,6 +862,7 @@ rust_library = rule(
828862
),
829863
},
830864
fragments = ["cpp"],
865+
cfg = _crate_scope_transition,
831866
toolchains = [
832867
str(Label("//rust:toolchain_type")),
833868
"@bazel_tools//tools/cpp:toolchain_type",
@@ -901,16 +936,16 @@ rust_library = rule(
901936
def _rust_static_library_transition_impl(settings, attr):
902937
return {
903938
"//command_line_option:platforms": str(attr.platform) if attr.platform else settings["//command_line_option:platforms"],
904-
}
939+
} | _crate_scope_transition_impl(settings, attr)
905940

906941
_rust_static_library_transition = transition(
907942
implementation = _rust_static_library_transition_impl,
908943
inputs = [
909944
"//command_line_option:platforms",
910-
],
945+
] + _crate_scope_transition_inputs,
911946
outputs = [
912947
"//command_line_option:platforms",
913-
],
948+
] + _crate_scope_transition_outputs,
914949
)
915950

916951
rust_static_library = rule(
@@ -920,9 +955,6 @@ rust_static_library = rule(
920955
doc = "Optional platform to transition the static library to.",
921956
default = None,
922957
),
923-
"_allowlist_function_transition": attr.label(
924-
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
925-
),
926958
},
927959
fragments = ["cpp"],
928960
cfg = _rust_static_library_transition,
@@ -950,16 +982,16 @@ rust_static_library = rule(
950982
def _rust_shared_library_transition_impl(settings, attr):
951983
return {
952984
"//command_line_option:platforms": str(attr.platform) if attr.platform else settings["//command_line_option:platforms"],
953-
}
985+
} | _crate_scope_transition_impl(settings, attr)
954986

955987
_rust_shared_library_transition = transition(
956988
implementation = _rust_shared_library_transition_impl,
957989
inputs = [
958990
"//command_line_option:platforms",
959-
],
991+
] + _crate_scope_transition_inputs,
960992
outputs = [
961993
"//command_line_option:platforms",
962-
],
994+
] + _crate_scope_transition_outputs,
963995
)
964996

965997
rust_shared_library = rule(
@@ -969,9 +1001,6 @@ rust_shared_library = rule(
9691001
doc = "Optional platform to transition the shared library to.",
9701002
default = None,
9711003
),
972-
"_allowlist_function_transition": attr.label(
973-
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
974-
),
9751004
"_use_grep_includes": attr.bool(default = True),
9761005
},
9771006
fragments = ["cpp"],
@@ -1018,9 +1047,7 @@ rust_proc_macro = rule(
10181047
# https://docs.bazel.build/versions/main/skylark/config.html#user-defined-transitions.
10191048
attrs = dict(
10201049
_common_attrs.items(),
1021-
_allowlist_function_transition = attr.label(
1022-
default = Label("//tools/allowlists/function_transition_allowlist"),
1023-
),
1050+
_change_crate_scope = attr.string(default = "proc_macro"),
10241051
deps = attr.label_list(
10251052
doc = dedent("""\
10261053
List of other libraries to be linked to this library target.
@@ -1032,6 +1059,7 @@ rust_proc_macro = rule(
10321059
),
10331060
),
10341061
fragments = ["cpp"],
1062+
cfg = _crate_scope_transition,
10351063
toolchains = [
10361064
str(Label("//rust:toolchain_type")),
10371065
"@bazel_tools//tools/cpp:toolchain_type",
@@ -1074,6 +1102,7 @@ _rust_binary_attrs = {
10741102
Link script to forward into linker via rustc options.
10751103
"""),
10761104
allow_single_file = True,
1105+
cfg = _crate_scope_reset_transition,
10771106
),
10781107
"out_binary": attr.bool(
10791108
doc = (
@@ -1090,16 +1119,16 @@ _rust_binary_attrs = {
10901119
def _rust_binary_transition_impl(settings, attr):
10911120
return {
10921121
"//command_line_option:platforms": str(attr.platform) if attr.platform else settings["//command_line_option:platforms"],
1093-
}
1122+
} | _crate_scope_transition_impl(settings, attr)
10941123

10951124
_rust_binary_transition = transition(
10961125
implementation = _rust_binary_transition_impl,
10971126
inputs = [
10981127
"//command_line_option:platforms",
1099-
],
1128+
] + _crate_scope_transition_inputs,
11001129
outputs = [
11011130
"//command_line_option:platforms",
1102-
],
1131+
] + _crate_scope_transition_outputs,
11031132
)
11041133

11051134
rust_binary = rule(
@@ -1110,9 +1139,6 @@ rust_binary = rule(
11101139
doc = "Optional platform to transition the binary to.",
11111140
default = None,
11121141
),
1113-
"_allowlist_function_transition": attr.label(
1114-
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
1115-
),
11161142
},
11171143
executable = True,
11181144
fragments = ["cpp"],
@@ -1252,9 +1278,7 @@ rust_binary_without_process_wrapper = rule(
12521278
doc = "Optional platform to transition the binary to.",
12531279
default = None,
12541280
),
1255-
"_allowlist_function_transition": attr.label(
1256-
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
1257-
),
1281+
"_change_crate_scope": attr.string(default = "regular"),
12581282
}),
12591283
executable = True,
12601284
fragments = ["cpp"],
@@ -1268,8 +1292,11 @@ rust_binary_without_process_wrapper = rule(
12681292
rust_library_without_process_wrapper = rule(
12691293
implementation = _rust_library_impl,
12701294
provides = COMMON_PROVIDERS,
1271-
attrs = dict(_common_attrs_for_binary_without_process_wrapper(_common_attrs).items()),
1295+
attrs = _common_attrs_for_binary_without_process_wrapper(_common_attrs | {
1296+
"_change_crate_scope": attr.string(default = "regular"),
1297+
}),
12721298
fragments = ["cpp"],
1299+
cfg = _crate_scope_transition,
12731300
toolchains = [
12741301
str(Label("//rust:toolchain_type")),
12751302
"@bazel_tools//tools/cpp:toolchain_type",
@@ -1279,16 +1306,16 @@ rust_library_without_process_wrapper = rule(
12791306
def _rust_test_transition_impl(settings, attr):
12801307
return {
12811308
"//command_line_option:platforms": str(attr.platform) if attr.platform else settings["//command_line_option:platforms"],
1282-
}
1309+
} | _crate_scope_transition_impl(settings, attr)
12831310

12841311
_rust_test_transition = transition(
12851312
implementation = _rust_test_transition_impl,
12861313
inputs = [
12871314
"//command_line_option:platforms",
1288-
],
1315+
] + _crate_scope_transition_inputs,
12891316
outputs = [
12901317
"//command_line_option:platforms",
1291-
],
1318+
] + _crate_scope_transition_outputs,
12921319
)
12931320

12941321
rust_test = rule(
@@ -1299,9 +1326,6 @@ rust_test = rule(
12991326
doc = "Optional platform to transition the test to.",
13001327
default = None,
13011328
),
1302-
"_allowlist_function_transition": attr.label(
1303-
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
1304-
),
13051329
},
13061330
executable = True,
13071331
fragments = ["cpp"],

rust/settings/BUILD.bazel

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,27 @@ bzl_library(
4949
],
5050
)
5151

52+
config_setting(
53+
name = "non_rust_scope",
54+
flag_values = {
55+
"//rust/private:crate_scope": "none",
56+
},
57+
)
58+
59+
config_setting(
60+
name = "proc_macro_scope",
61+
flag_values = {
62+
"//rust/private:crate_scope": "proc_macro",
63+
},
64+
)
65+
66+
config_setting(
67+
name = "regular_crate_scope",
68+
flag_values = {
69+
"//rust/private:crate_scope": "regular",
70+
},
71+
)
72+
5273
capture_clippy_output()
5374

5475
clippy_flag()

test/crate_scope/BUILD.bazel

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
load("//rust:defs.bzl", "rust_library", "rust_proc_macro", "rust_test")
2+
3+
rust_test(
4+
name = "proc_macro_data_test",
5+
srcs = select({
6+
"//rust/settings:regular_crate_scope": ["rust_test.rs"],
7+
# Analysis fails if rust_test doesn't set the condition above.
8+
}),
9+
edition = "2021",
10+
proc_macro_deps = [
11+
":rust_proc_macro",
12+
],
13+
deps = [
14+
":nonmacro_library",
15+
],
16+
)
17+
18+
rust_library(
19+
name = "nonmacro_library",
20+
srcs = select({
21+
"//rust/settings:regular_crate_scope": ["nonmacro_library.rs"],
22+
# Analysis fails if rust_library doesn't set the condition above.
23+
}),
24+
edition = "2021",
25+
proc_macro_deps = [
26+
":rust_proc_macro",
27+
],
28+
)
29+
30+
rust_proc_macro(
31+
name = "rust_proc_macro",
32+
srcs = ["rust_proc_macro.rs"],
33+
data = select({
34+
"//rust/settings:proc_macro_scope": [":proc_macro_data"],
35+
# Analysis fails if rust_proc_macro doesn't set the condition above.
36+
}),
37+
edition = "2021",
38+
rustc_env = {"CARGO_MANIFEST_DIR": package_name()},
39+
deps = [
40+
":proc_macro_helper",
41+
],
42+
)
43+
44+
rust_library(
45+
name = "proc_macro_helper",
46+
srcs = ["proc_macro_helper.rs"],
47+
data = select({
48+
"//rust/settings:proc_macro_scope": [":helper_data"],
49+
# Analysis fails if rust_library doesn't propagate the condition above.
50+
}),
51+
edition = "2021",
52+
rustc_env = {"CARGO_MANIFEST_DIR": package_name()},
53+
)
54+
55+
filegroup(
56+
name = "proc_macro_data",
57+
srcs = select({
58+
"//rust/settings:non_rust_scope": ["proc_macro_data.txt"],
59+
# Analysis fails if the data attribute doesn't reset the condition above.
60+
}),
61+
)
62+
63+
filegroup(
64+
name = "helper_data",
65+
srcs = select({
66+
"//rust/settings:non_rust_scope": ["helper_data.txt"],
67+
# Analysis fails if the data attribute doesn't reset the condition above.
68+
}),
69+
)

test/crate_scope/helper_data.txt

Whitespace-only changes.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
rust_proc_macro::ensure_proc_macro_data_exists!();
2+
3+
pub use rust_proc_macro::ensure_proc_macro_data_exists;

test/crate_scope/proc_macro_data.txt

Whitespace-only changes.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
use std::path::Path;
2+
3+
pub fn ensure_helper_data_exists() {
4+
let path = Path::new(env!("CARGO_MANIFEST_DIR")).join("helper_data.txt");
5+
assert!(path.exists(), "not found: {}", path.display());
6+
}

0 commit comments

Comments
 (0)