diff --git a/rust/private/rustc.bzl b/rust/private/rustc.bzl index 1ad6a5f5be..0c3fbd0bb0 100644 --- a/rust/private/rustc.bzl +++ b/rust/private/rustc.bzl @@ -2044,6 +2044,7 @@ def rustc_compile_action( cc_toolchain = cc_toolchain, linking_contexts = linking_contexts, compilation_outputs = compilation_outputs, + link_deps_statically = ctx.fragments.cpp.dynamic_mode() != "FULLY", name = output_relative_to_package, stamp = ctx.attr.stamp, main_output = crate_info.output, diff --git a/test/unit/cc_toolchain_runtime_lib/cc_toolchain_runtime_lib_test.bzl b/test/unit/cc_toolchain_runtime_lib/cc_toolchain_runtime_lib_test.bzl index b097e1faf0..6772eb480e 100644 --- a/test/unit/cc_toolchain_runtime_lib/cc_toolchain_runtime_lib_test.bzl +++ b/test/unit/cc_toolchain_runtime_lib/cc_toolchain_runtime_lib_test.bzl @@ -4,10 +4,10 @@ Tests for handling of cc_toolchain's static_runtime_lib/dynamic_runtime_lib. load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts") load("@rules_cc//cc:cc_toolchain_config_lib.bzl", "feature") -load("@rules_cc//cc:defs.bzl", "cc_toolchain") +load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_toolchain") load("@rules_cc//cc/common:cc_common.bzl", "cc_common") load("@rules_cc//cc/toolchains:cc_toolchain_config_info.bzl", "CcToolchainConfigInfo") -load("//rust:defs.bzl", "rust_shared_library", "rust_static_library") +load("//rust:defs.bzl", "rust_binary", "rust_shared_library", "rust_static_library") def _test_cc_config_impl(ctx): config_info = cc_common.create_cc_toolchain_config_info( @@ -22,6 +22,7 @@ def _test_cc_config_impl(ctx): abi_libc_version = "unknown", features = [ feature(name = "static_link_cpp_runtimes", enabled = True), + feature(name = "supports_dynamic_linker", enabled = True), ], ) return config_info @@ -32,27 +33,40 @@ test_cc_config = rule( ) def _with_extra_toolchain_transition_impl(_settings, attr): - return {"//command_line_option:extra_toolchains": [attr.extra_toolchain]} + return { + "//command_line_option:dynamic_mode": attr.dynamic_mode, + "//command_line_option:extra_toolchains": [attr.extra_toolchain], + } with_extra_toolchain_transition = transition( implementation = _with_extra_toolchain_transition_impl, inputs = [], - outputs = ["//command_line_option:extra_toolchains"], + outputs = [ + "//command_line_option:dynamic_mode", + "//command_line_option:extra_toolchains", + ], ) DepActionsInfo = provider( "Contains information about dependencies actions.", - fields = {"actions": "List[Action]"}, + fields = { + "actions": "List[Action]", + "runfiles": "depset[File]", + }, ) def _with_extra_toolchain_impl(ctx): return [ - DepActionsInfo(actions = ctx.attr.target[0].actions), + DepActionsInfo( + actions = ctx.attr.target[0].actions, + runfiles = ctx.attr.target[0][DefaultInfo].default_runfiles.files, + ), ] with_extra_toolchain = rule( implementation = _with_extra_toolchain_impl, attrs = { + "dynamic_mode": attr.string(default = "default"), "extra_toolchain": attr.label(), "target": attr.label(cfg = with_extra_toolchain_transition), }, @@ -61,8 +75,9 @@ with_extra_toolchain = rule( def _inputs_analysis_test_impl(ctx): env = analysistest.begin(ctx) tut = analysistest.target_under_test(env) - action = tut[DepActionsInfo].actions[0] - asserts.equals(env, action.mnemonic, "Rustc") + actions = [action for action in tut[DepActionsInfo].actions if action.mnemonic == ctx.attr.mnemonic] + asserts.equals(env, 1, len(actions)) + action = actions[0] inputs = action.inputs.to_list() for expected in ctx.attr.expected_inputs: asserts.true( @@ -78,6 +93,46 @@ inputs_analysis_test = analysistest.make( doc = """An analysistest to examine the inputs of a library target.""", attrs = { "expected_inputs": attr.string_list(), + "mnemonic": attr.string(default = "Rustc"), + }, +) + +def _linkage_analysis_test_impl(ctx): + env = analysistest.begin(ctx) + tut = analysistest.target_under_test(env)[DepActionsInfo] + actions = [action for action in tut.actions if action.mnemonic == "CppLink"] + asserts.equals(env, 1, len(actions)) + argv = actions[0].argv + + for expected in ctx.attr.expected_link_args: + asserts.true( + env, + any([expected in arg for arg in argv]), + "expected '{}' in link arguments: '{}'".format(expected, argv), + ) + for unexpected in ctx.attr.unexpected_link_args: + asserts.false( + env, + any([unexpected in arg for arg in argv]), + "did not expect '{}' in link arguments: '{}'".format(unexpected, argv), + ) + + runfiles = tut.runfiles.to_list() + for expected in ctx.attr.expected_runfiles: + asserts.true( + env, + any([file.basename == expected for file in runfiles]), + "expected '{}' in runfiles: '{}'".format(expected, runfiles), + ) + + return analysistest.end(env) + +linkage_analysis_test = analysistest.make( + impl = _linkage_analysis_test_impl, + attrs = { + "expected_link_args": attr.string_list(), + "expected_runfiles": attr.string_list(), + "unexpected_link_args": attr.string_list(), }, ) @@ -150,3 +205,107 @@ def runtime_libs_test(name): target_under_test = "%s/_static_library" % name, expected_inputs = ["dummy.a"], ) + + rust_binary( + name = "%s/__rust_runtime_selection" % name, + edition = "2021", + experimental_use_cc_common_link = 1, + srcs = ["main.rs"], + tags = ["manual", "nobuild"], + ) + + with_extra_toolchain( + name = "%s/_rust_runtime_selection" % name, + dynamic_mode = "fully", + extra_toolchain = ":%s/test_cc_toolchain" % name, + target = "%s/__rust_runtime_selection" % name, + tags = ["manual"], + ) + + # Rust behavior should be consistent with the cc_runtime_selection test below. + linkage_analysis_test( + name = "%s/rust_runtime_selection" % name, + target_under_test = "%s/_rust_runtime_selection" % name, + expected_link_args = ["dummy.so"], + unexpected_link_args = ["dummy.a"], + ) + + # This C++ baseline verifies that Rust matches cc_common's native runtime selection. + cc_binary( + name = "%s/__cc_runtime_selection" % name, + linkstatic = True, + srcs = ["main.cc"], + tags = ["manual", "nobuild"], + ) + + with_extra_toolchain( + name = "%s/_cc_runtime_selection" % name, + dynamic_mode = "fully", + extra_toolchain = ":%s/test_cc_toolchain" % name, + target = "%s/__cc_runtime_selection" % name, + tags = ["manual"], + ) + + linkage_analysis_test( + name = "%s/cc_runtime_selection" % name, + target_under_test = "%s/_cc_runtime_selection" % name, + expected_link_args = ["dummy.so"], + unexpected_link_args = ["dummy.a"], + ) + # End of the cc_binary runtime-selection test. + + cc_library( + name = "%s/shared_link_dep" % name, + srcs = ["link_dep.so"], + tags = ["manual", "nobuild"], + ) + + rust_binary( + name = "%s/__rust_shared_dep" % name, + edition = "2021", + experimental_use_cc_common_link = 1, + link_deps = [":%s/shared_link_dep" % name], + srcs = ["main.rs"], + tags = ["manual", "nobuild"], + ) + + with_extra_toolchain( + name = "%s/_rust_shared_dep" % name, + dynamic_mode = "off", + extra_toolchain = ":%s/test_cc_toolchain" % name, + target = "%s/__rust_shared_dep" % name, + tags = ["manual"], + ) + + # Rust behavior should be consistent with the cc_shared_dep test below. + linkage_analysis_test( + name = "%s/rust_shared_dep" % name, + target_under_test = "%s/_rust_shared_dep" % name, + expected_link_args = ["link_dep.so"], + expected_runfiles = ["link_dep.so"], + ) + + # This C++ baseline verifies that Rust matches cc_common's shared-dependency behavior. + cc_binary( + name = "%s/__cc_shared_dep" % name, + deps = [":%s/shared_link_dep" % name], + linkstatic = True, + srcs = ["main.cc"], + tags = ["manual", "nobuild"], + ) + + with_extra_toolchain( + name = "%s/_cc_shared_dep" % name, + dynamic_mode = "off", + extra_toolchain = ":%s/test_cc_toolchain" % name, + target = "%s/__cc_shared_dep" % name, + tags = ["manual"], + ) + + linkage_analysis_test( + name = "%s/cc_shared_dep" % name, + target_under_test = "%s/_cc_shared_dep" % name, + expected_link_args = ["link_dep.so"], + expected_runfiles = ["link_dep.so"], + ) + # End of the cc_binary shared-dependency test. diff --git a/test/unit/cc_toolchain_runtime_lib/link_dep.so b/test/unit/cc_toolchain_runtime_lib/link_dep.so new file mode 100644 index 0000000000..de1901a8a4 --- /dev/null +++ b/test/unit/cc_toolchain_runtime_lib/link_dep.so @@ -0,0 +1 @@ +shared library marker diff --git a/test/unit/cc_toolchain_runtime_lib/main.cc b/test/unit/cc_toolchain_runtime_lib/main.cc new file mode 100644 index 0000000000..76e8197013 --- /dev/null +++ b/test/unit/cc_toolchain_runtime_lib/main.cc @@ -0,0 +1 @@ +int main() { return 0; } diff --git a/test/unit/cc_toolchain_runtime_lib/main.rs b/test/unit/cc_toolchain_runtime_lib/main.rs new file mode 100644 index 0000000000..f328e4d9d0 --- /dev/null +++ b/test/unit/cc_toolchain_runtime_lib/main.rs @@ -0,0 +1 @@ +fn main() {}