blob: 8b37460e0105bbb30cc3649d728dcdbde939ac05 [file] [edit]
"""Tests for link build variables."""
load("@rules_testing//lib:analysis_test.bzl", "test_suite")
load("@rules_testing//lib:truth.bzl", "matching")
load("@rules_testing//lib:util.bzl", "util")
load("//cc:cc_binary.bzl", "cc_binary")
load("//cc:cc_library.bzl", "cc_library")
load("//cc:cc_test.bzl", "cc_test")
load("//tests/cc/testutil:cc_analysis_test.bzl", "cc_analysis_test")
load("//tests/cc/testutil:link_action_subject.bzl", "link_action_subject")
def _cc_library_setup(name):
util.helper_target(
cc_library,
name = name + "_lib",
srcs = ["a.cc"],
)
def _cc_binary_setup(name):
util.helper_target(
cc_binary,
name = name + "_bin",
srcs = ["a.cc"],
)
def _cc_library_nodeps_dynamic_library_action(env, target):
return env.expect.that_target(target).action_generating("{package}/lib{name}.so")
def _cc_library_static_library_action(env, target):
return env.expect.that_target(target).action_generating("{package}/lib{name}.a")
def _test_force_pic_build_variable(name):
_cc_binary_setup(name)
cc_analysis_test(
name = name,
impl = _test_force_pic_build_variable_impl,
target = name + "_bin",
with_features = ["supports_pic", "force_pic_flags"],
config_settings = {
"//command_line_option:force_pic": True,
},
)
def _test_force_pic_build_variable_impl(env, target):
action = link_action_subject.from_target(env, target)
action.argv().contains("--force-pic-flag")
def _test_libraries_to_link_are_exported(name):
_cc_library_setup(name)
cc_analysis_test(
name = name,
impl = _test_libraries_to_link_are_exported_impl,
target = name + "_lib",
with_features = ["supports_dynamic_linker", "libraries_to_link"],
)
_OBJECT_FILE_SUFFIXES = ("a.o", "a.pic.o", "a.obj", "a.pic.obj")
def _test_libraries_to_link_are_exported_impl(env, target):
action = _cc_library_nodeps_dynamic_library_action(env, target)
action.argv().contains_predicate(
matching.custom(
"contains a.o or a.pic.o",
lambda s: s.startswith("--library-to-link=") and s.endswith(_OBJECT_FILE_SUFFIXES),
),
)
def _dummy_file_impl(ctx):
out = ctx.actions.declare_file(ctx.attr.filename)
ctx.actions.write(out, "")
return [DefaultInfo(files = depset([out]))]
_dummy_file = rule(
implementation = _dummy_file_impl,
attrs = {"filename": attr.string(mandatory = True)},
)
def _dummy_lib_and_bin_setup(name, filename):
lib_target = name + "_lib"
util.helper_target(
_dummy_file,
name = lib_target,
filename = filename,
)
util.helper_target(
cc_binary,
name = name + "_bin",
srcs = [lib_target],
)
def _test_library_search_directories_are_exported(name):
_dummy_lib_and_bin_setup(name, "some-dir/bar.so")
cc_analysis_test(
name = name,
impl = _test_library_search_directories_are_exported_impl,
target = name + "_bin",
with_features = ["library_search_directories"],
)
def _test_library_search_directories_are_exported_impl(env, target):
action = link_action_subject.from_target(env, target)
action.argv().contains_predicate(
matching.custom(
"contains 'some-dir'",
lambda s: "some-dir" in s,
),
)
def _test_link_simple_lib_name(name):
_dummy_lib_and_bin_setup(name, "some-dir/libbar.so")
cc_analysis_test(
name = name,
impl = _test_link_simple_lib_name_impl,
target = name + "_bin",
with_features = ["libraries_to_link"],
)
def _test_link_simple_lib_name_impl(env, target):
action = link_action_subject.from_target(env, target)
action.argv().contains("--library-to-link=bar")
def _test_link_versioned_lib_name(name):
_dummy_lib_and_bin_setup(name, "some-dir/libbar.so.1a.2")
cc_analysis_test(
name = name,
impl = _test_link_versioned_lib_name_impl,
target = name + "_bin",
with_features = ["libraries_to_link"],
)
def _test_link_versioned_lib_name_impl(env, target):
action = link_action_subject.from_target(env, target)
action.argv().contains("--library-to-link=libbar.so.1a.2")
def _test_link_unusual_lib_name(name):
_dummy_lib_and_bin_setup(name, "some-dir/_libbar.so")
cc_analysis_test(
name = name,
impl = _test_link_unusual_lib_name_impl,
target = name + "_bin",
with_features = ["libraries_to_link"],
)
def _test_link_unusual_lib_name_impl(env, target):
action = link_action_subject.from_target(env, target)
action.argv().contains("--library-to-link=_libbar.so")
def _test_interface_library_building_variables_when_generation_possible(name):
_cc_library_setup(name)
cc_analysis_test(
name = name,
impl = _test_interface_library_building_variables_when_generation_possible_impl,
target = name + "_lib",
with_features = [
"supports_dynamic_linker",
"supports_interface_shared_libraries",
"uses_ifso_variables",
],
)
def _test_interface_library_building_variables_when_generation_possible_impl(env, target):
action = _cc_library_nodeps_dynamic_library_action(env, target)
action.argv().contains("--generate-interface-library=yes")
action.argv().contains_at_least_predicates([
matching.str_matches("--interface-library-input=*lib{name}.so".format(name = target.label.name)),
matching.str_matches("--interface-library-output=*lib{name}.ifso".format(name = target.label.name)),
matching.str_matches("--interface-library-builder=*build_interface_so"),
])
def _test_interface_library_building_variables_when_generation_not_allowed(name):
_cc_library_setup(name)
cc_analysis_test(
name = name,
impl = _test_interface_library_building_variables_when_generation_not_allowed_impl,
target = name + "_lib",
with_features = [
"supports_interface_shared_libraries",
"uses_ifso_variables",
],
)
def _test_interface_library_building_variables_when_generation_not_allowed_impl(env, target):
action = _cc_library_static_library_action(env, target)
action.argv().contains("--generate-interface-library=no")
action.argv().contains("--interface-library-input=ignored")
action.argv().contains("--interface-library-output=ignored")
action.argv().contains("--interface-library-builder=ignored")
def _test_no_ifso_building_when_thin_lto_indexing(name):
_cc_library_setup(name)
cc_analysis_test(
name = name,
impl = _test_no_ifso_building_when_thin_lto_indexing_impl,
target = name + "_lib",
with_features = [
"thin_lto",
"supports_pic",
"supports_interface_shared_libraries",
"supports_dynamic_linker",
"supports_start_end_lib",
"uses_ifso_variables",
],
config_settings = {
"//command_line_option:features": ["thin_lto"],
},
)
def _test_no_ifso_building_when_thin_lto_indexing_impl(env, target):
action = env.expect.that_target(target).action_generating(
"{package}/lib{name}.so-lto-final.params",
)
action.argv().contains("--generate-interface-library=no")
action.argv().contains("--interface-library-input=ignored")
action.argv().contains("--interface-library-output=ignored")
action.argv().contains("--interface-library-builder=ignored")
def _test_output_execpath(name):
_cc_library_setup(name)
cc_analysis_test(
name = name,
impl = _test_output_execpath_impl,
target = name + "_lib",
with_features = [
"supports_dynamic_linker",
"uses_output_execpath",
],
)
def _test_output_execpath_impl(env, target):
action = _cc_library_nodeps_dynamic_library_action(env, target)
action.argv().contains_predicate(
matching.custom(
"ends with libfoo.so",
lambda s: s.startswith("--output-execpath=") and s.endswith("lib" + target.label.name + ".so"),
),
)
def _test_output_execpath_is_not_exposed_when_thin_lto_indexing(name):
_cc_library_setup(name)
cc_analysis_test(
name = name,
impl = _test_output_execpath_is_not_exposed_when_thin_lto_indexing_impl,
target = name + "_lib",
with_features = [
"thin_lto",
"supports_pic",
"supports_interface_shared_libraries",
"supports_dynamic_linker",
"supports_start_end_lib",
"uses_output_execpath",
],
config_settings = {
"//command_line_option:features": ["thin_lto"],
},
)
def _test_output_execpath_is_not_exposed_when_thin_lto_indexing_impl(env, target):
# TODO(b/525692821): Consider using build graph traversal once available to find the LTO backend action.
action = env.expect.that_target(target).action_generating(
"{package}/lib{name}.so-lto-final.params",
)
action.argv().not_contains_predicate(
matching.custom(
"starts with --output-execpath=",
lambda s: s.startswith("--output-execpath="),
),
)
def _test_is_cc_test_link_action_build_variable_for_test(name):
util.helper_target(
cc_test,
name = name + "_test_target",
srcs = ["a.cc"],
)
cc_analysis_test(
name = name,
impl = _test_is_cc_test_link_action_build_variable_test_impl,
target = name + "_test_target",
with_features = ["uses_is_cc_test"],
)
def _test_is_cc_test_link_action_build_variable_test_impl(env, target):
action = link_action_subject.from_target(env, target)
action.argv().contains("--linkopt-is-cc-test")
def _test_is_cc_test_link_action_build_variable_for_binary(name):
_cc_binary_setup(name)
cc_analysis_test(
name = name,
impl = _test_is_cc_test_link_action_build_variable_bin_impl,
target = name + "_bin",
with_features = ["uses_is_cc_test"],
)
def _test_is_cc_test_link_action_build_variable_bin_impl(env, target):
action = link_action_subject.from_target(env, target)
action.argv().contains("--linkopt-is-not-cc-test")
def _strip_test_present_impl(env, target):
action = link_action_subject.from_target(env, target)
action.argv().contains("--strip-debug-symbols")
def _strip_test_absent_impl(env, target):
action = link_action_subject.from_target(env, target)
action.argv().not_contains("--strip-debug-symbols")
def _strip_test_helper(name, strip, mode, should_have_strip):
_cc_binary_setup(name)
impl = _strip_test_present_impl if should_have_strip else _strip_test_absent_impl
cc_analysis_test(
name = name,
impl = impl,
target = name + "_bin",
with_features = ["uses_strip_debug_symbols"],
config_settings = {
"//command_line_option:strip": strip,
"//command_line_option:compilation_mode": mode,
},
)
def _test_strip_always_opt(name):
_strip_test_helper(name, "always", "opt", True)
def _test_strip_always_fastbuild(name):
_strip_test_helper(name, "always", "fastbuild", True)
def _test_strip_always_dbg(name):
_strip_test_helper(name, "always", "dbg", True)
def _test_strip_sometimes_opt(name):
_strip_test_helper(name, "sometimes", "opt", False)
def _test_strip_sometimes_fastbuild(name):
_strip_test_helper(name, "sometimes", "fastbuild", True)
def _test_strip_sometimes_dbg(name):
_strip_test_helper(name, "sometimes", "dbg", False)
def _test_strip_never_opt(name):
_strip_test_helper(name, "never", "opt", False)
def _test_strip_never_fastbuild(name):
_strip_test_helper(name, "never", "fastbuild", False)
def _test_strip_never_dbg(name):
_strip_test_helper(name, "never", "dbg", False)
def _test_is_using_fission_enabled(name):
_cc_binary_setup(name)
cc_analysis_test(
name = name,
impl = _test_is_using_fission_enabled_impl,
target = name + "_bin",
with_features = ["per_object_debug_info", "uses_is_using_fission"],
test_features = ["per_object_debug_info"],
config_settings = {
"//command_line_option:fission": "yes",
},
)
def _test_is_using_fission_enabled_impl(env, target):
action = link_action_subject.from_target(env, target)
action.argv().contains("--is-using-fission")
def _test_is_using_fission_disabled(name):
_cc_binary_setup(name)
cc_analysis_test(
name = name,
impl = _test_is_using_fission_disabled_impl,
target = name + "_bin",
with_features = ["per_object_debug_info", "uses_is_using_fission"],
test_features = ["per_object_debug_info"],
config_settings = {
"//command_line_option:fission": "no",
},
)
def _test_is_using_fission_disabled_impl(env, target):
action = link_action_subject.from_target(env, target)
action.argv().not_contains("--is-using-fission")
def _test_sysroot_variable(name):
_cc_binary_setup(name)
cc_analysis_test(
name = name,
impl = _test_sysroot_variable_impl,
target = name + "_bin",
with_features = ["uses_sysroot"],
)
def _test_sysroot_variable_impl(env, target):
action = link_action_subject.from_target(env, target)
action.argv().contains("--sysroot=/usr/grte/v1")
def _test_user_link_flags_with_linkopt_option(name):
util.helper_target(
cc_binary,
name = name + "_bin",
srcs = ["a.cc"],
linkopts = ["-foo"],
)
cc_analysis_test(
name = name,
impl = _test_user_link_flags_with_linkopt_option_impl,
target = name + "_bin",
with_features = ["uses_user_link_flags"],
config_settings = {
"//command_line_option:linkopt": ["-bar"],
},
)
def _test_user_link_flags_with_linkopt_option_impl(env, target):
action = link_action_subject.from_target(env, target)
action.argv().contains_at_least(["-foo", "-bar"]).in_order()
def _test_linker_inputs_override_whole_archive(name):
a_target = name + "_a"
b_target = name + "_b"
c_target = name + "_c"
util.helper_target(
cc_library,
name = a_target,
srcs = ["a.cc"],
features = ["disable_whole_archive_for_static_lib"],
)
util.helper_target(
cc_library,
name = b_target,
srcs = ["b.cc"],
alwayslink = 1,
)
util.helper_target(
cc_binary,
name = c_target,
linkstatic = 1,
linkshared = 1,
deps = [":" + a_target, ":" + b_target],
)
cc_analysis_test(
name = name,
impl = _test_linker_inputs_override_whole_archive_impl,
target = ":" + c_target,
with_features = [
"disable_whole_archive_for_static_lib_configuration",
"uses_whole_archive",
],
attrs = {
"_is_macos": attr.label(default = "@platforms//os:macos"),
},
)
def _test_linker_inputs_override_whole_archive_impl(env, target):
package = target.label.package
name = target.label.name
output_path = "{}/lib{}.so".format(package, name)
action = env.expect.that_target(target).action_generating(output_path)
is_macos = env.ctx.target_platform_has_constraint(env.ctx.attr._is_macos[platform_common.ConstraintValueInfo])
if is_macos:
action.argv().contains(
"-Wl,-force_load,{bindir}/{package}/lib{test_name}_b.lo",
)
action.argv().not_contains_predicate(
matching.str_matches("-Wl,-force_load,*_a.lo"),
)
else:
action.argv().contains_at_least([
"-Wl,-whole-archive",
"{bindir}/{package}/lib{test_name}_b.lo",
"-Wl,-no-whole-archive",
]).in_order()
action.argv().not_contains(
"{bindir}/{package}/lib{test_name}_a.lo",
)
def link_build_variables_tests(name):
test_suite(
name = name,
tests = [
_test_force_pic_build_variable,
_test_libraries_to_link_are_exported,
_test_library_search_directories_are_exported,
_test_link_simple_lib_name,
_test_link_versioned_lib_name,
_test_link_unusual_lib_name,
_test_interface_library_building_variables_when_generation_possible,
_test_interface_library_building_variables_when_generation_not_allowed,
_test_no_ifso_building_when_thin_lto_indexing,
_test_output_execpath,
_test_output_execpath_is_not_exposed_when_thin_lto_indexing,
_test_is_cc_test_link_action_build_variable_for_test,
_test_is_cc_test_link_action_build_variable_for_binary,
_test_strip_always_opt,
_test_strip_always_fastbuild,
_test_strip_always_dbg,
_test_strip_sometimes_opt,
_test_strip_sometimes_fastbuild,
_test_strip_sometimes_dbg,
_test_strip_never_opt,
_test_strip_never_fastbuild,
_test_strip_never_dbg,
_test_is_using_fission_enabled,
_test_is_using_fission_disabled,
_test_sysroot_variable,
_test_user_link_flags_with_linkopt_option,
_test_linker_inputs_override_whole_archive,
],
)