Skip to content

Commit 6bf03f2

Browse files
authored
Allow rustc_compile_action to threat all dependencies as direct depenencies (#970)
1 parent 4efa71d commit 6bf03f2

File tree

6 files changed

+202
-10
lines changed

6 files changed

+202
-10
lines changed

rust/private/rustc.bzl

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,8 @@ def construct_arguments(
448448
out_dir,
449449
build_env_files,
450450
build_flags_files,
451-
emit = ["dep-info", "link"]):
451+
emit = ["dep-info", "link"],
452+
force_all_deps_direct = False):
452453
"""Builds an Args object containing common rustc flags
453454
454455
Args:
@@ -468,6 +469,8 @@ def construct_arguments(
468469
build_env_files (list): Files containing rustc environment variables, for instance from `cargo_build_script` actions.
469470
build_flags_files (list): The output files of a `cargo_build_script` actions containing rustc build flags
470471
emit (list): Values for the --emit flag to rustc.
472+
force_all_deps_direct (bool, optional): Whether to pass the transitive rlibs with --extern
473+
to the commandline as opposed to -L.
471474
472475
Returns:
473476
tuple: A tuple of the following items
@@ -598,7 +601,7 @@ def construct_arguments(
598601
_add_native_link_flags(rustc_flags, dep_info, linkstamp_outs, crate_info.type, toolchain, cc_toolchain, feature_configuration)
599602

600603
# These always need to be added, even if not linking this crate.
601-
add_crate_link_flags(rustc_flags, dep_info)
604+
add_crate_link_flags(rustc_flags, dep_info, force_all_deps_direct)
602605

603606
needs_extern_proc_macro_flag = "proc-macro" in [crate_info.type, crate_info.wrapped_crate_type] and \
604607
crate_info.edition != "2015"
@@ -647,7 +650,8 @@ def rustc_compile_action(
647650
crate_info,
648651
output_hash = None,
649652
rust_flags = [],
650-
environ = {}):
653+
environ = {},
654+
force_all_deps_direct = False):
651655
"""Create and run a rustc compile action based on the current rule's attributes
652656
653657
Args:
@@ -658,6 +662,8 @@ def rustc_compile_action(
658662
output_hash (str, optional): The hashed path of the crate root. Defaults to None.
659663
rust_flags (list, optional): Additional flags to pass to rustc. Defaults to [].
660664
environ (dict, optional): A set of makefile expandable environment variables for the action
665+
force_all_deps_direct (bool, optional): Whether to pass the transitive rlibs with --extern
666+
to the commandline as opposed to -L.
661667
662668
Returns:
663669
list: A list of the following providers:
@@ -710,6 +716,7 @@ def rustc_compile_action(
710716
out_dir = out_dir,
711717
build_env_files = build_env_files,
712718
build_flags_files = build_flags_files,
719+
force_all_deps_direct = force_all_deps_direct,
713720
)
714721

715722
if hasattr(attr, "version") and attr.version != "0.0.0":
@@ -962,33 +969,55 @@ def _get_dir_names(files):
962969
dirs[f.dirname] = None
963970
return dirs.keys()
964971

965-
def add_crate_link_flags(args, dep_info):
972+
def add_crate_link_flags(args, dep_info, force_all_deps_direct = False):
966973
"""Adds link flags to an Args object reference
967974
968975
Args:
969976
args (Args): An arguments object reference
970977
dep_info (DepInfo): The current target's dependency info
978+
force_all_deps_direct (bool, optional): Whether to pass the transitive rlibs with --extern
979+
to the commandline as opposed to -L.
971980
"""
972981

973-
# nb. Crates are linked via --extern regardless of their crate_type
974-
args.add_all(dep_info.direct_crates, map_each = _crate_to_link_flag)
982+
if force_all_deps_direct:
983+
args.add_all(
984+
depset(
985+
transitive = [
986+
dep_info.direct_crates,
987+
dep_info.transitive_crates,
988+
],
989+
),
990+
uniquify = True,
991+
map_each = _crate_to_link_flag,
992+
)
993+
else:
994+
# nb. Direct crates are linked via --extern regardless of their crate_type
995+
args.add_all(dep_info.direct_crates, map_each = _crate_to_link_flag)
975996
args.add_all(
976997
dep_info.transitive_crates,
977998
map_each = _get_crate_dirname,
978999
uniquify = True,
9791000
format_each = "-Ldependency=%s",
9801001
)
9811002

982-
def _crate_to_link_flag(crate_info):
1003+
def _crate_to_link_flag(crate):
9831004
"""A helper macro used by `add_crate_link_flags` for adding crate link flags to a Arg object
9841005
9851006
Args:
986-
crate_info (CrateInfo): A CrateInfo provider from the current rule
1007+
crate (CrateInfo|AliasableDepInfo): A CrateInfo or an AliasableDepInfo provider
9871008
9881009
Returns:
989-
list: Link flags for the current crate info
1010+
list: Link flags for the given provider
9901011
"""
991-
return ["--extern={}={}".format(crate_info.name, crate_info.dep.output.path)]
1012+
1013+
# This is AliasableDepInfo, we should use the alias as a crate name
1014+
if hasattr(crate, "dep"):
1015+
name = crate.name
1016+
crate_info = crate.dep
1017+
else:
1018+
name = crate.name
1019+
crate_info = crate
1020+
return ["--extern={}={}".format(name, crate_info.output.path)]
9921021

9931022
def _get_crate_dirname(crate):
9941023
"""A helper macro used by `add_crate_link_flags` for getting the directory name of the current crate's output path
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
load(":force_all_deps_direct_test.bzl", "force_all_deps_direct_test_suite")
2+
3+
############################ UNIT TESTS #############################
4+
force_all_deps_direct_test_suite(name = "force_all_deps_direct_test_suite")
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
use transitive::transitive_fn;
2+
3+
pub fn direct_fn() {
4+
transitive_fn();
5+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
"""Unittest to verify that we can treat all dependencies as direct dependencies"""
2+
3+
load("@bazel_skylib//lib:unittest.bzl", "analysistest")
4+
load("//rust:defs.bzl", "rust_library")
5+
load("//test/unit:common.bzl", "assert_action_mnemonic", "assert_argv_contains_prefix")
6+
load("//test/unit/force_all_deps_direct:generator.bzl", "generator")
7+
8+
def _force_all_deps_direct_rustc_flags_test(ctx):
9+
env = analysistest.begin(ctx)
10+
tut = analysistest.target_under_test(env)
11+
action = tut.actions[1]
12+
argv = action.argv
13+
assert_action_mnemonic(env, action, "Rustc")
14+
assert_argv_contains_prefix(
15+
env,
16+
action,
17+
"--extern=transitive",
18+
)
19+
return analysistest.end(env)
20+
21+
force_all_deps_direct_test = analysistest.make(_force_all_deps_direct_rustc_flags_test)
22+
23+
def _force_all_deps_direct_test():
24+
rust_library(
25+
name = "direct",
26+
srcs = ["direct.rs"],
27+
edition = "2018",
28+
deps = [":transitive"],
29+
)
30+
31+
rust_library(
32+
name = "transitive",
33+
srcs = ["transitive.rs"],
34+
edition = "2018",
35+
)
36+
37+
generator(
38+
name = "generate",
39+
deps = [":direct"],
40+
tags = ["noclippy"],
41+
)
42+
43+
force_all_deps_direct_test(
44+
name = "force_all_deps_direct_rustc_flags_test",
45+
target_under_test = ":generate",
46+
)
47+
48+
def force_all_deps_direct_test_suite(name):
49+
"""Entry-point macro called from the BUILD file.
50+
51+
Args:
52+
name: Name of the macro.
53+
"""
54+
_force_all_deps_direct_test()
55+
56+
native.test_suite(
57+
name = name,
58+
tests = [
59+
":force_all_deps_direct_rustc_flags_test",
60+
],
61+
)
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
"""A custom rule that threats all its dependencies as direct dependencies."""
2+
3+
# buildifier: disable=bzl-visibility
4+
load("//rust/private:common.bzl", "rust_common")
5+
6+
# buildifier: disable=bzl-visibility
7+
load("//rust/private:providers.bzl", "BuildInfo", "CrateInfo", "DepInfo", "DepVariantInfo")
8+
9+
# buildifier: disable=bzl-visibility
10+
load("//rust/private:rustc.bzl", "rustc_compile_action")
11+
12+
def _generator_impl(ctx):
13+
rs_file = ctx.actions.declare_file(ctx.label.name + "_generated.rs")
14+
ctx.actions.run_shell(
15+
outputs = [rs_file],
16+
command = """cat <<EOF > {}
17+
use direct::direct_fn;
18+
use transitive::transitive_fn;
19+
20+
pub fn call_both() {}
21+
direct_fn();
22+
transitive_fn();
23+
{}
24+
EOF
25+
""".format(rs_file.path, "{", "}"),
26+
mnemonic = "WriteRsFile",
27+
)
28+
29+
toolchain = ctx.toolchains[Label("//rust:toolchain")]
30+
31+
# Determine unique hash for this rlib
32+
output_hash = repr(hash(rs_file.path))
33+
crate_name = ctx.label.name
34+
crate_type = "rlib"
35+
36+
rust_lib_name = "{prefix}{name}-{lib_hash}{extension}".format(
37+
prefix = "lib",
38+
name = crate_name,
39+
lib_hash = output_hash,
40+
extension = ".rlib",
41+
)
42+
43+
deps = [DepVariantInfo(
44+
crate_info = dep[CrateInfo] if CrateInfo in dep else None,
45+
dep_info = dep[DepInfo] if DepInfo in dep else None,
46+
build_info = dep[BuildInfo] if BuildInfo in dep else None,
47+
cc_info = dep[CcInfo] if CcInfo in dep else None,
48+
) for dep in ctx.attr.deps]
49+
50+
rust_lib = ctx.actions.declare_file(rust_lib_name)
51+
return rustc_compile_action(
52+
ctx = ctx,
53+
attr = ctx.attr,
54+
toolchain = toolchain,
55+
crate_info = rust_common.create_crate_info(
56+
name = crate_name,
57+
type = crate_type,
58+
root = rs_file,
59+
srcs = depset([rs_file]),
60+
deps = depset(deps),
61+
proc_macro_deps = depset([]),
62+
aliases = {},
63+
output = rust_lib,
64+
owner = ctx.label,
65+
edition = "2018",
66+
compile_data = depset([]),
67+
rustc_env = {},
68+
is_test = False,
69+
),
70+
output_hash = output_hash,
71+
force_all_deps_direct = True,
72+
)
73+
74+
generator = rule(
75+
implementation = _generator_impl,
76+
attrs = {
77+
"deps": attr.label_list(),
78+
"_cc_toolchain": attr.label(
79+
default = "@bazel_tools//tools/cpp:current_cc_toolchain",
80+
),
81+
"_error_format": attr.label(default = "@rules_rust//:error_format"),
82+
"_process_wrapper": attr.label(
83+
default = Label("@rules_rust//util/process_wrapper"),
84+
executable = True,
85+
allow_single_file = True,
86+
cfg = "exec",
87+
),
88+
},
89+
toolchains = ["@rules_rust//rust:toolchain", "@bazel_tools//tools/cpp:toolchain_type"],
90+
incompatible_use_toolchain_transition = True,
91+
fragments = ["cpp"],
92+
)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub fn transitive_fn() {}

0 commit comments

Comments
 (0)