blob: 662b9c7219545e444e6c39088fe69a2c2f268878 [file]
"""Tests for debug info packaging (Fission)."""
load("@rules_testing//lib:analysis_test.bzl", "test_suite")
load("@rules_testing//lib:truth.bzl", "subjects")
load("@rules_testing//lib:util.bzl", "util")
load("//cc:cc_binary.bzl", "cc_binary")
load("//cc:cc_library.bzl", "cc_library")
load("//tests/cc/testutil:cc_analysis_test.bzl", "cc_analysis_test")
load("//tests/cc/testutil/toolchains:features.bzl", "FEATURE_NAMES")
def _create_fission_binary(name):
util.empty_file(name + "_fission.cc")
util.helper_target(
cc_binary,
name = name + "_fission",
srcs = [name + "_fission.cc"],
)
def _test_dwp_output_names(name):
"""Verifies the names of expected implicit .dwp outputs for supporting cc_* rules."""
_create_fission_binary(name)
cc_analysis_test(
name = name,
impl = _test_dwp_output_names_impl,
target = name + "_fission",
with_features = [FEATURE_NAMES.supports_pic, FEATURE_NAMES.per_object_debug_info],
config_settings = {
"//command_line_option:fission": "yes",
"//command_line_option:force_pic": True,
},
)
def _test_dwp_output_names_impl(env, target):
executable = target[DefaultInfo].files_to_run.executable
dwp_path = executable.short_path + ".dwp"
dwp_action = env.expect.that_target(target).action_generating(dwp_path)
dwp_action.mnemonic().equals("CcGenerateDwp")
def _test_dwp_builds_require_fission_mode_disabled(name):
"""Tests that .dwp files can be built in both fission and non-fission configurations."""
_create_fission_binary(name)
cc_analysis_test(
name = name,
impl = _test_dwp_builds_require_fission_mode_disabled_impl,
target = name + "_fission",
with_features = [FEATURE_NAMES.supports_pic, FEATURE_NAMES.per_object_debug_info],
config_settings = {
"//command_line_option:fission": "no",
},
)
def _test_dwp_builds_require_fission_mode_disabled_impl(env, target):
# Fission disabled (output is a non-meaningful empty file):
executable = target[DefaultInfo].files_to_run.executable
dwp_path = executable.short_path + ".dwp"
action = env.expect.that_target(target).action_generating(dwp_path)
action.mnemonic().equals("FileWrite")
action.content().equals("")
def _test_dwp_builds_require_fission_mode_enabled(name):
"""Tests that .dwp files can be built in both fission and non-fission configurations."""
_create_fission_binary(name)
cc_analysis_test(
name = name,
impl = _test_dwp_builds_require_fission_mode_enabled_impl,
target = name + "_fission",
with_features = [FEATURE_NAMES.supports_pic, FEATURE_NAMES.per_object_debug_info],
config_settings = {
"//command_line_option:fission": "yes",
"//command_line_option:force_pic": True,
},
)
def _test_dwp_builds_require_fission_mode_enabled_impl(env, target):
# Fission enabled:
executable = target[DefaultInfo].files_to_run.executable
dwp_path = executable.short_path + ".dwp"
action = env.expect.that_target(target).action_generating(dwp_path)
action.mnemonic().equals("CcGenerateDwp")
def _test_dwp_action_structure(name):
"""Tests the structure (i.e. inputs, outputs, command line) of the action that generates a target's .dwp."""
_create_fission_binary(name)
cc_analysis_test(
name = name,
impl = _test_dwp_action_structure_impl,
target = name + "_fission",
with_features = [FEATURE_NAMES.supports_pic, FEATURE_NAMES.per_object_debug_info],
config_settings = {
"//command_line_option:fission": "yes",
"//command_line_option:force_pic": True,
},
)
def _test_dwp_action_structure_impl(env, target):
executable = target[DefaultInfo].files_to_run.executable
dwp_path = executable.short_path + ".dwp"
action = env.expect.that_target(target).action_generating(dwp_path)
action.mnemonic().equals("CcGenerateDwp")
argv = action.argv()
# The first argument should be the command being executed.
argv.offset(0, subjects.str).equals("/usr/bin/mock-dwp")
# The final two arguments should be "-o dwpOutputFile".
argv.offset(-2, subjects.str).equals("-o")
argv.offset(-1, subjects.str).ends_with("/" + dwp_path)
# The remaining arguments should be the set of .dwo inputs.
dwo_files = _get_dwo_files_subject(env, target, dwp_path)
expected_dwo = "{package}/_objs/{target}/{target}.pic.dwo".format(
package = target.label.package,
target = target.label.name,
)
dwo_files.contains_exactly([expected_dwo])
def _create_dwo_input_set_tree(name, linkstatic):
util.empty_file(name + "_lib1.cc")
util.empty_file(name + "_lib2.cc")
util.empty_file(name + "_lib_pregen.o")
util.empty_file(name + "_test_malloc.cc")
util.empty_file(name + "_main.cc")
util.empty_file(name + "_bin_pregen.o")
util.helper_target(
cc_library,
name = name + "_lib",
srcs = [
name + "_lib1.cc",
name + "_lib2.cc",
name + "_lib_pregen.o",
],
)
util.helper_target(
cc_library,
name = name + "_test_malloc",
srcs = [name + "_test_malloc.cc"],
)
util.helper_target(
cc_library,
name = name + "_empty_lib",
)
util.helper_target(
cc_binary,
name = name + "_binary",
srcs = [
name + "_main.cc",
name + "_bin_pregen.o",
],
deps = [name + "_lib"],
malloc = name + "_test_malloc",
link_extra_lib = name + "_empty_lib", # copybara:strip
linkstatic = linkstatic,
)
def _get_dwo_files_subject(env, target, dwp_path):
action = env.expect.that_target(target).action_generating(dwp_path)
dwo_files = []
package_prefix = target.label.package + "/"
for f in action.actual.inputs.to_list():
if f.basename.endswith(".dwo") and f.short_path.startswith(package_prefix):
dwo_files.append(f.short_path)
elif f.basename.endswith(".dwp") and f.short_path != dwp_path:
sub_action = env.expect.that_target(target).action_generating(f.short_path)
for sf in sub_action.actual.inputs.to_list():
if sf.basename.endswith(".dwo") and sf.short_path.startswith(package_prefix):
dwo_files.append(sf.short_path)
return env.expect.that_collection(dwo_files)
def _test_dwo_input_set_pic_mode(name):
"""Tests that the set of input .dwo files is as expected.
This set should consist of the corresponding .dwo for every generated .o file
that is fed into a binary's link. Note that "generated .o" files are distinguished
from "source .o" files: .o files checked directly into the depot are not compiled
at build time and thus have no corresponding .dwo.
This version of the test applies "pic-mode" linking (.pic.o files are linked in
over their .o counterparts).
Args:
name: test target name
"""
_create_dwo_input_set_tree(name, linkstatic = True)
cc_analysis_test(
name = name,
impl = _test_dwo_input_set_pic_mode_impl,
target = name + "_binary",
with_features = [FEATURE_NAMES.supports_pic, FEATURE_NAMES.per_object_debug_info],
config_settings = {
"//command_line_option:fission": "yes",
"//command_line_option:force_pic": True,
},
)
def _test_dwo_input_set_pic_mode_impl(env, target):
executable = target[DefaultInfo].files_to_run.executable
dwp_path = executable.short_path + ".dwp"
dwo_files = _get_dwo_files_subject(env, target, dwp_path)
pkg = target.label.package
prefix = target.label.name.replace("_binary", "")
lib_target = prefix + "_lib"
malloc_target = prefix + "_test_malloc"
bin_target = prefix + "_binary"
expected = [
"{pkg}/_objs/{lib}/{prefix}_lib1.pic.dwo".format(pkg = pkg, lib = lib_target, prefix = prefix),
"{pkg}/_objs/{lib}/{prefix}_lib2.pic.dwo".format(pkg = pkg, lib = lib_target, prefix = prefix),
"{pkg}/_objs/{malloc}/{prefix}_test_malloc.pic.dwo".format(pkg = pkg, malloc = malloc_target, prefix = prefix),
"{pkg}/_objs/{bin}/{prefix}_main.pic.dwo".format(pkg = pkg, bin = bin_target, prefix = prefix),
]
dwo_files.contains_exactly(expected)
def _test_dwo_input_set_dynamic_mode(name):
"""Tests the .dwo input set for a dynamically linked binary.
As described above, the .dwo input set for a binary should roughly correspond to
the .o files that are fed into the binary's link. For a dynamically linked
binary, this excludes everything in dependent dynamic libraries.
Args:
name: test target name
"""
_create_dwo_input_set_tree(name, linkstatic = False)
cc_analysis_test(
name = name,
impl = _test_dwo_input_set_dynamic_mode_impl,
target = name + "_binary",
with_features = [FEATURE_NAMES.supports_pic, FEATURE_NAMES.per_object_debug_info],
config_settings = {
"//command_line_option:fission": "yes",
"//command_line_option:force_pic": True,
},
)
def _test_dwo_input_set_dynamic_mode_impl(env, target):
executable = target[DefaultInfo].files_to_run.executable
dwp_path = executable.short_path + ".dwp"
dwo_files = _get_dwo_files_subject(env, target, dwp_path)
pkg = target.label.package
prefix = target.label.name.replace("_binary", "")
bin_target = prefix + "_binary"
expected_main = "{pkg}/_objs/{bin}/{prefix}_main.pic.dwo".format(pkg = pkg, bin = bin_target, prefix = prefix)
dwo_files.contains_exactly([expected_main])
def debug_info_packaging_tests(name):
test_suite(
name = name,
tests = [
_test_dwp_output_names,
_test_dwp_builds_require_fission_mode_disabled,
_test_dwp_builds_require_fission_mode_enabled,
_test_dwp_action_structure,
_test_dwo_input_set_pic_mode,
_test_dwo_input_set_dynamic_mode,
],
)