diff --git a/cargo/tests/cargo_build_script/transitive_data/BUILD.bazel b/cargo/tests/cargo_build_script/transitive_data/BUILD.bazel new file mode 100644 index 0000000000..91fdd6eb14 --- /dev/null +++ b/cargo/tests/cargo_build_script/transitive_data/BUILD.bazel @@ -0,0 +1,5 @@ +load(":transitive_data_test.bzl", "transitive_cbs_data_test_suite") + +transitive_cbs_data_test_suite( + name = "transitive_cbs_data_test_suite", +) diff --git a/cargo/tests/cargo_build_script/transitive_data/transitive_data_test.bzl b/cargo/tests/cargo_build_script/transitive_data/transitive_data_test.bzl new file mode 100644 index 0000000000..1740c30921 --- /dev/null +++ b/cargo/tests/cargo_build_script/transitive_data/transitive_data_test.bzl @@ -0,0 +1,115 @@ +"""Tests documenting that cargo_build_script `data` files currently act as both +compile_data and runtime data -- they appear in Rustc compile action inputs for +both the direct library and transitive dependents. + +See https://github.com/bazelbuild/rules_rust/issues/3609 for context.""" + +load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts") +load("@bazel_skylib//rules:write_file.bzl", "write_file") +load("//cargo:defs.bzl", "cargo_build_script") +load("//rust:defs.bzl", "rust_library") + +def _cbs_data_in_rustc_inputs_impl(ctx): + env = analysistest.begin(ctx) + target = analysistest.target_under_test(env) + + rustc_action = None + for action in target.actions: + if action.mnemonic == "Rustc": + rustc_action = action + break + + asserts.false(env, rustc_action == None, "Expected a Rustc action") + + # cargo_build_script `data` currently flows into BuildInfo.compile_data + # via script_data, so it appears in Rustc action inputs for both the + # direct dependent and transitive dependents. This documents that + # CBS `data` effectively acts as both compile_data and data today. + data_inputs = [i for i in rustc_action.inputs.to_list() if "cbs_data_dep.txt" in i.path] + asserts.true( + env, + len(data_inputs) > 0, + "Expected CBS data file to appear in Rustc action inputs (CBS data currently acts as compile_data)", + ) + + return analysistest.end(env) + +cbs_data_in_rustc_inputs_test = analysistest.make( + _cbs_data_in_rustc_inputs_impl, +) + +def _define_test_targets(): + write_file( + name = "cbs_data_dep_file", + out = "cbs_data_dep.txt", + content = ["data for build script", ""], + newline = "unix", + ) + + write_file( + name = "build_rs_src", + out = "build.rs", + content = ["fn main() {}", ""], + newline = "unix", + ) + + cargo_build_script( + name = "build_script", + srcs = [":build.rs"], + data = [":cbs_data_dep.txt"], + edition = "2021", + ) + + write_file( + name = "lib_src", + out = "lib.rs", + content = ["pub fn hello() {}", ""], + newline = "unix", + ) + + rust_library( + name = "lib", + srcs = [":lib.rs"], + deps = [":build_script"], + edition = "2021", + ) + + write_file( + name = "bin_src", + out = "bin.rs", + content = ["extern crate lib;", ""], + newline = "unix", + ) + + rust_library( + name = "bin", + srcs = [":bin.rs"], + deps = [":lib"], + edition = "2021", + ) + +def transitive_cbs_data_test_suite(name): + """Entry-point macro called from the BUILD file. + + Args: + name (str): Name of the macro. + """ + _define_test_targets() + + cbs_data_in_rustc_inputs_test( + name = "cbs_data_in_lib_compile_inputs_test", + target_under_test = ":lib", + ) + + cbs_data_in_rustc_inputs_test( + name = "cbs_data_in_bin_compile_inputs_test", + target_under_test = ":bin", + ) + + native.test_suite( + name = name, + tests = [ + ":cbs_data_in_lib_compile_inputs_test", + ":cbs_data_in_bin_compile_inputs_test", + ], + ) diff --git a/rust/private/rustc.bzl b/rust/private/rustc.bzl index 34e19bd4d1..a51c21e4b2 100644 --- a/rust/private/rustc.bzl +++ b/rust/private/rustc.bzl @@ -858,6 +858,7 @@ def collect_inputs( build_info = build_info, dep_info = dep_info, include_link_flags = include_link_flags, + include_transitive_data = not toolchain._incompatible_do_not_include_transitive_data_in_compile_inputs, ) # TODO(parkmycar): Cleanup the handling of lint_files here. @@ -1994,13 +1995,15 @@ def add_edition_flags(args, crate): def _process_build_scripts( build_info, dep_info, - include_link_flags = True): + include_link_flags = True, + include_transitive_data = False): """Gathers the outputs from a target's `cargo_build_script` action. Args: build_info (BuildInfo): The target Build's dependency info. dep_info (DepInfo): The Depinfo provider form the target Crate's set of inputs. include_link_flags (bool, optional): Whether to include flags like `-l` that instruct the linker to search for a library. + include_transitive_data (bool, optional): Whether to include transitive data dependencies in compile inputs. Returns: tuple: A tuple: A tuple of the following items: @@ -2010,7 +2013,9 @@ def _process_build_scripts( - (depset[File]): All direct and transitive build flags from the current build info. """ direct_inputs = [] - transitive_inputs = [dep_info.link_search_path_files, dep_info.transitive_data] + transitive_inputs = [dep_info.link_search_path_files] + if include_transitive_data: + transitive_inputs.append(dep_info.transitive_data) # Arguments to the commandline line wrapper that are going to be used # to create the final command line @@ -2037,6 +2042,7 @@ def _process_build_scripts( for dep_build_info in dep_info.transitive_build_infos.to_list(): if dep_build_info.out_dir: direct_inputs.append(dep_build_info.out_dir) + transitive_inputs.append(dep_build_info.compile_data) out_dir_compile_inputs = depset( direct_inputs, diff --git a/rust/settings/BUILD.bazel b/rust/settings/BUILD.bazel index daa02a4c0c..d2b84debcc 100644 --- a/rust/settings/BUILD.bazel +++ b/rust/settings/BUILD.bazel @@ -27,6 +27,7 @@ load( "extra_rustc_flags", "incompatible_change_clippy_error_format", "incompatible_do_not_include_data_in_compile_data", + "incompatible_do_not_include_transitive_data_in_compile_inputs", "lto", "no_std", "pipelined_compilation", @@ -111,6 +112,8 @@ incompatible_change_clippy_error_format() incompatible_do_not_include_data_in_compile_data() +incompatible_do_not_include_transitive_data_in_compile_inputs() + lto() no_std() diff --git a/rust/settings/settings.bzl b/rust/settings/settings.bzl index b6954f41ce..2769272dc5 100644 --- a/rust/settings/settings.bzl +++ b/rust/settings/settings.bzl @@ -535,6 +535,15 @@ def incompatible_do_not_include_data_in_compile_data(): issue = "https://github.com/bazelbuild/rules_rust/issues/2977", ) +# buildifier: disable=unnamed-macro +def incompatible_do_not_include_transitive_data_in_compile_inputs(): + """A flag to control whether transitive data dependencies are included in compile inputs.""" + incompatible_flag( + name = "incompatible_do_not_include_transitive_data_in_compile_inputs", + build_setting_default = True, + issue = "https://github.com/bazelbuild/rules_rust/issues/3915", + ) + def codegen_units(): """The default value for `--codegen-units` which also affects resource allocation for rustc actions. diff --git a/rust/toolchain.bzl b/rust/toolchain.bzl index f59f7ac853..471a28ec7f 100644 --- a/rust/toolchain.bzl +++ b/rust/toolchain.bzl @@ -623,6 +623,7 @@ def _rust_toolchain_impl(ctx): _experimental_use_coverage_metadata_files = ctx.attr._experimental_use_coverage_metadata_files[BuildSettingInfo].value, _toolchain_generated_sysroot = ctx.attr._toolchain_generated_sysroot[BuildSettingInfo].value, _incompatible_do_not_include_data_in_compile_data = ctx.attr._incompatible_do_not_include_data_in_compile_data[IncompatibleFlagInfo].enabled, + _incompatible_do_not_include_transitive_data_in_compile_inputs = ctx.attr._incompatible_do_not_include_transitive_data_in_compile_inputs[IncompatibleFlagInfo].enabled, _no_std = no_std, _codegen_units = ctx.attr._codegen_units[BuildSettingInfo].value, _experimental_use_allocator_libraries_with_mangled_symbols = ctx.attr.experimental_use_allocator_libraries_with_mangled_symbols, @@ -866,6 +867,10 @@ rust_toolchain = rule( default = Label("//rust/settings:incompatible_do_not_include_data_in_compile_data"), doc = "Label to a boolean build setting that controls whether to include data files in compile_data.", ), + "_incompatible_do_not_include_transitive_data_in_compile_inputs": attr.label( + default = Label("//rust/settings:incompatible_do_not_include_transitive_data_in_compile_inputs"), + doc = "Label to a boolean build setting that controls whether to include transitive data dependencies in compile inputs.", + ), "_linker_preference": attr.label( default = Label("//rust/settings:toolchain_linker_preference"), ), diff --git a/test/unit/compile_data/compile_data_test.bzl b/test/unit/compile_data/compile_data_test.bzl index 95031b6d0d..a23f9da67e 100644 --- a/test/unit/compile_data/compile_data_test.bzl +++ b/test/unit/compile_data/compile_data_test.bzl @@ -56,10 +56,34 @@ def _compile_data_propagates_to_rust_doc_test_impl(ctx): return analysistest.end(env) +def _transitive_data_not_in_compile_inputs_test_impl(ctx): + env = analysistest.begin(ctx) + target = analysistest.target_under_test(env) + + rustc_action = None + for action in target.actions: + if action.mnemonic == "Rustc": + rustc_action = action + break + + asserts.false(env, rustc_action == None, "Expected a Rustc action") + + data_inputs = [i for i in rustc_action.inputs.to_list() if "transitive_data_dep.txt" in i.path] + asserts.equals( + env, + 0, + len(data_inputs), + "Expected transitive data dep file to NOT appear in Rustc action inputs, but found: " + + str([i.path for i in data_inputs]), + ) + + return analysistest.end(env) + compile_data_propagates_to_crate_info_test = analysistest.make(_compile_data_propagates_to_crate_info_test_impl) wrapper_rule_propagates_to_crate_info_test = analysistest.make(_wrapper_rule_propagates_to_crate_info_test_impl) wrapper_rule_propagates_and_joins_compile_data_test = analysistest.make(_wrapper_rule_propagates_and_joins_compile_data_test_impl) compile_data_propagates_to_rust_doc_test = analysistest.make(_compile_data_propagates_to_rust_doc_test_impl) +transitive_data_not_in_compile_inputs_test = analysistest.make(_transitive_data_not_in_compile_inputs_test_impl) def _define_test_targets(): rust_library( @@ -134,6 +158,41 @@ def _define_test_targets(): crate = ":compile_data_gen_srcs", ) + write_file( + name = "transitive_data_dep_file", + out = "transitive_data_dep.txt", + content = ["transitive data dep", ""], + newline = "unix", + ) + + write_file( + name = "lib_with_data_src", + out = "lib_with_data.rs", + content = ["pub fn hello() {}", ""], + newline = "unix", + ) + + rust_library( + name = "lib_with_data", + srcs = [":lib_with_data.rs"], + data = [":transitive_data_dep.txt"], + edition = "2021", + ) + + write_file( + name = "lib_depending_on_data_src", + out = "lib_depending_on_data.rs", + content = ["extern crate lib_with_data;", ""], + newline = "unix", + ) + + rust_library( + name = "lib_depending_on_data", + srcs = [":lib_depending_on_data.rs"], + deps = [":lib_with_data"], + edition = "2021", + ) + def compile_data_test_suite(name): """Entry-point macro called from the BUILD file. @@ -163,6 +222,11 @@ def compile_data_test_suite(name): target_under_test = ":compile_data_env_rust_doc", ) + transitive_data_not_in_compile_inputs_test( + name = "transitive_data_not_in_compile_inputs_test", + target_under_test = ":lib_depending_on_data", + ) + native.test_suite( name = name, tests = [ @@ -170,5 +234,6 @@ def compile_data_test_suite(name): ":wrapper_rule_propagates_to_crate_info_test", ":wrapper_rule_propagates_and_joins_compile_data_test", ":compile_data_propagates_to_rust_doc_test", + ":transitive_data_not_in_compile_inputs_test", ], )