blob: 5cbb1d1167d6a0f72be7722553a615de0848a831 [file]
"""Tests for cc_binary with ThinLTO."""
load("@bazel_features//:features.bzl", "bazel_features")
load("@rules_testing//lib:analysis_test.bzl", "test_suite")
load("@rules_testing//lib:truth.bzl", "matching", "subjects")
load("@rules_testing//lib:util.bzl", "TestingAspectInfo", "util")
load("//cc:cc_binary.bzl", _actual_cc_binary = "cc_binary")
load("//cc:cc_library.bzl", "cc_library")
load("//cc:cc_test.bzl", _actual_cc_test = "cc_test")
load("//cc/toolchains:fdo_prefetch_hints.bzl", "fdo_prefetch_hints")
load("//cc/toolchains:fdo_profile.bzl", "fdo_profile")
load("//cc/toolchains:propeller_optimize.bzl", "propeller_optimize")
load("//tests/cc/testutil:cc_analysis_test.bzl", "cc_analysis_test")
load("//tests/cc/testutil:cc_binary_target_subject.bzl", "cc_binary_target_subject")
# Wrap cc_binary to mock out common dependencies.
def cc_binary(name, **kwargs):
if "malloc" not in kwargs:
kwargs["malloc"] = "//tests/cc/testutil/toolchains:mock_malloc"
_actual_cc_binary(
name = name,
**kwargs
)
# Wrap cc_test to mock out common dependencies.
def cc_test(name, **kwargs):
if "malloc" not in kwargs:
kwargs["malloc"] = "//tests/cc/testutil/toolchains:mock_malloc"
_actual_cc_test(
name = name,
**kwargs
)
def _test_thin_lto_action_graph(name, **kwargs):
util.helper_target(
cc_library,
name = name + "/lib",
srcs = ["bye.cc"],
hdrs = ["bye.h"],
linkstamp = "linkstamp.cc",
)
util.helper_target(
cc_binary,
name = name + "/bin",
srcs = ["hello.cc"],
deps = [":" + name + "/lib"],
)
cc_analysis_test(
name = name,
impl = _test_thin_lto_action_graph_impl,
target = name + "/bin",
test_features = ["thin_lto", "supports_pic", "supports_start_end_lib"],
**kwargs
)
def _test_thin_lto_action_graph_impl(env, target):
package = target.label.package
name = target.label.name
bindir = target[TestingAspectInfo].bin_path
test_name = name.split("/")[0]
lib_name = test_name + "/lib"
binary_obj_path = "{package}/{name}.lto/{bindir}/{package}/_objs/{name}/hello.pic.o".format(
package = package,
name = name,
bindir = bindir,
)
library_obj_path = "{package}/{name}.lto/{bindir}/{package}/_objs/{lib_name}/bye.pic.o".format(
package = package,
name = name,
bindir = bindir,
lib_name = lib_name,
)
params_path = "{package}/{name}-lto-final.params".format(
package = package,
name = name,
)
param_file_arg = "thinlto_param_file={bindir}/{params_path}".format(
bindir = bindir,
params_path = params_path,
)
binary_target = cc_binary_target_subject.from_target(env, target)
link_action = binary_target.action_generating("{package}/{name}{binary_extension}")
link_action.inputs().contains(binary_obj_path)
link_action.inputs().contains(library_obj_path)
link_action.inputs().contains(params_path)
# Check linkstamp
link_action.inputs().contains_predicate(matching.file_basename_contains("linkstamp"))
# Check argv
link_action.argv().contains_at_least([
"{bindir}/{package}/{name}.lto.merged.o".format(bindir = bindir, package = package, name = name),
param_file_arg,
]).in_order()
# Check that all our _objs args (except linkstamp) are in LTO dir
lto_dir = "{package}/{name}.lto".format(package = package, name = name)
objs_args = link_action.argv().transform(
desc = "object arguments",
filter = lambda arg: "_objs" in arg and "linkstamp" not in arg and package in arg,
)
bad_args = objs_args.transform(
desc = "object arguments not using LTO paths",
filter = lambda arg: lto_dir not in arg,
)
bad_args.is_empty()
# Backend action
backend_action = env.expect.that_target(target).action_generating(binary_obj_path)
backend_action.mnemonic().equals("CcLtoBackendCompile")
backend_action.inputs().contains(binary_obj_path + ".thinlto.bc")
backend_action.inputs().contains(binary_obj_path + ".imports")
thinlto_index_arg = "thinlto_index={bindir}/{package}/{name}.lto/{bindir}/{package}/_objs/{name}/hello.pic.o".format(
package = package,
name = name,
bindir = bindir,
) + ".thinlto.bc"
thinlto_output_arg = "thinlto_output_object_file={bindir}/{package}/{name}.lto/{bindir}/{package}/_objs/{name}/hello.pic.o".format(
package = package,
name = name,
bindir = bindir,
)
thinlto_input_arg = "thinlto_input_bitcode_file={bindir}/{package}/_objs/{name}/hello.pic.o".format(
package = package,
name = name,
bindir = bindir,
)
backend_action.argv().contains_at_least([
thinlto_index_arg,
thinlto_output_arg,
thinlto_input_arg,
])
# Index action
index_action = env.expect.that_target(target).action_generating(binary_obj_path + ".thinlto.bc")
index_action.mnemonic().equals("CppLTOIndexing")
# Linkstamp compile action should not be input to indexing
linkstamp_compile_action = env.expect.that_target(target).action_named("CppLinkstampCompile")
linkstamp_outputs = linkstamp_compile_action.actual.outputs.to_list()
index_action.inputs().contains_none_of(linkstamp_outputs)
index_action.argv().not_contains(
param_file_arg,
)
index_outputs = env.expect.that_depset_of_files(index_action.actual.outputs)
index_outputs.contains(binary_obj_path + ".imports")
index_outputs.contains(binary_obj_path + ".thinlto.bc")
index_outputs.contains(library_obj_path + ".imports")
index_outputs.contains(library_obj_path + ".thinlto.bc")
index_outputs.contains(params_path)
binary_indexing_obj = "{package}/_objs/{name}/hello.pic.indexing.o".format(
package = package,
name = name,
)
library_indexing_obj = "{package}/_objs/{lib_name}/bye.pic.indexing.o".format(
package = package,
lib_name = lib_name,
)
index_action.inputs().contains(binary_indexing_obj)
index_action.inputs().contains(library_indexing_obj)
bitcode_action = env.expect.that_target(target).action_generating(binary_indexing_obj)
bitcode_action.mnemonic().equals("CppCompile")
bitcode_action.argv().contains(
"lto_indexing_bitcode={bindir}/{binary_indexing_obj}".format(
bindir = bindir,
binary_indexing_obj = binary_indexing_obj,
),
)
def _test_thin_lto_linkshared(name, **kwargs):
util.helper_target(
cc_library,
name = name + "/lib",
srcs = ["bye.cc"],
hdrs = ["bye.h"],
)
util.helper_target(
cc_binary,
name = name + "/bin.so",
srcs = ["hello.cc"],
deps = [":" + name + "/lib"],
linkshared = 1,
)
cc_analysis_test(
name = name,
impl = _test_thin_lto_linkshared_impl,
target = name + "/bin.so",
test_features = ["thin_lto", "supports_pic", "supports_start_end_lib", "user_compile_flags"],
config_settings = {
"//command_line_option:linkopt": ["alinkopt"],
},
**kwargs
)
def _test_thin_lto_linkshared_impl(env, target):
package = target.label.package
name = target.label.name
bindir = target[TestingAspectInfo].bin_path
binary_obj_path = "{package}/{name}.lto/{bindir}/{package}/_objs/{name}/hello.pic.o".format(
package = package,
name = name,
bindir = bindir,
)
backend_action = env.expect.that_target(target).action_generating(binary_obj_path)
backend_action.mnemonic().equals("CcLtoBackendCompile")
backend_action.argv().not_contains("alinkopt")
def _test_thin_lto_no_linkstatic(name, **kwargs):
util.helper_target(
cc_library,
name = name + "/lib",
srcs = ["bye.cc"],
hdrs = ["bye.h"],
)
util.helper_target(
cc_binary,
name = name + "/bin",
srcs = ["hello.cc"],
deps = [":" + name + "/lib"],
linkstatic = 0,
)
cc_analysis_test(
name = name,
impl = _test_thin_lto_no_linkstatic_impl,
targets = {
"bin": name + "/bin",
"lib": name + "/lib",
},
test_features = [
"thin_lto",
"supports_pic",
"supports_start_end_lib",
"supports_dynamic_linker",
"supports_interface_shared_libraries",
],
**kwargs
)
def _test_thin_lto_no_linkstatic_impl(env, targets):
bin_target = targets.bin
lib_target = targets.lib
package = bin_target.label.package
name = bin_target.label.name
bindir = bin_target[TestingAspectInfo].bin_path
test_name = name.split("/")[0]
lib_target_name = test_name + "/lib"
binary_target = cc_binary_target_subject.from_target(env, bin_target)
link_action = binary_target.action_generating("{package}/{name}{binary_extension}")
# TODO(b/526555277): Propose enhancement to rules_testing to add transform/to_collection to DepsetFileSubject.
# Manually wrap inputs in CollectionSubject to use transform
link_inputs_collection = subjects.collection(
link_action.actual.inputs.to_list(),
link_action.meta.derive("inputs()"),
)
solib_inputs = link_inputs_collection.transform(
desc = "solib inputs",
filter = lambda f: "_solib" in f.path and "linkstatic_Sliblib" in f.path,
)
solib_inputs.has_size(1)
solib_file = solib_inputs.offset(0, subjects.file).actual
lib_target_subject = env.expect.that_target(lib_target)
solib_action = lib_target_subject.action_generating(solib_file.short_path)
solib_action.mnemonic().is_in(["SolibSymlink", "Symlink"])
# The input to the solib symlink action is the library itself.
solib_action_inputs = solib_action.actual.inputs.to_list()
lib_file = solib_action_inputs[0]
lib_link_action = lib_target_subject.action_generating(lib_file.short_path)
lib_link_action.mnemonic().equals("CppLink")
# Construct library LTO paths
library_lto_dir = "{package}/{test_name}/liblib.so.lto".format(
package = package,
test_name = test_name,
)
lib_obj_path = "{library_lto_dir}/{bindir}/{package}/_objs/{lib_target_name}/bye.pic.o".format(
library_lto_dir = library_lto_dir,
bindir = bindir,
package = package,
lib_target_name = lib_target_name,
)
lib_params_path = "{package}/{test_name}/liblib.so-lto-final.params".format(
package = package,
test_name = test_name,
)
binary_obj_path = "{package}/{name}.lto/{bindir}/{package}/_objs/{name}/hello.pic.o".format(
package = package,
name = name,
bindir = bindir,
)
params_path = "{package}/{name}-lto-final.params".format(
package = package,
name = name,
)
# Binary link action assertions
link_action.inputs().contains(binary_obj_path)
link_action.inputs().contains(solib_file.short_path)
link_action.inputs().contains(params_path)
# Check argv for binary link
link_action.argv().contains("-Wl,@{bindir}/{params_path}".format(
bindir = bindir,
params_path = params_path,
))
# Check that all our _objs args (except linkstamp) are in LTO dir
lto_dir = "{package}/{name}.lto".format(package = package, name = name)
objs_args = link_action.argv().transform(
desc = "object arguments",
filter = lambda arg: "_objs" in arg and "linkstamp" not in arg and package in arg,
)
bad_args = objs_args.transform(
desc = "object arguments not using LTO paths",
filter = lambda arg: lto_dir not in arg,
)
bad_args.is_empty()
# Library LTO backend action
lib_backend_action = lib_target_subject.action_generating(lib_obj_path)
lib_backend_action.mnemonic().equals("CcLtoBackendCompile")
lib_backend_action.inputs().contains(lib_obj_path + ".thinlto.bc")
# Library backend argv
lib_thinlto_index_arg = "thinlto_index={bindir}/{lib_obj_path}.thinlto.bc".format(
bindir = bindir,
lib_obj_path = lib_obj_path,
)
lib_thinlto_output_arg = "thinlto_output_object_file={bindir}/{lib_obj_path}".format(
bindir = bindir,
lib_obj_path = lib_obj_path,
)
lib_thinlto_input_arg = "thinlto_input_bitcode_file={bindir}/{package}/_objs/{lib_target_name}/bye.pic.o".format(
bindir = bindir,
package = package,
lib_target_name = lib_target_name,
)
lib_backend_action.argv().contains_at_least([
lib_thinlto_index_arg,
lib_thinlto_output_arg,
lib_thinlto_input_arg,
])
# Library Index action
lib_index_action = lib_target_subject.action_generating(lib_obj_path + ".thinlto.bc")
lib_index_action.mnemonic().equals("CppLTOIndexing")
lib_index_outputs = env.expect.that_depset_of_files(lib_index_action.actual.outputs)
lib_index_outputs.contains(lib_obj_path + ".imports")
lib_index_outputs.contains(lib_obj_path + ".thinlto.bc")
lib_index_outputs.contains(lib_params_path)
lib_indexing_obj = "{package}/_objs/{lib_target_name}/bye.pic.indexing.o".format(
package = package,
lib_target_name = lib_target_name,
)
lib_index_action.inputs().contains(lib_indexing_obj)
# Library bitcode action
lib_bitcode_action = lib_target_subject.action_generating(lib_indexing_obj)
lib_bitcode_action.mnemonic().equals("CppCompile")
lib_bitcode_action.argv().contains(
"lto_indexing_bitcode={bindir}/{lib_indexing_obj}".format(
bindir = bindir,
lib_indexing_obj = lib_indexing_obj,
),
)
def _test_thin_lto_backend_env(name, **kwargs):
util.helper_target(
cc_library,
name = name + "/lib",
srcs = ["bye.cc"],
hdrs = ["bye.h"],
)
util.helper_target(
cc_binary,
name = name + "/bin",
srcs = ["hello.cc"],
deps = [":" + name + "/lib"],
)
cc_analysis_test(
name = name,
impl = _test_thin_lto_backend_env_impl,
target = name + "/bin",
test_features = ["thin_lto", "supports_pic", "supports_start_end_lib", "env_feature", "static_env_feature", "module_maps"],
**kwargs
)
def _test_thin_lto_backend_env_impl(env, target):
package = target.label.package
name = target.label.name
bindir = target[TestingAspectInfo].bin_path
binary_obj_path = "{package}/{name}.lto/{bindir}/{package}/_objs/{name}/hello.pic.o".format(
package = package,
name = name,
bindir = bindir,
)
backend_action = env.expect.that_target(target).action_generating(binary_obj_path)
backend_action.mnemonic().equals("CcLtoBackendCompile")
backend_action.env().contains_at_least({"cat": "meow"})
def _test_thin_lto_fission(name, **kwargs):
util.helper_target(
cc_library,
name = name + "/lib",
srcs = ["bye.cc"],
hdrs = ["bye.h"],
)
util.helper_target(
cc_binary,
name = name + "/bin",
srcs = ["hello.cc"],
deps = [":" + name + "/lib"],
)
cc_analysis_test(
name = name,
impl = _test_thin_lto_fission_impl,
target = name + "/bin",
test_features = ["thin_lto", "supports_pic", "supports_start_end_lib", "per_object_debug_info"],
config_settings = {
"//command_line_option:fission": ["yes"],
"//command_line_option:copt": ["-g0"],
},
**kwargs
)
def _test_thin_lto_fission_impl(env, target):
package = target.label.package
name = target.label.name
bindir = target[TestingAspectInfo].bin_path
test_name = name.split("/")[0]
lib_target_name = test_name + "/lib"
# Binary LTO backend
binary_obj_path = "{package}/{name}.lto/{bindir}/{package}/_objs/{name}/hello.pic.o".format(
package = package,
name = name,
bindir = bindir,
)
binary_dwo_path = "{package}/{name}.lto/{bindir}/{package}/_objs/{name}/hello.pic.dwo".format(
package = package,
name = name,
bindir = bindir,
)
backend_action = env.expect.that_target(target).action_generating(binary_obj_path)
backend_action.mnemonic().equals("CcLtoBackendCompile")
backend_outputs = env.expect.that_depset_of_files(backend_action.actual.outputs)
backend_outputs.contains_exactly([binary_obj_path, binary_dwo_path])
backend_action.argv().contains_at_least(["-g0", "per_object_debug_info_option"])
# Library LTO backend (static linking, so in binary's LTO dir)
lib_obj_path = "{package}/{name}.lto/{bindir}/{package}/_objs/{lib_target_name}/bye.pic.o".format(
package = package,
name = name,
bindir = bindir,
lib_target_name = lib_target_name,
)
lib_dwo_path = "{package}/{name}.lto/{bindir}/{package}/_objs/{lib_target_name}/bye.pic.dwo".format(
package = package,
name = name,
bindir = bindir,
lib_target_name = lib_target_name,
)
lib_backend_action = env.expect.that_target(target).action_generating(lib_obj_path)
lib_backend_action.mnemonic().equals("CcLtoBackendCompile")
lib_backend_outputs = env.expect.that_depset_of_files(lib_backend_action.actual.outputs)
lib_backend_outputs.contains_exactly([lib_obj_path, lib_dwo_path])
lib_backend_action.argv().contains("per_object_debug_info_option")
# DWP action
dwp_file_path = "{package}/{name}.dwp".format(
package = package,
name = name,
)
dwp_action = env.expect.that_target(target).action_generating(dwp_file_path)
dwp_action.mnemonic().equals("CcGenerateDwp")
dwp_inputs = dwp_action.actual.inputs.to_list()
inter_dwps = [f for f in dwp_inputs if f.extension == "dwp"]
_verify_dwos_in_dwp(env, dwp_action, [target], ["hello.pic.dwo", "bye.pic.dwo"])
# Verify final DWP action arguments
if inter_dwps:
some_inter_dwp_arg = "{bindir}/{package}/_dwps/{package}/{name}-1.dwp".format(
bindir = bindir,
package = package,
name = name,
)
dwp_action.argv().contains(some_inter_dwp_arg)
else:
dwp_action.argv().contains("{bindir}/{binary_dwo_path}".format(bindir = bindir, binary_dwo_path = binary_dwo_path))
dwp_action.argv().contains("{bindir}/{lib_dwo_path}".format(bindir = bindir, lib_dwo_path = lib_dwo_path))
dwp_action.argv().contains_at_least(["-o", "{bindir}/{dwp_file_path}".format(bindir = bindir, dwp_file_path = dwp_file_path)]).in_order()
def _test_thin_lto_no_linkstatic_fission(name, **kwargs):
util.helper_target(
cc_library,
name = name + "/lib",
srcs = ["bye.cc"],
hdrs = ["bye.h"],
)
util.helper_target(
cc_binary,
name = name + "/bin",
srcs = ["hello.cc"],
deps = [":" + name + "/lib"],
linkstatic = 0,
)
cc_analysis_test(
name = name,
impl = _test_thin_lto_no_linkstatic_fission_impl,
targets = {
"bin": name + "/bin",
"lib": name + "/lib",
},
test_features = [
"thin_lto",
"supports_pic",
"supports_start_end_lib",
"supports_dynamic_linker",
"supports_interface_shared_libraries",
"per_object_debug_info",
],
config_settings = {
"//command_line_option:fission": ["yes"],
},
**kwargs
)
def _test_thin_lto_no_linkstatic_fission_impl(env, targets):
bin_target = targets.bin
lib_target = targets.lib
package = bin_target.label.package
name = bin_target.label.name
bindir = bin_target[TestingAspectInfo].bin_path
test_name = name.split("/")[0]
lib_target_name = test_name + "/lib"
# Library LTO backend
library_lto_dir = "{package}/{test_name}/liblib.so.lto".format(
package = package,
test_name = test_name,
)
lib_obj_path = "{library_lto_dir}/{bindir}/{package}/_objs/{lib_target_name}/bye.pic.o".format(
library_lto_dir = library_lto_dir,
bindir = bindir,
package = package,
lib_target_name = lib_target_name,
)
lib_dwo_path = "{library_lto_dir}/{bindir}/{package}/_objs/{lib_target_name}/bye.pic.dwo".format(
library_lto_dir = library_lto_dir,
bindir = bindir,
package = package,
lib_target_name = lib_target_name,
)
lib_target_subject = env.expect.that_target(lib_target)
lib_backend_action = lib_target_subject.action_generating(lib_obj_path)
lib_backend_action.mnemonic().equals("CcLtoBackendCompile")
lib_backend_outputs = env.expect.that_depset_of_files(lib_backend_action.actual.outputs)
lib_backend_outputs.contains_exactly([lib_obj_path, lib_dwo_path])
# Binary LTO backend
binary_obj_path = "{package}/{name}.lto/{bindir}/{package}/_objs/{name}/hello.pic.o".format(
package = package,
name = name,
bindir = bindir,
)
binary_dwo_path = "{package}/{name}.lto/{bindir}/{package}/_objs/{name}/hello.pic.dwo".format(
package = package,
name = name,
bindir = bindir,
)
binary_backend_action = env.expect.that_target(bin_target).action_generating(binary_obj_path)
binary_backend_outputs = env.expect.that_depset_of_files(binary_backend_action.actual.outputs)
binary_backend_outputs.contains_exactly([binary_obj_path, binary_dwo_path])
# DWP action
dwp_file_path = "{package}/{name}.dwp".format(
package = package,
name = name,
)
dwp_action = env.expect.that_target(bin_target).action_generating(dwp_file_path)
dwp_action.mnemonic().equals("CcGenerateDwp")
# Assert binary dwo is input, but library dwo is NOT
dwp_action.inputs().contains(binary_dwo_path)
dwp_action.inputs().not_contains(lib_dwo_path)
# Assert argv
binary_dwo_arg = "{bindir}/{binary_dwo_path}".format(bindir = bindir, binary_dwo_path = binary_dwo_path)
lib_dwo_arg = "{bindir}/{lib_dwo_path}".format(bindir = bindir, lib_dwo_path = lib_dwo_path)
dwp_action.argv().contains(binary_dwo_arg)
dwp_action.argv().not_contains(lib_dwo_arg)
dwp_action.argv().contains_at_least(["-o", "{bindir}/{dwp_file_path}".format(bindir = bindir, dwp_file_path = dwp_file_path)]).in_order()
def _test_thin_lto_linkstatic_cc_test_fission(name, **kwargs):
util.helper_target(
cc_library,
name = name + "/lib",
srcs = ["bye.cc"],
hdrs = ["bye.h"],
linkstamp = "linkstamp.cc",
)
util.helper_target(
cc_test,
name = name + "/bin_test",
srcs = ["hello.cc"],
deps = [":" + name + "/lib"],
linkstatic = 1,
)
cc_analysis_test(
name = name,
impl = _test_thin_lto_linkstatic_cc_test_fission_impl,
targets = {
"bin": name + "/bin_test",
"lib": name + "/lib",
},
test_features = [
"thin_lto",
"supports_pic",
"supports_start_end_lib",
"per_object_debug_info",
"thin_lto_linkstatic_tests_use_shared_nonlto_backends",
],
config_settings = {
"//command_line_option:fission": ["yes"],
},
**kwargs
)
def _test_thin_lto_linkstatic_cc_test_fission_impl(env, targets):
bin_target = targets.bin
lib_target = targets.lib
package = bin_target.label.package
name = bin_target.label.name
bindir = bin_target[TestingAspectInfo].bin_path
test_name = name.split("/")[0]
lib_target_name = test_name + "/lib"
# All backends should be shared non-LTO in this case.
binary_obj_path = "shared.nonlto/{bindir}/{package}/_objs/{name}/hello.pic.o".format(
bindir = bindir,
package = package,
name = name,
)
binary_dwo_path = "shared.nonlto/{bindir}/{package}/_objs/{name}/hello.pic.dwo".format(
bindir = bindir,
package = package,
name = name,
)
backend_action = env.expect.that_target(bin_target).action_generating(binary_obj_path)
backend_action.mnemonic().equals("CcLtoBackendCompile")
backend_outputs = env.expect.that_depset_of_files(backend_action.actual.outputs)
backend_outputs.contains_exactly([binary_obj_path, binary_dwo_path])
backend_action.argv().contains("per_object_debug_info_option")
# Library backend
lib_obj_path = "shared.nonlto/{bindir}/{package}/_objs/{lib_target_name}/bye.pic.o".format(
bindir = bindir,
package = package,
lib_target_name = lib_target_name,
)
lib_dwo_path = "shared.nonlto/{bindir}/{package}/_objs/{lib_target_name}/bye.pic.dwo".format(
bindir = bindir,
package = package,
lib_target_name = lib_target_name,
)
# Query from lib_target instead of bin_target
lib_backend_action = env.expect.that_target(lib_target).action_generating(lib_obj_path)
lib_backend_action.mnemonic().equals("CcLtoBackendCompile")
lib_backend_action.argv().contains("-fPIC")
lib_backend_outputs = env.expect.that_depset_of_files(lib_backend_action.actual.outputs)
lib_backend_outputs.contains_exactly([lib_obj_path, lib_dwo_path])
lib_backend_action.argv().contains("per_object_debug_info_option")
# DWP action
dwp_file_path = "{package}/{name}.dwp".format(
package = package,
name = name,
)
dwp_action = env.expect.that_target(bin_target).action_generating(dwp_file_path)
dwp_action.mnemonic().equals("CcGenerateDwp")
dwp_inputs = dwp_action.actual.inputs.to_list()
inter_dwps = [f for f in dwp_inputs if f.extension == "dwp"]
# We need to search actions in both bin and lib targets because the library's
# DWP action (or intermediate DWP actions) might be registered on lib?
# Actually, intermediate DWP actions for the binary's DWP are created by the binary.
# So they should be on bin_target.
# But let's check.
_verify_dwos_in_dwp(env, dwp_action, [bin_target, lib_target], ["hello.pic.dwo", "bye.pic.dwo"])
# Verify final DWP action arguments
if inter_dwps:
some_inter_dwp_arg = "{bindir}/{package}/_dwps/{package}/{name}-1.dwp".format(
bindir = bindir,
package = package,
name = name,
)
dwp_action.argv().contains(some_inter_dwp_arg)
else:
dwp_action.argv().contains("{bindir}/{binary_dwo_path}".format(bindir = bindir, binary_dwo_path = binary_dwo_path))
dwp_action.argv().contains("{bindir}/{lib_dwo_path}".format(bindir = bindir, lib_dwo_path = lib_dwo_path))
dwp_action.argv().contains_at_least(["-o", "{bindir}/{dwp_file_path}".format(bindir = bindir, dwp_file_path = dwp_file_path)]).in_order()
def _find_action(targets, short_path):
for t in targets:
if TestingAspectInfo in t:
for action in t[TestingAspectInfo].actions:
for output in action.outputs.to_list():
if output.short_path == short_path:
return action
return None
def _verify_dwos_in_dwp(env, dwp_action, targets, expected_dwos):
dwo_found = {dwo: False for dwo in expected_dwos}
dwp_inputs = dwp_action.actual.inputs.to_list()
inter_dwps = [f for f in dwp_inputs if f.extension == "dwp"]
if inter_dwps:
for inter_file in inter_dwps:
action = _find_action(targets, inter_file.short_path)
if action:
inputs = action.inputs.to_list()
for f in inputs:
for dwo in expected_dwos:
if dwo in f.path:
dwo_found[dwo] = True
else:
for f in dwp_inputs:
for dwo in expected_dwos:
if dwo in f.path:
dwo_found[dwo] = True
expected_dict = {dwo: True for dwo in expected_dwos}
env.expect.that_dict(dwo_found).contains_exactly(expected_dict)
def _test_linkstatic_cc_test(name, **kwargs):
util.helper_target(
cc_library,
name = name + "/lib",
srcs = ["bye.cc"],
hdrs = ["bye.h"],
linkstamp = "linkstamp.cc",
)
util.helper_target(
cc_test,
name = name + "/bin_test",
srcs = ["hello.cc"],
deps = [":" + name + "/lib"],
linkstatic = 1,
)
util.helper_target(
cc_test,
name = name + "/bin_test2",
srcs = ["hello.cc"],
deps = [":" + name + "/lib"],
linkstatic = 1,
)
cc_analysis_test(
name = name,
impl = _test_linkstatic_cc_test_impl,
targets = {
"bin1": name + "/bin_test",
"bin2": name + "/bin_test2",
"lib": name + "/lib",
},
test_features = [
"thin_lto",
"supports_pic",
"supports_start_end_lib",
"thin_lto_linkstatic_tests_use_shared_nonlto_backends",
"per_object_debug_info",
"user_compile_flags",
],
config_settings = {
"//command_line_option:linkopt": ["alinkopt"],
},
**kwargs
)
def _test_linkstatic_cc_test_impl(env, targets):
bin1_target = targets.bin1
bin2_target = targets.bin2
lib_target = targets.lib
package = bin1_target.label.package
bin1_name = bin1_target.label.name
bin2_name = bin2_target.label.name
lib_name = lib_target.label.name
bindir = bin1_target[TestingAspectInfo].bin_path
lib_obj_path = "shared.nonlto/{bindir}/{package}/_objs/{lib_target_name}/bye.pic.o".format(
bindir = bindir,
package = package,
lib_target_name = lib_name,
)
bin1_obj_path = "shared.nonlto/{bindir}/{package}/_objs/{bin1_target_name}/hello.pic.o".format(
bindir = bindir,
package = package,
bin1_target_name = bin1_name,
)
bin1_backend_action = env.expect.that_target(bin1_target).action_generating(bin1_obj_path)
bin1_backend_action.mnemonic().equals("CcLtoBackendCompile")
bin1_backend_action.argv().not_contains("alinkopt")
lib_backend_action = env.expect.that_target(lib_target).action_generating(lib_obj_path)
lib_backend_action.mnemonic().equals("CcLtoBackendCompile")
lib_backend_action.argv().contains("-fPIC")
lib_backend_action.argv().not_contains("alinkopt")
bin1_subject = cc_binary_target_subject.from_target(env, bin1_target)
bin1_executable = "{package}/{name}".format(package = package, name = bin1_name)
bin1_link_action = bin1_subject.action_generating(bin1_executable)
bin1_link_action.inputs().contains(lib_obj_path)
bin2_subject = cc_binary_target_subject.from_target(env, bin2_target)
bin2_executable = "{package}/{name}".format(package = package, name = bin2_name)
bin2_link_action = bin2_subject.action_generating(bin2_executable)
bin2_link_action.inputs().contains(lib_obj_path)
def _test_test_only_target(name, **kwargs):
util.helper_target(
cc_binary,
name = name + "/bin",
srcs = ["hello.cc"],
testonly = 1,
)
cc_analysis_test(
name = name,
impl = _test_test_only_target_impl,
target = name + "/bin",
test_features = [
"thin_lto",
"supports_pic",
"supports_start_end_lib",
"thin_lto_linkstatic_tests_use_shared_nonlto_backends",
"user_compile_flags",
],
config_settings = {
"//command_line_option:linkopt": ["alinkopt"],
},
**kwargs
)
def _test_test_only_target_impl(env, target):
package = target.label.package
name = target.label.name
bindir = target[TestingAspectInfo].bin_path
obj_path = "shared.nonlto/{bindir}/{package}/_objs/{name}/hello.pic.o".format(
bindir = bindir,
package = package,
name = name,
)
backend_action = env.expect.that_target(target).action_generating(obj_path)
backend_action.mnemonic().equals("CcLtoBackendCompile")
backend_action.argv().not_contains("alinkopt")
def _test_use_shared_all_linkstatic(name, **kwargs):
util.helper_target(
cc_binary,
name = name + "/bin",
srcs = ["hello.cc"],
)
cc_analysis_test(
name = name,
impl = _test_use_shared_all_linkstatic_impl,
target = name + "/bin",
test_features = [
"thin_lto",
"supports_pic",
"supports_start_end_lib",
"thin_lto_all_linkstatic_use_shared_nonlto_backends",
"user_compile_flags",
],
config_settings = {
"//command_line_option:linkopt": ["alinkopt"],
},
**kwargs
)
def _test_use_shared_all_linkstatic_impl(env, target):
package = target.label.package
name = target.label.name
bindir = target[TestingAspectInfo].bin_path
obj_path = "shared.nonlto/{bindir}/{package}/_objs/{name}/hello.pic.o".format(
bindir = bindir,
package = package,
name = name,
)
backend_action = env.expect.that_target(target).action_generating(obj_path)
backend_action.mnemonic().equals("CcLtoBackendCompile")
backend_action.argv().not_contains("alinkopt")
def _test_assembler_source(name, **kwargs):
util.helper_target(
cc_library,
name = name + "/lib",
srcs = [
"bye.cc",
name + "_tracing.S",
],
hdrs = ["bye.h"],
)
util.helper_target(
cc_binary,
name = name + "/bin",
srcs = ["hello.cc"],
deps = [":" + name + "/lib"],
)
cc_analysis_test(
name = name,
impl = _test_assembler_source_impl,
targets = {
"bin": name + "/bin",
"lib": name + "/lib",
},
test_features = ["thin_lto", "supports_pic", "supports_start_end_lib"],
**kwargs
)
def _test_assembler_source_impl(env, targets):
bin_target = targets.bin
lib_target = targets.lib
package = bin_target.label.package
name = bin_target.label.name
test_name = name.split("/")[0]
lib_target_name = test_name + "/lib"
s_file_name = test_name + "_tracing"
obj_path = "{package}/_objs/{lib_target_name}/{s_file_name}.pic.o".format(
package = package,
lib_target_name = lib_target_name,
s_file_name = s_file_name,
)
compile_action = env.expect.that_target(lib_target).action_generating(obj_path)
compile_action.mnemonic().equals("CppCompile")
binary_target = cc_binary_target_subject.from_target(env, bin_target)
link_action = binary_target.action_generating("{package}/{name}{binary_extension}")
link_action.inputs().contains(obj_path)
def _test_assembler_source_with_shared_nonlto_backends(name, **kwargs):
# The assembler source (.S file) is compiled to a native object, not bitcode.
# This forces the library to contain at least one non-bitcode object, which
# triggers the LTO indexing code path for non-bitcode objects when
# include_link_static_in_lto_indexing is false.
s_file = util.empty_file(name + "_tracing.S")
util.helper_target(
cc_library,
name = name + "/lib",
srcs = ["bye.cc", s_file],
hdrs = ["bye.h"],
)
util.helper_target(
cc_binary,
name = name + "/bin",
srcs = ["hello.cc"],
deps = [":" + name + "/lib"],
)
cc_analysis_test(
name = name,
impl = _test_assembler_source_impl,
targets = {
"bin": name + "/bin",
"lib": name + "/lib",
},
test_features = [
"thin_lto",
"supports_pic",
"supports_start_end_lib",
"thin_lto_all_linkstatic_use_shared_nonlto_backends",
],
**kwargs
)
def _test_duplicated_static_libraries_in_lto(name, **kwargs):
# The static library file (.a) is precompiled.
lib_file = util.empty_file(name + "_static.a")
util.helper_target(
cc_library,
name = name + "/lib1",
srcs = [lib_file],
)
util.helper_target(
cc_library,
name = name + "/lib2",
srcs = [lib_file],
)
util.helper_target(
cc_binary,
name = name + "/bin",
srcs = ["hello.cc"],
deps = [
":" + name + "/lib1",
":" + name + "/lib2",
],
)
cc_analysis_test(
name = name,
impl = _test_duplicated_static_libraries_in_lto_impl,
target = name + "/bin",
test_features = ["thin_lto", "supports_pic", "supports_start_end_lib"],
**kwargs
)
def _test_duplicated_static_libraries_in_lto_impl(env, target):
package = target.label.package
name = target.label.name
test_name = name.split("/")[0]
lib_file_path = "{package}/{test_name}_static.a".format(
package = package,
test_name = test_name,
)
binary_target = cc_binary_target_subject.from_target(env, target)
link_action = binary_target.action_generating("{package}/{name}{binary_extension}")
# Verify that the static library is an input to the link action.
link_action.inputs().contains(lib_file_path)
# Make sure we don't choke on a cc_library without sources and therefore, without bitcode files.
def _test_no_source_files(name, **kwargs):
util.helper_target(
cc_library,
name = name + "/lib",
srcs = [name + "_static.a"],
)
util.helper_target(
cc_binary,
name = name + "/bin",
srcs = ["hello.cc"],
deps = [":" + name + "/lib"],
)
cc_analysis_test(
name = name,
impl = _test_no_source_files_impl,
target = name + "/bin",
test_features = ["thin_lto", "supports_pic", "supports_start_end_lib"],
**kwargs
)
def _test_no_source_files_impl(env, target):
env.expect.that_str(target.label.name).ends_with("bin")
def _test_fdo_instrument(name, **kwargs):
util.helper_target(
cc_binary,
name = name + "/bin",
srcs = ["hello.cc"],
)
cc_analysis_test(
name = name,
impl = _test_fdo_instrument_impl,
target = name + "/bin",
test_features = ["thin_lto", "supports_pic", "supports_start_end_lib"],
with_features = ["thin_lto", "supports_pic", "supports_start_end_lib", "fdo_instrument"],
config_settings = {
"//command_line_option:fdo_instrument": "profiles",
},
**kwargs
)
def _test_fdo_instrument_impl(env, target):
package = target.label.package
name = target.label.name
bindir = target[TestingAspectInfo].bin_path
obj_path = "{package}/{name}.lto/{bindir}/{package}/_objs/{name}/hello.pic.o".format(
package = package,
name = name,
bindir = bindir,
)
backend_action = env.expect.that_target(target).action_generating(obj_path)
backend_action.mnemonic().equals("CcLtoBackendCompile")
# If the LtoBackendAction incorrectly tries to add the fdo_instrument
# feature, we will fail with an "unknown variable 'fdo_instrument_path'"
# error. But let's also explicitly confirm that the fdo_instrument
# option didn't end up here.
backend_action.argv().not_contains("fdo_instrument_option")
def _create_thin_lto_basic_targets(name):
util.helper_target(
cc_library,
name = name + "/lib",
srcs = ["libfile.cc"],
hdrs = ["libfile.h"],
linkstamp = "linkstamp.cc",
)
util.helper_target(
cc_binary,
name = name + "/bin",
srcs = ["binfile.cc"],
deps = [":" + name + "/lib"],
)
def _test_lto_index_opt(name, **kwargs):
_create_thin_lto_basic_targets(name)
cc_analysis_test(
name = name,
impl = _test_lto_index_opt_impl,
target = name + "/bin",
test_features = ["thin_lto", "supports_pic", "supports_start_end_lib"],
config_settings = {
"//command_line_option:ltoindexopt": ["anltoindexopt"],
},
**kwargs
)
def _test_lto_index_opt_impl(env, target):
package = target.label.package
name = target.label.name
bindir = target[TestingAspectInfo].bin_path
binary_obj_path = "{package}/{name}.lto/{bindir}/{package}/_objs/{name}/binfile.pic.o".format(
package = package,
name = name,
bindir = bindir,
)
index_action = env.expect.that_target(target).action_generating(binary_obj_path + ".thinlto.bc")
index_action.mnemonic().equals("CppLTOIndexing")
index_action.argv().contains("anltoindexopt")
def _test_lto_standalone_command_lines(name, **kwargs):
_create_thin_lto_basic_targets(name)
cc_analysis_test(
name = name,
impl = _test_lto_standalone_command_lines_impl,
target = name + "/bin",
test_features = ["thin_lto", "supports_pic", "supports_start_end_lib"],
config_settings = {
"//command_line_option:ltoindexopt": ["anltoindexopt"],
},
**kwargs
)
def _test_lto_standalone_command_lines_impl(env, target):
package = target.label.package
name = target.label.name
bindir = target[TestingAspectInfo].bin_path
binary_obj_path = "{package}/{name}.lto/{bindir}/{package}/_objs/{name}/binfile.pic.o".format(
package = package,
name = name,
bindir = bindir,
)
index_action = env.expect.that_target(target).action_generating(binary_obj_path + ".thinlto.bc")
index_action.mnemonic().equals("CppLTOIndexing")
index_action.argv().contains("--i_come_from_standalone_lto_index=anltoindexopt")
def _test_copt(name, **kwargs):
_create_thin_lto_basic_targets(name)
cc_analysis_test(
name = name,
impl = _test_copt_impl,
target = name + "/bin",
test_features = ["thin_lto", "supports_pic", "supports_start_end_lib"],
config_settings = {
"//command_line_option:copt": ["acopt"],
},
**kwargs
)
def _test_copt_impl(env, target):
package = target.label.package
name = target.label.name
bindir = target[TestingAspectInfo].bin_path
binary_obj_path = "{package}/{name}.lto/{bindir}/{package}/_objs/{name}/binfile.pic.o".format(
package = package,
name = name,
bindir = bindir,
)
backend_action = env.expect.that_target(target).action_generating(binary_obj_path)
backend_action.mnemonic().equals("CcLtoBackendCompile")
backend_action.argv().contains("acopt")
def _test_per_file_copt(name, **kwargs):
_create_thin_lto_basic_targets(name)
cc_analysis_test(
name = name,
impl = _test_per_file_copt_impl,
target = name + "/bin",
test_features = ["thin_lto", "supports_pic", "supports_start_end_lib"],
config_settings = {
"//command_line_option:per_file_copt": [
"binfile\\.cc@copt1",
"libfile\\.cc@copt2",
".*\\.cc,-binfile\\.cc@copt2",
],
},
**kwargs
)
def _test_per_file_copt_impl(env, target):
package = target.label.package
name = target.label.name
bindir = target[TestingAspectInfo].bin_path
test_name = name.split("/")[0]
lib_target_name = test_name + "/lib"
binary_obj_path = "{package}/{name}.lto/{bindir}/{package}/_objs/{name}/binfile.pic.o".format(
package = package,
name = name,
bindir = bindir,
)
lib_obj_path = "{package}/{name}.lto/{bindir}/{package}/_objs/{lib_target_name}/libfile.pic.o".format(
package = package,
name = name,
bindir = bindir,
lib_target_name = lib_target_name,
)
bin_backend_action = env.expect.that_target(target).action_generating(binary_obj_path)
bin_backend_action.mnemonic().equals("CcLtoBackendCompile")
bin_backend_action.argv().contains("copt1")
bin_backend_action.argv().not_contains("copt2")
lib_backend_action = env.expect.that_target(target).action_generating(lib_obj_path)
lib_backend_action.mnemonic().equals("CcLtoBackendCompile")
lib_backend_action.argv().contains("copt2")
lib_backend_action.argv().not_contains("copt1")
def _test_lto_backend_opt(name, **kwargs):
_create_thin_lto_basic_targets(name)
cc_analysis_test(
name = name,
impl = _test_lto_backend_opt_impl,
target = name + "/bin",
test_features = ["thin_lto", "supports_pic", "supports_start_end_lib", "user_compile_flags"],
config_settings = {
"//command_line_option:ltobackendopt": ["anltobackendopt"],
"//command_line_option:linkopt": ["alinkopt"],
},
**kwargs
)
def _test_lto_backend_opt_impl(env, target):
package = target.label.package
name = target.label.name
bindir = target[TestingAspectInfo].bin_path
binary_obj_path = "{package}/{name}.lto/{bindir}/{package}/_objs/{name}/binfile.pic.o".format(
package = package,
name = name,
bindir = bindir,
)
backend_action = env.expect.that_target(target).action_generating(binary_obj_path)
backend_action.mnemonic().equals("CcLtoBackendCompile")
backend_action.argv().contains_at_least([
"--default-compile-flag",
"anltobackendopt",
])
backend_action.argv().not_contains("alinkopt")
def _test_per_file_lto_backend_opt(name, **kwargs):
_create_thin_lto_basic_targets(name)
cc_analysis_test(
name = name,
impl = _test_per_file_lto_backend_opt_impl,
target = name + "/bin",
test_features = ["thin_lto", "supports_pic", "supports_start_end_lib"],
config_settings = {
"//command_line_option:per_file_ltobackendopt": [
"binfile\\.pic\\.o@ltobackendopt1",
".*\\.o,-binfile\\.pic\\.o@ltobackendopt2",
],
},
**kwargs
)
def _test_per_file_lto_backend_opt_impl(env, target):
package = target.label.package
name = target.label.name
bindir = target[TestingAspectInfo].bin_path
test_name = name.split("/")[0]
lib_target_name = test_name + "/lib"
binary_obj_path = "{package}/{name}.lto/{bindir}/{package}/_objs/{name}/binfile.pic.o".format(
package = package,
name = name,
bindir = bindir,
)
lib_obj_path = "{package}/{name}.lto/{bindir}/{package}/_objs/{lib_target_name}/libfile.pic.o".format(
package = package,
name = name,
bindir = bindir,
lib_target_name = lib_target_name,
)
bin_backend_action = env.expect.that_target(target).action_generating(binary_obj_path)
bin_backend_action.mnemonic().equals("CcLtoBackendCompile")
bin_backend_action.argv().contains("ltobackendopt1")
bin_backend_action.argv().not_contains("ltobackendopt2")
lib_backend_action = env.expect.that_target(target).action_generating(lib_obj_path)
lib_backend_action.mnemonic().equals("CcLtoBackendCompile")
lib_backend_action.argv().contains("ltobackendopt2")
lib_backend_action.argv().not_contains("ltobackendopt1")
def _test_link_opt(name, **kwargs):
_create_thin_lto_basic_targets(name)
cc_analysis_test(
name = name,
impl = _test_link_opt_impl,
target = name + "/bin",
test_features = ["thin_lto", "supports_pic", "supports_start_end_lib"],
config_settings = {
"//command_line_option:linkopt": ["alinkopt"],
},
**kwargs
)
def _test_link_opt_impl(env, target):
package = target.label.package
name = target.label.name
bindir = target[TestingAspectInfo].bin_path
binary_obj_path = "{package}/{name}.lto/{bindir}/{package}/_objs/{name}/binfile.pic.o".format(
package = package,
name = name,
bindir = bindir,
)
backend_action = env.expect.that_target(target).action_generating(binary_obj_path)
backend_action.mnemonic().equals("CcLtoBackendCompile")
backend_action.argv().not_contains("alinkopt")
def _test_autofdo(name, **kwargs):
"""Tests that ThinLTO is enabled for AFDO with LLVM when thin_lto feature is explicitly requested."""
util.helper_target(
cc_binary,
name = name + "/bin",
srcs = ["binfile.cc"],
features = ["thin_lto"],
)
cc_analysis_test(
name = name,
impl = _test_autofdo_impl,
target = name + "/bin",
test_features = ["thin_lto", "autofdo", "supports_start_end_lib"],
config_settings = {
"//command_line_option:fdo_optimize": "/pkg/profile.afdo",
"//command_line_option:compilation_mode": "opt",
},
**kwargs
)
def _test_autofdo_impl(env, target):
binary_obj_path = "{package}/{name}.lto/{bindir}/{package}/_objs/{name}/binfile.o".format(
package = target.label.package,
name = target.label.name,
bindir = target[TestingAspectInfo].bin_path,
)
backend_action = env.expect.that_target(target).action_generating(binary_obj_path)
backend_action.mnemonic().equals("CcLtoBackendCompile")
backend_action.argv().contains_predicate(matching.str_matches("-fauto-profile=*profile.afdo"))
backend_action.inputs().contains_predicate(matching.file_basename_equals("profile.afdo"))
def _make_lto_backend_disabled_test_impl(obj_name):
def impl(env, target):
binary_obj_path = "{package}/{name}.lto/{bindir}/{package}/_objs/{name}/{obj_name}".format(
package = target.label.package,
name = target.label.name,
bindir = target[TestingAspectInfo].bin_path,
obj_name = obj_name,
)
_expect_no_lto_backend_action(env, target, binary_obj_path)
return impl
def _expect_no_lto_backend_action(env, target, binary_obj_path):
found_actions = []
for action in target[TestingAspectInfo].actions:
for output in action.outputs.to_list():
if output.short_path == binary_obj_path:
found_actions.append(action)
break
env.expect.that_collection(found_actions, expr = "LTO backend action exists").is_empty()
def _test_autofdo_no_implicit_thin_lto(name, **kwargs):
"""Tests that ThinLTO is not enabled for AFDO with LLVM without --features=autofdo_implicit_thinlto."""
util.helper_target(
cc_binary,
name = name + "/bin",
srcs = ["binfile.cc"],
)
cc_analysis_test(
name = name,
impl = _make_lto_backend_disabled_test_impl("binfile.o"),
target = name + "/bin",
with_features = ["thin_lto", "autofdo", "enable_afdo_thinlto", "autofdo_implicit_thinlto", "supports_start_end_lib"],
test_features = [],
config_settings = {
"//command_line_option:fdo_optimize": "/pkg/profile.afdo",
"//command_line_option:compilation_mode": "opt",
},
**kwargs
)
def _test_autofdo_implicit_thin_lto(name, **kwargs):
"""Tests that --features=autofdo_implicit_thinlto enables ThinLTO for AFDO with LLVM."""
util.helper_target(
cc_binary,
name = name + "/bin",
srcs = ["binfile.cc"],
)
cc_analysis_test(
name = name,
impl = _test_autofdo_implicit_thin_lto_impl,
target = name + "/bin",
with_features = ["thin_lto", "autofdo", "enable_afdo_thinlto", "autofdo_implicit_thinlto", "supports_start_end_lib"],
test_features = ["autofdo_implicit_thinlto"],
config_settings = {
"//command_line_option:fdo_optimize": "/pkg/profile.afdo",
"//command_line_option:compilation_mode": "opt",
},
**kwargs
)
def _test_autofdo_implicit_thin_lto_impl(env, target):
binary_obj_path = "{package}/{name}.lto/{bindir}/{package}/_objs/{name}/binfile.o".format(
package = target.label.package,
name = target.label.name,
bindir = target[TestingAspectInfo].bin_path,
)
backend_action = env.expect.that_target(target).action_generating(binary_obj_path)
backend_action.mnemonic().equals("CcLtoBackendCompile")
def _test_autofdo_implicit_thin_lto_disabled_option(name, **kwargs):
"""Tests that --features=-thin_lto overrides --features=autofdo_implicit_thinlto and prevents enabling ThinLTO for AFDO with LLVM."""
util.helper_target(
cc_binary,
name = name + "/bin",
srcs = ["binfile.cc"],
)
cc_analysis_test(
name = name,
impl = _make_lto_backend_disabled_test_impl("binfile.o"),
target = name + "/bin",
with_features = ["thin_lto", "autofdo", "enable_afdo_thinlto", "autofdo_implicit_thinlto", "supports_start_end_lib"],
test_features = ["autofdo_implicit_thinlto", "-thin_lto"],
config_settings = {
"//command_line_option:fdo_optimize": "/pkg/profile.afdo",
"//command_line_option:compilation_mode": "opt",
},
**kwargs
)
def _test_autofdo_implicit_thin_lto_disabled_rule(name, **kwargs):
"""Tests that features=[-thin_lto] in the build rule overrides --features=autofdo_implicit_thinlto and prevents enabling ThinLTO for AFDO with LLVM."""
util.helper_target(
cc_binary,
name = name + "/bin",
srcs = ["binfile.cc"],
features = ["-thin_lto"],
)
cc_analysis_test(
name = name,
impl = _make_lto_backend_disabled_test_impl("binfile.o"),
target = name + "/bin",
with_features = ["thin_lto", "autofdo", "enable_afdo_thinlto", "autofdo_implicit_thinlto", "supports_start_end_lib"],
test_features = ["autofdo_implicit_thinlto"],
config_settings = {
"//command_line_option:fdo_optimize": "/pkg/profile.afdo",
"//command_line_option:compilation_mode": "opt",
},
**kwargs
)
def _test_autofdo_implicit_thin_lto_disabled_package(name, **kwargs):
"""Tests that features=[-thin_lto] in the package overrides --features=autofdo_implicit_thinlto and prevents enabling ThinLTO for AFDO with LLVM."""
cc_analysis_test(
name = name,
impl = _make_lto_backend_disabled_test_impl("empty.o"),
target = "//tests/cc/common/disabled_package:bin",
with_features = ["thin_lto", "autofdo", "enable_afdo_thinlto", "autofdo_implicit_thinlto", "supports_start_end_lib"],
test_features = ["autofdo_implicit_thinlto"],
config_settings = {
"//command_line_option:fdo_optimize": "/pkg/profile.afdo",
"//command_line_option:compilation_mode": "opt",
},
**kwargs
)
def _test_fdo_no_implicit_thin_lto(name, **kwargs):
"""Tests that ThinLTO is not enabled for FDO with LLVM without --features=fdo_implicit_thinlto."""
util.helper_target(
cc_binary,
name = name + "/bin",
srcs = ["binfile.cc"],
)
cc_analysis_test(
name = name,
impl = _make_lto_backend_disabled_test_impl("binfile.o"),
target = name + "/bin",
with_features = ["thin_lto", "fdo_optimize", "enable_fdo_thinlto", "fdo_implicit_thinlto", "supports_start_end_lib"],
test_features = [],
config_settings = {
"//command_line_option:fdo_optimize": "/pkg/profile.zip",
"//command_line_option:compilation_mode": "opt",
},
**kwargs
)
def _test_fdo_implicit_thin_lto(name, **kwargs):
"""Tests that --features=fdo_implicit_thinlto enables ThinLTO for FDO with LLVM."""
util.helper_target(
cc_binary,
name = name + "/bin",
srcs = ["binfile.cc"],
)
cc_analysis_test(
name = name,
impl = _test_fdo_implicit_thin_lto_impl,
target = name + "/bin",
with_features = ["thin_lto", "fdo_optimize", "enable_fdo_thinlto", "fdo_implicit_thinlto", "supports_start_end_lib"],
test_features = ["fdo_implicit_thinlto"],
config_settings = {
"//command_line_option:fdo_optimize": "/pkg/profile.zip",
"//command_line_option:compilation_mode": "opt",
},
**kwargs
)
def _test_fdo_implicit_thin_lto_impl(env, target):
binary_obj_path = "{package}/{name}.lto/{bindir}/{package}/_objs/{name}/binfile.o".format(
package = target.label.package,
name = target.label.name,
bindir = target[TestingAspectInfo].bin_path,
)
backend_action = env.expect.that_target(target).action_generating(binary_obj_path)
backend_action.mnemonic().equals("CcLtoBackendCompile")
def _test_fdo_implicit_thin_lto_disabled_option(name, **kwargs):
""" Tests that --features=-thin_lto overrides --features=fdo_implicit_thinlto and prevents enabling ThinLTO for FDO with LLVM."""
util.helper_target(
cc_binary,
name = name + "/bin",
srcs = ["binfile.cc"],
)
cc_analysis_test(
name = name,
impl = _make_lto_backend_disabled_test_impl("binfile.o"),
target = name + "/bin",
with_features = ["thin_lto", "fdo_optimize", "enable_fdo_thinlto", "fdo_implicit_thinlto", "supports_start_end_lib"],
test_features = ["fdo_implicit_thinlto", "-thin_lto"],
config_settings = {
"//command_line_option:fdo_optimize": "/pkg/profile.zip",
"//command_line_option:compilation_mode": "opt",
},
**kwargs
)
def _test_fdo_implicit_thin_lto_disabled_rule(name, **kwargs):
"""Tests that features=[-thin_lto] in the build rule overrides --features=fdo_implicit_thinlto and prevents enabling ThinLTO for FDO with LLVM."""
util.helper_target(
cc_binary,
name = name + "/bin",
srcs = ["binfile.cc"],
features = ["-thin_lto"],
)
cc_analysis_test(
name = name,
impl = _make_lto_backend_disabled_test_impl("binfile.o"),
target = name + "/bin",
with_features = ["thin_lto", "fdo_optimize", "enable_fdo_thinlto", "fdo_implicit_thinlto", "supports_start_end_lib"],
test_features = ["fdo_implicit_thinlto"],
config_settings = {
"//command_line_option:fdo_optimize": "/pkg/profile.zip",
"//command_line_option:compilation_mode": "opt",
},
**kwargs
)
def _test_fdo_implicit_thin_lto_disabled_package(name, **kwargs):
"""Tests that features=[-thin_lto] in the package overrides --features=fdo_implicit_thinlto and prevents enabling ThinLTO for FDO with LLVM."""
cc_analysis_test(
name = name,
impl = _make_lto_backend_disabled_test_impl("empty.o"),
target = "//tests/cc/common/disabled_package_fdo:bin",
with_features = ["thin_lto", "fdo_optimize", "enable_fdo_thinlto", "fdo_implicit_thinlto", "supports_start_end_lib"],
test_features = ["fdo_implicit_thinlto"],
config_settings = {
"//command_line_option:fdo_optimize": "/pkg/profile.zip",
"//command_line_option:compilation_mode": "opt",
},
**kwargs
)
def _test_xbinary_fdo_no_implicit_thin_lto(name, **kwargs):
"""Tests that ThinLTO is not enabled for XFDO with LLVM without --features=xbinaryfdo_implicit_thinlto."""
fdo_profile(
name = name + "/out.xfdo",
profile = "profiles.xfdo",
)
util.helper_target(
cc_binary,
name = name + "/bin",
srcs = ["binfile.cc"],
)
cc_analysis_test(
name = name,
impl = _make_lto_backend_disabled_test_impl("binfile.o"),
target = name + "/bin",
with_features = ["thin_lto", "xbinaryfdo", "enable_xbinaryfdo_thinlto", "xbinaryfdo_implicit_thinlto", "supports_start_end_lib"],
test_features = [],
config_settings = {
"//command_line_option:xbinary_fdo": Label(":" + name + "/out.xfdo"),
"//command_line_option:compilation_mode": "opt",
},
**kwargs
)
def _test_xbinary_fdo_implicit_thin_lto(name, **kwargs):
"""Tests that --features=xbinaryfdo_implicit_thinlto enables ThinLTO for XFDO with LLVM."""
fdo_profile(
name = name + "/out.xfdo",
profile = "profiles.xfdo",
)
util.helper_target(
cc_binary,
name = name + "/bin",
srcs = ["binfile.cc"],
)
cc_analysis_test(
name = name,
impl = _test_xbinary_fdo_implicit_thin_lto_impl,
target = name + "/bin",
with_features = ["thin_lto", "xbinaryfdo", "enable_xbinaryfdo_thinlto", "xbinaryfdo_implicit_thinlto", "supports_start_end_lib"],
test_features = ["xbinaryfdo_implicit_thinlto"],
config_settings = {
"//command_line_option:xbinary_fdo": Label(":" + name + "/out.xfdo"),
"//command_line_option:compilation_mode": "opt",
},
**kwargs
)
def _test_xbinary_fdo_implicit_thin_lto_impl(env, target):
binary_obj_path = "{package}/{name}.lto/{bindir}/{package}/_objs/{name}/binfile.o".format(
package = target.label.package,
name = target.label.name,
bindir = target[TestingAspectInfo].bin_path,
)
backend_action = env.expect.that_target(target).action_generating(binary_obj_path)
backend_action.mnemonic().equals("CcLtoBackendCompile")
def _test_xbinary_fdo_implicit_thin_lto_disabled_option(name, **kwargs):
"""Tests that --features=-thin_lto overrides --features=xbinaryfdo_implicit_thinlto and prevents enabling ThinLTO for XFDO with LLVM."""
fdo_profile(
name = name + "/out.xfdo",
profile = "profiles.xfdo",
)
util.helper_target(
cc_binary,
name = name + "/bin",
srcs = ["binfile.cc"],
)
cc_analysis_test(
name = name,
impl = _make_lto_backend_disabled_test_impl("binfile.o"),
target = name + "/bin",
with_features = ["thin_lto", "xbinaryfdo", "enable_xbinaryfdo_thinlto", "xbinaryfdo_implicit_thinlto", "supports_start_end_lib"],
test_features = ["xbinaryfdo_implicit_thinlto", "-thin_lto"],
config_settings = {
"//command_line_option:xbinary_fdo": Label(":" + name + "/out.xfdo"),
"//command_line_option:compilation_mode": "opt",
},
**kwargs
)
def _test_xbinary_fdo_implicit_thin_lto_disabled_rule(name, **kwargs):
"""Tests that features=[-thin_lto] in the build rule overrides --features=xbinaryfdo_implicit_thinlto and prevents enabling ThinLTO for XFDO with LLVM."""
fdo_profile(
name = name + "/out.xfdo",
profile = "profiles.xfdo",
)
util.helper_target(
cc_binary,
name = name + "/bin",
srcs = ["binfile.cc"],
features = ["-thin_lto"],
)
cc_analysis_test(
name = name,
impl = _make_lto_backend_disabled_test_impl("binfile.o"),
target = name + "/bin",
with_features = ["thin_lto", "xbinaryfdo", "enable_xbinaryfdo_thinlto", "xbinaryfdo_implicit_thinlto", "supports_start_end_lib"],
test_features = ["xbinaryfdo_implicit_thinlto"],
config_settings = {
"//command_line_option:xbinary_fdo": Label(":" + name + "/out.xfdo"),
"//command_line_option:compilation_mode": "opt",
},
**kwargs
)
def _test_xbinary_fdo_implicit_thin_lto_disabled_package(name, **kwargs):
"""Tests that features=[-thin_lto] in the package overrides --features=xbinaryfdo_implicit_thinlto and prevents enabling ThinLTO for XFDO with LLVM."""
cc_analysis_test(
name = name,
impl = _make_lto_backend_disabled_test_impl("empty.o"),
target = "//tests/cc/common/disabled_package_xfdo:bin",
with_features = ["thin_lto", "xbinaryfdo", "enable_xbinaryfdo_thinlto", "xbinaryfdo_implicit_thinlto", "supports_start_end_lib"],
test_features = ["xbinaryfdo_implicit_thinlto"],
config_settings = {
"//command_line_option:xbinary_fdo": Label("//tests/cc/common/disabled_package_xfdo:out.xfdo"),
"//command_line_option:compilation_mode": "opt",
},
**kwargs
)
def _test_xbinary_fdo(name, **kwargs):
"""Tests that -fauto-profile is added to the LtoBackendAction when xbinary_fdo is enabled."""
fdo_profile(
name = name + "/out.xfdo",
profile = "profiles.xfdo",
)
util.helper_target(
cc_binary,
name = name + "/bin",
srcs = ["binfile.cc"],
features = ["thin_lto"],
)
cc_analysis_test(
name = name,
impl = _test_xbinary_fdo_impl,
target = name + "/bin",
with_features = ["thin_lto", "xbinaryfdo", "enable_xbinaryfdo_thinlto", "xbinaryfdo_implicit_thinlto", "supports_start_end_lib"],
test_features = ["thin_lto"],
config_settings = {
"//command_line_option:xbinary_fdo": Label(":" + name + "/out.xfdo"),
"//command_line_option:compilation_mode": "opt",
},
**kwargs
)
def _test_xbinary_fdo_impl(env, target):
binary_obj_path = "{package}/{name}.lto/{bindir}/{package}/_objs/{name}/binfile.o".format(
package = target.label.package,
name = target.label.name,
bindir = target[TestingAspectInfo].bin_path,
)
backend_action = env.expect.that_target(target).action_generating(binary_obj_path)
backend_action.mnemonic().equals("CcLtoBackendCompile")
backend_action.argv().contains_predicate(matching.str_matches("-fauto-profile=*profiles.xfdo"))
backend_action.inputs().contains_predicate(matching.file_basename_equals("profiles.xfdo"))
def _test_xbinary_fdo_no_autofdo_or_fdo_implicit_thin_lto(name, **kwargs):
"""Tests that ThinLTO is not enabled for XBINARYFDO with --features=autofdo_implicit_thinlto and --features=fdo_implicit_thinlto."""
fdo_profile(
name = name + "/out.xfdo",
profile = "profiles.xfdo",
)
util.helper_target(
cc_binary,
name = name + "/bin",
srcs = ["binfile.cc"],
)
cc_analysis_test(
name = name,
impl = _make_lto_backend_disabled_test_impl("binfile.o"),
target = name + "/bin",
with_features = [
"thin_lto",
"fdo_optimize",
"enable_fdo_thinlto",
"fdo_implicit_thinlto",
"autofdo",
"enable_afdo_thinlto",
"autofdo_implicit_thinlto",
"xbinaryfdo",
"supports_start_end_lib",
],
test_features = ["autofdo_implicit_thinlto", "fdo_implicit_thinlto"],
config_settings = {
"//command_line_option:xbinary_fdo": Label(":" + name + "/out.xfdo"),
"//command_line_option:compilation_mode": "opt",
},
**kwargs
)
def _test_pic_backend_order(name, **kwargs):
_create_thin_lto_basic_targets(name)
cc_analysis_test(
name = name,
impl = _test_pic_backend_order_impl,
target = name + "/bin",
test_features = ["thin_lto", "supports_pic", "supports_start_end_lib"],
config_settings = {
"//command_line_option:copt": ["-fno-PIE"],
},
**kwargs
)
def _test_pic_backend_order_impl(env, target):
backend_action = env.expect.that_target(target).action_generating(
"{package}/{name}.lto/{bindir}/{package}/_objs/{name}/binfile.pic.o",
)
backend_action.mnemonic().equals("CcLtoBackendCompile")
backend_action.argv().contains_at_least(["-fno-PIE", "-fPIC"]).in_order()
def _test_propeller_optimize_absolute_options(name, **kwargs):
_create_thin_lto_basic_targets(name)
cc_analysis_test(
name = name,
impl = _test_propeller_optimize_absolute_options_impl,
target = name + "/bin",
with_features = ["thin_lto", "autofdo", "supports_start_end_lib", "propeller_optimize"],
test_features = ["thin_lto", "supports_start_end_lib", "propeller_optimize"],
config_settings = {
"//command_line_option:propeller_optimize_absolute_cc_profile": "/tmp/cc_profile.txt",
"//command_line_option:propeller_optimize_absolute_ld_profile": "/tmp/ld_profile.txt",
"//command_line_option:compilation_mode": "opt",
},
**kwargs
)
def _test_propeller_optimize_absolute_options_impl(env, target):
binary_target = cc_binary_target_subject.from_target(env, target)
link_action = binary_target.action_generating("{package}/{name}{binary_extension}")
link_action.outputs().has_size(1)
link_action.inputs().contains_predicate(matching.file_basename_equals("ld_profile.txt"))
link_action.argv().contains_predicate(matching.str_matches("-Wl,--symbol-ordering-file=*/ld_profile.txt"))
backend_action = env.expect.that_target(target).action_generating(
"{package}/{name}.lto/{bindir}/{package}/_objs/{name}/binfile.o",
)
backend_action.mnemonic().equals("CcLtoBackendCompile")
backend_action.argv().contains_predicate(matching.str_matches("-fbasic-block-sections=list=*/cc_profile.txt"))
backend_action.argv().contains("-DBUILD_PROPELLER_ENABLED=1")
backend_action.inputs().contains_predicate(matching.file_basename_equals("cc_profile.txt"))
index_action = env.expect.that_target(target).action_generating(
"{package}/{name}.lto/{bindir}/{package}/_objs/{name}/binfile.o.thinlto.bc",
)
index_action.inputs().not_contains_predicate(matching.file_basename_equals("ld_profile.txt"))
def _test_propeller_cc_compile(name, **kwargs):
_create_thin_lto_basic_targets(name)
cc_analysis_test(
name = name,
impl = _test_propeller_cc_compile_impl,
target = name + "/bin",
with_features = ["thin_lto", "autofdo", "supports_start_end_lib", "propeller_optimize"],
test_features = ["thin_lto", "supports_start_end_lib", "propeller_optimize"],
config_settings = {
"//command_line_option:propeller_optimize_absolute_cc_profile": "/tmp/cc_profile.txt",
"//command_line_option:propeller_optimize_absolute_ld_profile": "/tmp/ld_profile.txt",
"//command_line_option:compilation_mode": "opt",
},
**kwargs
)
def _test_propeller_cc_compile_impl(env, target):
# We need to find bitcodeAction (CppCompile generating binfile.indexing.o)
# It is input to indexAction.
# indexAction output is obj_path + ".thinlto.bc"
index_action = env.expect.that_target(target).action_generating(
"{package}/{name}.lto/{bindir}/{package}/_objs/{name}/binfile.o.thinlto.bc",
)
index_action.inputs().contains("{package}/_objs/{name}/binfile.indexing.o")
bitcode_action = env.expect.that_target(target).action_generating("{package}/_objs/{name}/binfile.indexing.o")
bitcode_action.mnemonic().equals("CppCompile")
bitcode_action.inputs().not_contains_predicate(matching.file_basename_equals("cc_profile.txt"))
bitcode_action.argv().not_contains_predicate(matching.str_startswith("-fbasic-block-sections="))
# Check that the temporary opt-out from disabling Propeller profiles for ThinLTO compile actions
# works.
#
# TODO(b/182804945): Remove after making sure that the rollout of the new Propeller profile
# passing logic didn't break anything.
def _test_propeller_cc_compile_with_propeller_optimize_thin_lto_compile_actions(name, **kwargs):
_create_thin_lto_basic_targets(name)
cc_analysis_test(
name = name,
impl = _test_propeller_cc_compile_with_propeller_optimize_thin_lto_compile_actions_impl,
target = name + "/bin",
with_features = [
"thin_lto",
"autofdo",
"supports_start_end_lib",
"propeller_optimize",
"propeller_optimize_thinlto_compile_actions",
],
test_features = [
"thin_lto",
"supports_start_end_lib",
"propeller_optimize",
"propeller_optimize_thinlto_compile_actions",
],
config_settings = {
"//command_line_option:propeller_optimize_absolute_cc_profile": "/tmp/cc_profile.txt",
"//command_line_option:propeller_optimize_absolute_ld_profile": "/tmp/ld_profile.txt",
"//command_line_option:compilation_mode": "opt",
},
**kwargs
)
def _test_propeller_cc_compile_with_propeller_optimize_thin_lto_compile_actions_impl(env, target):
lib_name = target.label.name.removesuffix("/bin") + "/lib"
index_action = env.expect.that_target(target).action_generating(
"{package}/{name}.lto/{bindir}/{package}/_objs/{name}/binfile.o.thinlto.bc",
)
index_action.inputs().contains("{package}/_objs/{name}/binfile.indexing.o")
index_action.inputs().contains("{package}/_objs/" + lib_name + "/libfile.indexing.o")
bitcode_action = env.expect.that_target(target).action_generating("{package}/_objs/{name}/binfile.indexing.o")
bitcode_action.mnemonic().equals("CppCompile")
bitcode_action.inputs().contains_predicate(matching.file_basename_equals("cc_profile.txt"))
bitcode_action.argv().contains_predicate(matching.str_matches("-fbasic-block-sections=list=*/cc_profile.txt"))
def _propagating_testing_aspect_impl(target, ctx):
return [TestingAspectInfo(
attrs = ctx.rule.attr,
actions = target.actions,
vars = ctx.var,
bin_path = ctx.bin_dir.path,
required_aspects = ctx.aspect_ids[:-1],
)]
_propagating_testing_aspect = aspect(
implementation = _propagating_testing_aspect_impl,
attr_aspects = ["*"],
)
def _find_target_in_attr_by_suffix(env, target, attr_name, name_suffix):
targets = [
dep
for dep in getattr(target[TestingAspectInfo].attrs, attr_name)
if dep.label.name.endswith(name_suffix)
]
env.expect.that_collection(targets).has_size(1)
return targets[0]
def _test_propeller_cc_compile_with_thin_lto_disabled(name, **kwargs):
util.helper_target(
cc_library,
name = name + "/lib",
srcs = ["libfile.cc"],
hdrs = ["libfile.h"],
linkstamp = "linkstamp.cc",
features = ["-thin_lto"],
)
util.helper_target(
cc_binary,
name = name + "/bin",
srcs = ["binfile.cc"],
deps = [":" + name + "/lib"],
)
cc_analysis_test(
name = name,
impl = _test_propeller_cc_compile_with_thin_lto_disabled_impl,
target = name + "/bin",
with_features = ["thin_lto", "autofdo", "supports_start_end_lib", "propeller_optimize"],
test_features = ["thin_lto", "supports_start_end_lib", "propeller_optimize"],
testing_aspect = _propagating_testing_aspect,
config_settings = {
"//command_line_option:propeller_optimize_absolute_cc_profile": "/tmp/cc_profile.txt",
"//command_line_option:propeller_optimize_absolute_ld_profile": "/tmp/ld_profile.txt",
"//command_line_option:compilation_mode": "opt",
},
**kwargs
)
def _test_propeller_cc_compile_with_thin_lto_disabled_impl(env, target):
lib_target = _find_target_in_attr_by_suffix(env, target, attr_name = "deps", name_suffix = "/lib")
test_name = target.label.name.split("/")[0]
obj_path = "{package}/_objs/{lib_target_name}/libfile.o".format(
package = target.label.package,
lib_target_name = test_name + "/lib",
)
compile_action = env.expect.that_target(lib_target).action_generating(obj_path)
compile_action.mnemonic().equals("CppCompile")
compile_action.inputs().contains_predicate(matching.file_basename_equals("cc_profile.txt"))
compile_action.argv().contains_predicate(matching.str_matches("-fbasic-block-sections=list=*/cc_profile.txt"))
def _test_propeller_host_builds(name, **kwargs):
util.helper_target(
cc_binary,
name = name + "/gen_lib",
srcs = [name + "/gen_lib.cc"],
)
util.helper_target(
native.genrule,
name = name + "/lib_genrule",
srcs = [],
outs = [name + "/libfile.cc"],
cmd = "$(location :" + name + "/gen_lib) > \"$@\"",
tools = [":" + name + "/gen_lib"],
)
util.helper_target(
cc_library,
name = name + "/lib",
srcs = [":" + name + "/lib_genrule"],
hdrs = [name + "/libfile.h"],
)
util.helper_target(
cc_binary,
name = name + "/bin",
srcs = [name + "/binfile.cc"],
deps = [":" + name + "/lib"],
)
cc_analysis_test(
name = name,
impl = _test_propeller_host_builds_impl,
target = name + "/bin",
with_features = ["thin_lto", "autofdo", "supports_start_end_lib", "propeller_optimize"],
test_features = ["thin_lto", "supports_start_end_lib", "propeller_optimize"],
testing_aspect = _propagating_testing_aspect,
config_settings = {
"//command_line_option:propeller_optimize_absolute_cc_profile": "/tmp/cc_profile.txt",
"//command_line_option:propeller_optimize_absolute_ld_profile": "/tmp/ld_profile.txt",
"//command_line_option:compilation_mode": "opt",
},
**kwargs
)
def _test_propeller_host_builds_impl(env, target):
# Sanity check: Verify Propeller IS active on the target binary backend action
target_backend_action = env.expect.that_target(target).action_generating(
"{package}/{name}.lto/{bindir}/{package}/_objs/{name}/binfile.o".format(
package = target.label.package,
name = target.label.name,
bindir = target[TestingAspectInfo].bin_path,
),
)
target_backend_action.mnemonic().equals("CcLtoBackendCompile")
target_backend_action.argv().contains_predicate(matching.str_matches("-fbasic-block-sections=list=*/cc_profile.txt"))
lib_target = _find_target_in_attr_by_suffix(
env,
target,
attr_name = "deps",
name_suffix = "/lib",
)
lib_genrule_target = _find_target_in_attr_by_suffix(
env,
lib_target,
attr_name = "srcs",
name_suffix = "/lib_genrule",
)
gen_lib_target = _find_target_in_attr_by_suffix(
env,
lib_genrule_target,
attr_name = "tools",
name_suffix = "/gen_lib",
)
gen_lib_executable = gen_lib_target[DefaultInfo].files_to_run.executable
host_link_action = env.expect.that_target(gen_lib_target).action_generating(gen_lib_executable.short_path)
host_link_action.mnemonic().equals("CppLink")
host_link_action.inputs().not_contains_predicate(matching.file_basename_equals("ld_profile.txt"))
host_link_action.argv().not_contains_predicate(matching.str_startswith("-Wl,--symbol-ordering-file="))
host_compile_action = env.expect.that_target(gen_lib_target).action_generating("{package}/_objs/{name}/gen_lib.o")
host_compile_action.mnemonic().equals("CppCompile")
host_compile_action.inputs().not_contains_predicate(matching.file_basename_equals("cc_profile.txt"))
host_compile_action.argv().not_contains_predicate(matching.str_startswith("-fbasic-block-sections="))
def _test_propeller_optimize_option_from_label(name, **kwargs):
cc_profile = name + "/cc_profile.txt"
ld_profile = name + "/ld_profile.txt"
util.helper_target(
propeller_optimize,
name = name + "/test_propeller_optimize",
cc_profile = cc_profile,
ld_profile = ld_profile,
)
_create_thin_lto_basic_targets(name)
cc_analysis_test(
name = name,
impl = _test_propeller_optimize_option_from_label_impl,
target = name + "/bin",
with_features = ["thin_lto", "autofdo", "supports_start_end_lib", "propeller_optimize"],
test_features = ["thin_lto", "supports_start_end_lib", "propeller_optimize"],
config_settings = {
"//command_line_option:propeller_optimize": Label(":" + name + "/test_propeller_optimize"),
"//command_line_option:compilation_mode": "opt",
},
**kwargs
)
def _test_propeller_optimize_option_from_label_impl(env, target):
binary_target = cc_binary_target_subject.from_target(env, target)
link_action = binary_target.action_generating("{package}/{name}{binary_extension}")
link_action.outputs().has_size(1)
link_action.inputs().contains_predicate(matching.file_basename_equals("ld_profile.txt"))
link_action.argv().contains_predicate(matching.str_matches("-Wl,--symbol-ordering-file=*/ld_profile.txt"))
backend_action = env.expect.that_target(target).action_generating(
"{package}/{name}.lto/{bindir}/{package}/_objs/{name}/binfile.o",
)
backend_action.mnemonic().equals("CcLtoBackendCompile")
backend_action.argv().contains_predicate(matching.str_matches("-fbasic-block-sections=list=*/cc_profile.txt"))
backend_action.argv().contains("-DBUILD_PROPELLER_ENABLED=1")
backend_action.inputs().contains_predicate(matching.file_basename_equals("cc_profile.txt"))
backend_action.inputs().contains_predicate(matching.file_basename_equals("ld_profile.txt"))
def _test_no_use_lto_indexing_bitcode_file(name, **kwargs):
_create_thin_lto_basic_targets(name)
cc_analysis_test(
name = name,
impl = _test_no_use_lto_indexing_bitcode_file_impl,
target = name + "/bin",
test_features = [
"thin_lto",
"supports_pic",
"supports_start_end_lib",
"no_use_lto_indexing_bitcode_file",
],
**kwargs
)
def _test_no_use_lto_indexing_bitcode_file_impl(env, target):
test_name = target.label.name.split("/")[0]
lib_name = test_name + "/lib"
binary_obj_path = "{package}/{name}.lto/{bindir}/{package}/_objs/{name}/binfile.pic.o".format(
package = target.label.package,
name = target.label.name,
bindir = target[TestingAspectInfo].bin_path,
)
backend_action = env.expect.that_target(target).action_generating(binary_obj_path)
backend_action.mnemonic().equals("CcLtoBackendCompile")
index_action = env.expect.that_target(target).action_generating(binary_obj_path + ".thinlto.bc")
index_action.mnemonic().equals("CppLTOIndexing")
index_action.argv().not_contains("object_suffix_replace")
binary_normal_obj = "{package}/_objs/{name}/binfile.pic.o".format(
package = target.label.package,
name = target.label.name,
)
lib_normal_obj = "{package}/_objs/{lib_name}/libfile.pic.o".format(
package = target.label.package,
lib_name = lib_name,
)
index_action.inputs().contains(binary_normal_obj)
index_action.inputs().contains(lib_normal_obj)
bitcode_action = env.expect.that_target(target).action_generating(binary_normal_obj)
bitcode_action.mnemonic().equals("CppCompile")
bitcode_action.argv().not_contains("lto_indexing_bitcode=")
def _test_fdo_cache_prefetch_llvm_options_to_backend_base(name, extra_config_settings, **kwargs):
util.helper_target(
fdo_prefetch_hints,
name = name + "/test_profile",
profile = "prefetch.afdo",
)
_create_thin_lto_basic_targets(name)
config_settings = {
"//command_line_option:fdo_prefetch_hints": Label(":" + name + "/test_profile"),
"//command_line_option:compilation_mode": "opt",
}
config_settings.update(extra_config_settings)
cc_analysis_test(
name = name,
impl = _test_fdo_cache_prefetch_llvm_options_to_backend_impl,
target = name + "/bin",
with_features = ["thin_lto", "autofdo", "supports_start_end_lib", "fdo_prefetch_hints"],
test_features = ["thin_lto", "supports_start_end_lib", "fdo_prefetch_hints"],
config_settings = config_settings,
**kwargs
)
def _test_fdo_cache_prefetch_llvm_options_to_backend_impl(env, target):
obj_path = "{package}/{name}.lto/{bindir}/{package}/_objs/{name}/binfile.o".format(
package = target.label.package,
name = target.label.name,
bindir = target[TestingAspectInfo].bin_path,
)
backend_action = env.expect.that_target(target).action_generating(obj_path)
backend_action.mnemonic().equals("CcLtoBackendCompile")
backend_action.argv().contains("-mllvm")
backend_action.argv().contains_predicate(matching.str_matches("*-prefetch-hints-file=*/prefetch.afdo"))
backend_action.inputs().contains_predicate(matching.file_basename_equals("prefetch.afdo"))
def _test_fdo_cache_prefetch_llvm_options_to_backend_from_label(name, **kwargs):
_test_fdo_cache_prefetch_llvm_options_to_backend_base(name, [], **kwargs)
def _test_fdo_cache_prefetch_and_fdo_llvm_options_to_backend_from_label(name, **kwargs):
_test_fdo_cache_prefetch_llvm_options_to_backend_base(
name,
[("//command_line_option:fdo_optimize", "/profile.zip")],
**kwargs
)
def _test_thin_lto_without_supports_start_end_lib_error(name, **kwargs):
_create_thin_lto_basic_targets(name)
cc_analysis_test(
name = name,
impl = _test_thin_lto_without_supports_start_end_lib_error_impl,
target = name + "/bin",
with_features = ["thin_lto"],
test_features = ["thin_lto"],
expect_failure = True,
**kwargs
)
def _test_thin_lto_without_supports_start_end_lib_error_impl(env, target):
env.expect.that_target(target).failures().contains_predicate(
matching.contains("The feature supports_start_end_lib must be enabled."),
)
def cc_binary_thin_lto_tests(name):
"""TestSuite for cc_binary with ThinLTO.
Args:
name: The name of the test suite.
"""
tests = []
# These tests pass on all Bazel versions.
tests.append(_test_thin_lto_action_graph)
tests.append(_test_thin_lto_no_linkstatic)
tests.append(_test_thin_lto_fission)
tests.append(_test_thin_lto_no_linkstatic_fission)
tests.append(_test_thin_lto_linkstatic_cc_test_fission)
tests.append(_test_assembler_source)
tests.append(_test_no_source_files)
tests.append(_test_fdo_instrument)
tests.append(_test_lto_index_opt)
tests.append(_test_copt)
tests.append(_test_per_file_copt)
tests.append(_test_per_file_lto_backend_opt)
tests.append(_test_autofdo)
tests.append(_test_autofdo_no_implicit_thin_lto)
tests.append(_test_autofdo_implicit_thin_lto)
tests.append(_test_autofdo_implicit_thin_lto_disabled_option)
tests.append(_test_autofdo_implicit_thin_lto_disabled_rule)
tests.append(_test_autofdo_implicit_thin_lto_disabled_package)
tests.append(_test_fdo_no_implicit_thin_lto)
tests.append(_test_fdo_implicit_thin_lto)
tests.append(_test_fdo_implicit_thin_lto_disabled_option)
tests.append(_test_fdo_implicit_thin_lto_disabled_rule)
tests.append(_test_fdo_implicit_thin_lto_disabled_package)
tests.append(_test_xbinary_fdo_no_implicit_thin_lto)
tests.append(_test_xbinary_fdo_implicit_thin_lto)
tests.append(_test_xbinary_fdo_implicit_thin_lto_disabled_option)
tests.append(_test_xbinary_fdo_implicit_thin_lto_disabled_rule)
tests.append(_test_xbinary_fdo_implicit_thin_lto_disabled_package)
tests.append(_test_xbinary_fdo)
tests.append(_test_xbinary_fdo_no_autofdo_or_fdo_implicit_thin_lto)
tests.append(_test_pic_backend_order)
tests.append(_test_propeller_optimize_absolute_options)
tests.append(_test_propeller_cc_compile)
tests.append(_test_propeller_cc_compile_with_propeller_optimize_thin_lto_compile_actions)
tests.append(_test_propeller_cc_compile_with_thin_lto_disabled)
tests.append(_test_propeller_host_builds)
tests.append(_test_no_use_lto_indexing_bitcode_file)
tests.append(_test_fdo_cache_prefetch_llvm_options_to_backend_from_label)
tests.append(_test_fdo_cache_prefetch_and_fdo_llvm_options_to_backend_from_label)
tests.append(_test_thin_lto_without_supports_start_end_lib_error)
# These tests fail on Bazel 7 and 8, run only for Bazel 9+.
if bazel_features.cc.cc_common_is_in_rules_cc:
tests.append(_test_thin_lto_linkshared)
tests.append(_test_thin_lto_backend_env)
tests.append(_test_linkstatic_cc_test)
tests.append(_test_test_only_target)
tests.append(_test_use_shared_all_linkstatic)
tests.append(_test_lto_standalone_command_lines)
tests.append(_test_lto_backend_opt)
tests.append(_test_link_opt)
tests.append(_test_propeller_optimize_option_from_label)
tests.append(_test_assembler_source_with_shared_nonlto_backends)
tests.append(_test_duplicated_static_libraries_in_lto)
test_suite(
name = name,
tests = tests,
)