Skip to content

Commit

Permalink
Remove uses of DepInfo.transitive_libs (#1054)
Browse files Browse the repository at this point in the history
This is a step further towards #1051.

With this change, `rules_rust` doesn't need `DepInfo.transitive_libs` anymore. The only place where this field was used was to pass the files it contains as inputs to rust compile actions. We use `DepInfo.transitive_crate_outputs` for that now. For non-rlib compile actions, which need non-crate inputs as well, we add those inputs to the `additional_transitive_inputs` variable.
  • Loading branch information
scentini committed Dec 6, 2021
1 parent 3798757 commit 7ef755b
Show file tree
Hide file tree
Showing 6 changed files with 184 additions and 13 deletions.
36 changes: 23 additions & 13 deletions rust/private/rustc.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -179,11 +179,9 @@ def collect_deps(label, deps, proc_macro_deps, aliases, are_linkstamps_supported
transitive_build_infos.append(dep_info.transitive_build_infos)
elif cc_info:
# This dependency is a cc_library

# TODO: We could let the user choose how to link, instead of always preferring to link static libraries.
linker_inputs = cc_info.linking_context.linker_inputs.to_list()
libs = [get_preferred_artifact(lib) for li in linker_inputs for lib in li.libraries]
transitive_noncrate_libs.append(depset(libs))
transitive_noncrate_libs.append(depset(
_collect_libs_from_linker_inputs(cc_info.linking_context.linker_inputs.to_list()),
))
transitive_noncrates.append(cc_info.linking_context.linker_inputs)
elif dep_build_info:
if build_info:
Expand Down Expand Up @@ -218,6 +216,14 @@ def collect_deps(label, deps, proc_macro_deps, aliases, are_linkstamps_supported
depset(transitive = linkstamps),
)

def _collect_libs_from_linker_inputs(linker_inputs):
# TODO: We could let the user choose how to link, instead of always preferring to link static libraries.
return [
get_preferred_artifact(lib)
for li in linker_inputs
for lib in li.libraries
]

def _get_crate_and_dep_info(dep):
if type(dep) == "Target" and rust_common.crate_info in dep:
return (dep[rust_common.crate_info], dep[rust_common.dep_info])
Expand Down Expand Up @@ -369,15 +375,19 @@ def collect_inputs(

linker_depset = cc_toolchain.all_files

# Pass linker additional inputs (e.g., linker scripts) only for linking-like
# actions, not for example where the output is rlib. This avoids quadratic
# behavior where transitive noncrates are flattened on each transitive
# rust_library dependency.
# Pass linker inputs only for linking-like actions, not for example where
# the output is rlib. This avoids quadratic behavior where transitive noncrates are
# flattened on each transitive rust_library dependency.
additional_transitive_inputs = []
if crate_info.type in ("bin", "dylib", "cdylib"):
additional_transitive_inputs = [
if crate_info.type in ("staticlib", "proc-macro"):
additional_transitive_inputs = _collect_libs_from_linker_inputs(
dep_info.transitive_noncrates.to_list(),
)
elif crate_info.type in ("bin", "dylib", "cdylib"):
linker_inputs = dep_info.transitive_noncrates.to_list()
additional_transitive_inputs = _collect_libs_from_linker_inputs(linker_inputs) + [
additional_input
for linker_input in dep_info.transitive_noncrates.to_list()
for linker_input in linker_inputs
for additional_input in linker_input.additional_inputs
]

Expand All @@ -398,7 +408,7 @@ def collect_inputs(
toolchain.rust_lib.files,
linker_depset,
crate_info.srcs,
dep_info.transitive_libs,
dep_info.transitive_crate_outputs,
depset(additional_transitive_inputs),
crate_info.compile_data,
],
Expand Down
3 changes: 3 additions & 0 deletions test/unit/native_deps/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
load(":native_action_inputs_test.bzl", "native_action_inputs_test_suite")
load(":native_deps_test.bzl", "native_deps_test_suite")

############################ UNIT TESTS #############################
native_deps_test_suite(name = "native_deps_test_suite")

native_action_inputs_test_suite(name = "native_action_inputs_test_suite")
1 change: 1 addition & 0 deletions test/unit/native_deps/bar.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

1 change: 1 addition & 0 deletions test/unit/native_deps/foo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

1 change: 1 addition & 0 deletions test/unit/native_deps/foo_main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fn main() {}
155 changes: 155 additions & 0 deletions test/unit/native_deps/native_action_inputs_test.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
"""Unittests for rust rules."""

load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")
load(
"//rust:defs.bzl",
"rust_binary",
"rust_library",
"rust_proc_macro",
"rust_shared_library",
"rust_static_library",
)
load("//test/unit:common.bzl", "assert_action_mnemonic")

def _native_action_inputs_present_test_impl(ctx):
env = analysistest.begin(ctx)
tut = analysistest.target_under_test(env)
action = tut.actions[0]
assert_action_mnemonic(env, action, "Rustc")
inputs = action.inputs.to_list()
lib_name = _native_dep_lib_name(ctx)

asserts.true(
env,
_has_action_input(lib_name, inputs),
"Expected to contain {lib_name} as action input, got {inputs}".format(
lib_name = lib_name,
inputs = inputs,
),
)

return analysistest.end(env)

def _native_action_inputs_not_present_test_impl(ctx):
env = analysistest.begin(ctx)
tut = analysistest.target_under_test(env)
action = tut.actions[0]
assert_action_mnemonic(env, action, "Rustc")
inputs = action.inputs.to_list()
lib_name = _native_dep_lib_name(ctx)

asserts.false(
env,
_has_action_input(lib_name, inputs),
"Expected not to contain {lib_name}".format(lib_name = lib_name),
)

return analysistest.end(env)

def _native_dep_lib_name(ctx):
if ctx.target_platform_has_constraint(
ctx.attr._windows_constraint[platform_common.ConstraintValueInfo],
):
return "bar.lib"
else:
return "libbar.a"

def _has_action_input(name, inputs):
for file in inputs:
if file.basename == name:
return True
return False

native_action_inputs_present_test = analysistest.make(
_native_action_inputs_present_test_impl,
attrs = {
"_windows_constraint": attr.label(default = Label("@platforms//os:windows")),
},
)
native_action_inputs_not_present_test = analysistest.make(
_native_action_inputs_not_present_test_impl,
attrs = {
"_windows_constraint": attr.label(default = Label("@platforms//os:windows")),
},
)

def _native_action_inputs_test():
rust_library(
name = "foo_lib",
srcs = ["foo.rs"],
deps = [":bar"],
)

rust_binary(
name = "foo_bin",
srcs = ["foo_main.rs"],
deps = [":bar"],
)

rust_shared_library(
name = "foo_dylib",
srcs = ["foo.rs"],
deps = [":bar"],
)

rust_static_library(
name = "foo_static",
srcs = ["foo.rs"],
deps = [":bar"],
)

rust_proc_macro(
name = "foo_proc_macro",
srcs = ["foo.rs"],
deps = [":bar"],
)

# buildifier: disable=native-cc
native.cc_library(
name = "bar",
srcs = ["bar.cc"],
)

native_action_inputs_not_present_test(
name = "native_action_inputs_lib_test",
target_under_test = ":foo_lib",
)

native_action_inputs_present_test(
name = "native_action_inputs_bin_test",
target_under_test = ":foo_bin",
)

native_action_inputs_present_test(
name = "native_action_inputs_dylib_test",
target_under_test = ":foo_dylib",
)

native_action_inputs_present_test(
name = "native_action_inputs_static_test",
target_under_test = ":foo_static",
)

native_action_inputs_present_test(
name = "native_action_inputs_proc_macro_test",
target_under_test = ":foo_proc_macro",
)

def native_action_inputs_test_suite(name):
"""Entry-point macro called from the BUILD file.
Args:
name: Name of the macro.
"""
_native_action_inputs_test()

native.test_suite(
name = name,
tests = [
":native_action_inputs_lib_test",
":native_action_inputs_bin_test",
":native_action_inputs_dylib_test",
":native_action_inputs_static_test",
":native_action_inputs_proc_macro_test",
],
)

0 comments on commit 7ef755b

Please sign in to comment.