blob: 8af3d00ddb912a7bd8466e93fe61cef341b343b8 [file] [log] [blame]
// Copyright 2014 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.devtools.build.lib.rules.cpp;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.MoreCollectors;
import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.util.ActionsTestUtil;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget;
import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
import com.google.devtools.build.lib.packages.util.Crosstool.CcToolchainConfig;
import com.google.devtools.build.lib.packages.util.MockCcSupport;
import com.google.devtools.build.lib.packages.util.ResourceLoader;
import com.google.devtools.build.lib.rules.cpp.CcCommon.Language;
import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration;
import com.google.devtools.build.lib.rules.cpp.CppConfiguration.DynamicMode;
import com.google.devtools.build.lib.rules.cpp.CppConfiguration.Tool;
import com.google.devtools.build.lib.testutil.TestConstants;
import com.google.devtools.common.options.OptionsParsingException;
import java.io.IOException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/**
* Tests for toolchain features.
*/
@RunWith(JUnit4.class)
public class CcToolchainTest extends BuildViewTestCase {
@Test
public void testFilesToBuild() throws Exception {
scratch.file("a/BUILD", "cc_toolchain_alias(name = 'b')");
ConfiguredTarget b = getConfiguredTarget("//a:b");
assertThat(ActionsTestUtil.baseArtifactNames(getFilesToBuild(b))).isNotNull();
}
@Test
public void testInterfaceSharedObjects() throws Exception {
scratch.file("a/BUILD", "cc_toolchain_alias(name = 'b')");
getAnalysisMock()
.ccSupport()
.setupCcToolchainConfig(
mockToolsConfig,
CcToolchainConfig.builder()
.withFeatures(CppRuleClasses.SUPPORTS_INTERFACE_SHARED_LIBRARIES));
useConfiguration("--features=-supports_interface_shared_libraries");
invalidatePackages();
ConfiguredTarget target = getConfiguredTarget("//a:b");
assertThat(
CppHelper.useInterfaceSharedLibraries(
getConfiguration(target).getFragment(CppConfiguration.class),
FeatureConfiguration.EMPTY))
.isFalse();
useConfiguration();
invalidatePackages();
target = getConfiguredTarget("//a:b");
assertThat(
CppHelper.useInterfaceSharedLibraries(
getConfiguration(target).getFragment(CppConfiguration.class),
FeatureConfiguration.EMPTY))
.isFalse();
useConfiguration("--nointerface_shared_objects");
invalidatePackages();
target = getConfiguredTarget("//a:b");
assertThat(
CppHelper.useInterfaceSharedLibraries(
getConfiguration(target).getFragment(CppConfiguration.class),
FeatureConfiguration.EMPTY))
.isFalse();
}
@Test
public void testFission() throws Exception {
scratch.file("a/BUILD", "cc_library(name = 'a', srcs = ['a.cc'])");
// Default configuration: disabled.
getAnalysisMock()
.ccSupport()
.setupCcToolchainConfig(
mockToolsConfig,
CcToolchainConfig.builder().withFeatures(CppRuleClasses.PER_OBJECT_DEBUG_INFO));
useConfiguration();
assertThat(getCppCompileOutputs()).doesNotContain("yolo");
// Mode-specific settings.
useConfiguration("-c", "dbg", "--fission=dbg");
assertThat(getCppCompileOutputs()).contains("a.dwo");
useConfiguration("-c", "dbg", "--fission=opt");
assertThat(getCppCompileOutputs()).doesNotContain("a.dwo");
useConfiguration("-c", "dbg", "--fission=opt,dbg");
assertThat(getCppCompileOutputs()).contains("a.dwo");
useConfiguration("-c", "fastbuild", "--fission=opt,dbg");
assertThat(getCppCompileOutputs()).doesNotContain("a.dwo");
useConfiguration("-c", "fastbuild", "--fission=opt,dbg");
assertThat(getCppCompileOutputs()).doesNotContain("a.dwo");
// Universally enabled
useConfiguration("-c", "dbg", "--fission=yes");
assertThat(getCppCompileOutputs()).contains("a.dwo");
useConfiguration("-c", "opt", "--fission=yes");
assertThat(getCppCompileOutputs()).contains("a.dwo");
useConfiguration("-c", "fastbuild", "--fission=yes");
assertThat(getCppCompileOutputs()).contains("a.dwo");
// Universally disabled
useConfiguration("-c", "dbg", "--fission=no");
assertThat(getCppCompileOutputs()).doesNotContain("a.dwo");
useConfiguration("-c", "opt", "--fission=no");
assertThat(getCppCompileOutputs()).doesNotContain("a.dwo");
useConfiguration("-c", "fastbuild", "--fission=no");
assertThat(getCppCompileOutputs()).doesNotContain("a.dwo");
}
private ImmutableList<String> getCppCompileOutputs() throws Exception {
RuleConfiguredTarget target = (RuleConfiguredTarget) getConfiguredTarget("//a:a");
return target.getActions().stream()
.filter(a -> a.getMnemonic().equals("CppCompile"))
.findFirst()
.get()
.getOutputs()
.stream()
.map(a -> a.getFilename())
.collect(ImmutableList.toImmutableList());
}
@Test
public void testPic() throws Exception {
scratch.file("a/BUILD", "cc_toolchain_alias(name = 'b')");
assertThat(usePicForBinariesWithConfiguration("--platforms=" + TestConstants.PLATFORM_LABEL))
.isFalse();
assertThat(
usePicForBinariesWithConfiguration(
"--platforms=" + TestConstants.PLATFORM_LABEL, "-c", "opt"))
.isFalse();
getAnalysisMock()
.ccSupport()
.setupCcToolchainConfig(
mockToolsConfig, CcToolchainConfig.builder().withFeatures(CppRuleClasses.SUPPORTS_PIC));
invalidatePackages();
assertThat(usePicForBinariesWithConfiguration("--platforms=" + TestConstants.PLATFORM_LABEL))
.isTrue();
assertThat(
usePicForBinariesWithConfiguration(
"--platforms=" + TestConstants.PLATFORM_LABEL, "-c", "opt"))
.isFalse();
}
private boolean usePicForBinariesWithConfiguration(String... configuration) throws Exception {
useConfiguration(configuration);
ConfiguredTarget target = getConfiguredTarget("//a:b");
CcToolchainProvider toolchainProvider = target.get(CcToolchainProvider.PROVIDER);
CppConfiguration cppConfiguration = getRuleContext(target).getFragment(CppConfiguration.class);
FeatureConfiguration featureConfiguration =
CcCommon.configureFeaturesOrThrowEvalException(
/* requestedFeatures= */ ImmutableSet.of(),
/* unsupportedFeatures= */ ImmutableSet.of(),
Language.CPP,
toolchainProvider,
cppConfiguration);
return CppHelper.usePicForBinaries(cppConfiguration, featureConfiguration);
}
@Test
public void testBadDynamicRuntimeLib() throws Exception {
scratch.file("a/cc_toolchain_config.bzl", MockCcSupport.EMPTY_CC_TOOLCHAIN);
scratch.file(
"a/BUILD",
"""
load(":cc_toolchain_config.bzl", "cc_toolchain_config")
filegroup(
name = "dynamic",
srcs = [
"not-an-so",
"so.so",
],
)
filegroup(
name = "static",
srcs = [
"a.a",
"not-an-a",
],
)
cc_toolchain(
name = "a",
all_files = "all-a",
ar_files = "ar-a",
as_files = "as-a",
compiler_files = "compile-a",
coverage_files = "gcov-a",
dwp_files = "dwp-a",
dynamic_runtime_lib = ":dynamic",
linker_files = "link-a",
module_map = "map",
objcopy_files = "objcopy-a",
static_runtime_lib = ":static",
strip_files = "strip-a",
toolchain_config = ":toolchain_config",
)
cc_toolchain_config(name = "toolchain_config")
""");
getAnalysisMock()
.ccSupport()
.setupCcToolchainConfig(
mockToolsConfig,
CcToolchainConfig.builder().withFeatures(CppRuleClasses.STATIC_LINK_CPP_RUNTIMES));
useConfiguration();
getConfiguredTarget("//a:a");
}
@Test
public void testDynamicMode() throws Exception {
scratch.file(
"a/BUILD",
"""
load(":cc_toolchain_config.bzl", "cc_toolchain_config")
filegroup(
name = "empty",
)
filegroup(
name = "banana",
srcs = [
"banana1",
"banana2",
],
)
cc_toolchain(
name = "b",
all_files = ":banana",
ar_files = ":empty",
as_files = ":empty",
compiler_files = ":empty",
dwp_files = ":empty",
dynamic_runtime_lib = ":empty",
linker_files = ":empty",
objcopy_files = ":empty",
static_runtime_lib = ":empty",
strip_files = ":empty",
toolchain_config = ":toolchain_config",
toolchain_identifier = "toolchain-identifier-k8",
)
cc_toolchain_config(name = "toolchain_config")
""");
scratch.file("a/cc_toolchain_config.bzl", MockCcSupport.EMPTY_CC_TOOLCHAIN);
// Check defaults.
useConfiguration();
ConfiguredTarget target = getConfiguredTarget("//a:b");
CppConfiguration cppConfiguration =
getConfiguration(target).getFragment(CppConfiguration.class);
assertThat(cppConfiguration.getDynamicModeFlag()).isEqualTo(DynamicMode.DEFAULT);
// Test "off"
useConfiguration("--dynamic_mode=off");
target = getConfiguredTarget("//a:b");
cppConfiguration = getConfiguration(target).getFragment(CppConfiguration.class);
assertThat(cppConfiguration.getDynamicModeFlag()).isEqualTo(DynamicMode.OFF);
// Test "fully"
useConfiguration("--dynamic_mode=fully");
target = getConfiguredTarget("//a:b");
cppConfiguration = getConfiguration(target).getFragment(CppConfiguration.class);
assertThat(cppConfiguration.getDynamicModeFlag()).isEqualTo(DynamicMode.FULLY);
// Check an invalid value for disable_dynamic.
OptionsParsingException e =
assertThrows(OptionsParsingException.class, () -> useConfiguration("--dynamic_mode=very"));
assertThat(e)
.hasMessageThat()
.isEqualTo(
"While parsing option --dynamic_mode=very: Not a valid dynamic mode: 'very' "
+ "(should be off, default or fully)");
}
public void assertInvalidIncludeDirectoryMessage(String entry, String messageRegex)
throws Exception {
scratch.overwriteFile("a/BUILD", "cc_toolchain_alias(name = 'b')");
getAnalysisMock()
.ccSupport()
.setupCcToolchainConfig(
mockToolsConfig, CcToolchainConfig.builder().withCxxBuiltinIncludeDirectories(entry));
useConfiguration();
invalidatePackages();
AssertionError e = assertThrows(AssertionError.class, () -> getConfiguredTarget("//a:b"));
assertThat(e).hasMessageThat().containsMatch(messageRegex);
}
@Test
public void testInvalidIncludeDirectory() throws Exception {
assertInvalidIncludeDirectoryMessage("%package(//a", "has an unrecognized %prefix%");
assertInvalidIncludeDirectoryMessage(
"%package(//a:@@a)%", "invalid package identifier '//a:@@a': contains ':'");
assertInvalidIncludeDirectoryMessage(
"%package(//a)%foo", "The path in the package.*is not valid");
}
@Test
public void testModuleMapAttribute() throws Exception {
scratch.file("modules/map/cc_toolchain_config.bzl", MockCcSupport.EMPTY_CC_TOOLCHAIN);
scratchConfiguredTarget(
"modules/map",
"c",
"load(':cc_toolchain_config.bzl', 'cc_toolchain_config')",
"cc_toolchain(",
" name = 'c',",
" toolchain_identifier = 'toolchain-identifier-k8',",
" toolchain_config = ':toolchain_config',",
" module_map = 'map',",
" ar_files = 'ar-cherry',",
" as_files = 'as-cherry',",
" compiler_files = 'compile-cherry',",
" dwp_files = 'dwp-cherry',",
" coverage_files = 'gcov-cherry',",
" linker_files = 'link-cherry',",
" strip_files = ':every-file',",
" objcopy_files = 'objcopy-cherry',",
" all_files = ':every-file',",
" dynamic_runtime_lib = 'dynamic-runtime-libs-cherry',",
" static_runtime_lib = 'static-runtime-libs-cherry')",
"cc_toolchain_config(name = 'toolchain_config')");
}
@Test
public void testModuleMapAttributeOptional() throws Exception {
scratch.file("modules/map/cc_toolchain_config.bzl", MockCcSupport.EMPTY_CC_TOOLCHAIN);
scratchConfiguredTarget(
"modules/map",
"c",
"load(':cc_toolchain_config.bzl', 'cc_toolchain_config')",
"cc_toolchain(",
" name = 'c',",
" toolchain_identifier = 'toolchain-identifier-k8',",
" toolchain_config = ':toolchain_config',",
" ar_files = 'ar-cherry',",
" as_files = 'as-cherry',",
" compiler_files = 'compile-cherry',",
" dwp_files = 'dwp-cherry',",
" linker_files = 'link-cherry',",
" strip_files = ':every-file',",
" objcopy_files = 'objcopy-cherry',",
" all_files = ':every-file',",
" dynamic_runtime_lib = 'dynamic-runtime-libs-cherry',",
" static_runtime_lib = 'static-runtime-libs-cherry')",
"cc_toolchain_config(name = 'toolchain_config')");
}
@Test
public void testFailWithMultipleModuleMaps() throws Exception {
scratch.file("modules/multiple/cc_toolchain_config.bzl", MockCcSupport.EMPTY_CC_TOOLCHAIN);
checkError(
"modules/multiple",
"c",
"expected a single artifact",
"load(':cc_toolchain_config.bzl', 'cc_toolchain_config')",
"filegroup(name = 'multiple-maps', srcs = ['a.cppmap', 'b.cppmap'])",
"cc_toolchain(",
" name = 'c',",
" toolchain_identifier = 'toolchain-identifier-k8',",
" toolchain_config = ':toolchain_config',",
" module_map = ':multiple-maps',",
" ar_files = 'ar-cherry',",
" as_files = 'as-cherry',",
" compiler_files = 'compile-cherry',",
" dwp_files = 'dwp-cherry',",
" coverage_files = 'gcov-cherry',",
" linker_files = 'link-cherry',",
" strip_files = ':every-file',",
" objcopy_files = 'objcopy-cherry',",
" all_files = ':every-file',",
" dynamic_runtime_lib = 'dynamic-runtime-libs-cherry',",
" static_runtime_lib = 'static-runtime-libs-cherry')",
"cc_toolchain_config(name = 'toolchain_config')");
}
@Test
public void testToolchainAlias() throws Exception {
ConfiguredTarget reference = scratchConfiguredTarget("a", "ref",
"cc_toolchain_alias(name='ref')");
assertThat(reference.get(CcToolchainProvider.PROVIDER.getKey())).isNotNull();
}
@Test
public void testFdoOptimizeInvalidUseGeneratedArtifact() throws Exception {
reporter.removeHandler(failFastHandler);
scratch.file(
"a/BUILD",
"""
cc_toolchain_alias(name = "b")
genrule(
name = "gen_artifact",
outs = ["profile.profdata"],
cmd = "touch $@",
)
""");
useConfiguration("-c", "opt", "--fdo_optimize=//a:gen_artifact");
assertThat(getConfiguredTarget("//a:b")).isNull();
assertContainsEvent(
"--fdo_optimize points to a target that is not an input file or an fdo_profile rule");
}
@Test
public void testFdoOptimizeUnexpectedExtension() throws Exception {
reporter.removeHandler(failFastHandler);
scratch.file(
"a/BUILD",
"""
cc_toolchain_alias(name = "b")
exports_files(["profile.unexpected"])
""");
scratch.file("a/profile.unexpected", "");
useConfiguration("-c", "opt", "--fdo_optimize=//a:profile.unexpected");
assertThat(getConfiguredTarget("//a:b")).isNull();
assertContainsEvent("invalid extension for FDO profile file");
}
@Test
public void testFdoOptimizeNotInputFile() throws Exception {
reporter.removeHandler(failFastHandler);
scratch.file(
"a/BUILD",
"""
cc_toolchain_alias(name = "b")
filegroup(
name = "profile",
srcs = ["my_profile.afdo"],
)
""");
scratch.file("my_profile.afdo", "");
useConfiguration("-c", "opt", "--fdo_optimize=//a:profile");
assertThat(getConfiguredTarget("//a:b")).isNull();
assertContainsEvent(
"--fdo_optimize points to a target that is not an input file or an fdo_profile rule");
}
@Test
public void testFdoOptimizeNotCompatibleWithCoverage() throws Exception {
reporter.removeHandler(failFastHandler);
scratch.file(
"a/BUILD",
"""
cc_toolchain_alias(name = "b")
exports_files(["profile.afdo"])
""");
scratch.file("a/profile.afdo", "");
useConfiguration("-c", "opt", "--fdo_optimize=//a:profile.afdo", "--collect_code_coverage");
assertThat(getConfiguredTarget("//a:b")).isNull();
assertContainsEvent("coverage mode is not compatible with FDO optimization");
}
@Test
public void testCSFdoRejectRelativePath() throws Exception {
reporter.removeHandler(failFastHandler);
scratch.file("a/BUILD", "cc_toolchain_alias(name = 'b')");
scratch.file("a/profile.profdata", "");
scratch.file("a/csprofile.profdata", "");
Exception e =
assertThrows(
Exception.class,
() ->
useConfiguration(
"-c",
"opt",
"--fdo_optimize=/a/profile.profdata",
"--cs_fdo_absolute_path=a/csprofile.profdata"));
assertThat(e).hasMessageThat().contains("in --cs_fdo_absolute_path is not an absolute path");
}
@Test
public void testXFdoOptimizeNotProvider() throws Exception {
reporter.removeHandler(failFastHandler);
scratch.file(
"a/BUILD",
"""
cc_toolchain_alias(name = "b")
genrule(
name = "profile.xfdo",
outs = ["c.txt"],
cmd = "",
)
""");
useConfiguration("-c", "opt", "--xbinary_fdo=//a:profile.xfdo");
assertThat(getConfiguredTarget("//a:b")).isNull();
assertContainsEvent("does not have mandatory providers: 'FdoProfileInfo'");
}
@Test
public void testXFdoOptimizeAcceptAFdoInput() throws Exception {
reporter.removeHandler(failFastHandler);
scratch.file(
"a/BUILD",
"""
cc_toolchain_alias(name = "b")
fdo_profile(
name = "out.afdo",
profile = "profile.afdo",
)
""");
useConfiguration("-c", "opt", "--xbinary_fdo=//a:out.afdo");
assertThat(getConfiguredTarget("//a:b")).isNotNull();
assertNoEvents();
}
@Test
public void testXFdoOptimizeRejectFdoInput() throws Exception {
reporter.removeHandler(failFastHandler);
scratch.file(
"a/BUILD",
"""
cc_toolchain_alias(name = "b")
fdo_profile(
name = "out.fdo",
profile = "profile.profdata",
)
""");
useConfiguration("-c", "opt", "--xbinary_fdo=//a:out.fdo");
assertThat(getConfiguredTarget("//a:b")).isNull();
assertContainsEvent("--xbinary_fdo only accepts");
}
@Test
public void testZipperInclusionDependsOnFdoOptimization() throws Exception {
reporter.removeHandler(failFastHandler);
scratch.file(
"a/BUILD",
"""
load(":cc_toolchain_config.bzl", "cc_toolchain_config")
filegroup(
name = "empty",
)
cc_toolchain(
name = "b",
all_files = ":empty",
ar_files = ":empty",
as_files = ":empty",
compiler_files = ":empty",
dwp_files = ":empty",
linker_files = ":empty",
objcopy_files = ":empty",
strip_files = ":empty",
toolchain_config = ":toolchain_config",
toolchain_identifier = "toolchain-identifier-k8",
)
cc_toolchain_config(name = "toolchain_config")
""");
scratch.file("fdo/my_profile.afdo", "");
scratch.file(
"fdo/BUILD",
"""
exports_files(["my_profile.afdo"])
fdo_profile(
name = "fdo",
profile = ":my_profile.profdata",
)
""");
scratch.file("a/cc_toolchain_config.bzl", MockCcSupport.EMPTY_CC_TOOLCHAIN);
useConfiguration();
assertThat(getPrerequisites(getConfiguredTarget("//a:b"), ":zipper")).isEmpty();
useConfiguration("-c", "opt", "--fdo_optimize=//fdo:my_profile.afdo");
assertThat(getPrerequisites(getConfiguredTarget("//a:b"), ":zipper")).isNotEmpty();
useConfiguration("-c", "opt", "--fdo_profile=//fdo:fdo");
assertThat(getPrerequisites(getConfiguredTarget("//a:b"), ":zipper")).isNotEmpty();
}
private void loadCcToolchainConfigLib() throws IOException {
scratch.appendFile("tools/cpp/BUILD", "");
scratch.overwriteFile(
"tools/cpp/cc_toolchain_config_lib.bzl",
ResourceLoader.readFromResources(
TestConstants.RULES_CC_REPOSITORY_EXECROOT + "cc/cc_toolchain_config_lib.bzl"));
}
@Test
public void testToolPathsInToolchainFromStarlarkRule() throws Exception {
loadCcToolchainConfigLib();
writeStarlarkRule();
useConfiguration("--cpu=k8");
ConfiguredTarget target = getConfiguredTarget("//a:b");
CcToolchainProvider toolchainProvider = target.get(CcToolchainProvider.PROVIDER);
assertThat(
CcToolchainProvider.getToolPathString(
toolchainProvider.getToolPaths(),
Tool.AR,
toolchainProvider.getCcToolchainLabel(),
toolchainProvider.getToolchainIdentifier()))
.isEqualTo("/absolute/path");
assertThat(
CcToolchainProvider.getToolPathString(
toolchainProvider.getToolPaths(),
Tool.CPP,
toolchainProvider.getCcToolchainLabel(),
toolchainProvider.getToolchainIdentifier()))
.isEqualTo("a/relative/path");
}
private void writeStarlarkRule() throws IOException {
scratch.file(
"a/BUILD",
"""
load(":crosstool_rule.bzl", "cc_toolchain_config_rule")
cc_toolchain_config_rule(name = "toolchain_config")
filegroup(
name = "empty",
)
cc_toolchain(
name = "b",
all_files = ":empty",
ar_files = ":empty",
as_files = ":empty",
compiler_files = ":empty",
dwp_files = ":empty",
linker_files = ":empty",
objcopy_files = ":empty",
strip_files = ":empty",
toolchain_config = ":toolchain_config",
)
""");
scratch.file(
"a/crosstool_rule.bzl",
"""
load(
"//tools/cpp:cc_toolchain_config_lib.bzl",
"action_config",
"artifact_name_pattern",
"env_entry",
"env_set",
"feature",
"feature_set",
"flag_group",
"flag_set",
"make_variable",
"tool",
"tool_path",
"variable_with_value",
"with_feature_set",
)
def _impl(ctx):
return cc_common.create_cc_toolchain_config_info(
ctx = ctx,
features = [
feature(name = "simple_feature"),
feature(name = "no_legacy_features"),
],
action_configs = [
action_config(action_name = "simple_action", enabled = True),
],
artifact_name_patterns = [artifact_name_pattern(
category_name = "static_library",
prefix = "prefix",
extension = ".a",
)],
cxx_builtin_include_directories = ["dir1", "dir2", "dir3"],
toolchain_identifier = "toolchain",
host_system_name = "host",
target_system_name = "target",
target_cpu = "cpu",
target_libc = "libc",
compiler = "compiler",
abi_libc_version = "abi_libc",
abi_version = "banana",
tool_paths = [
tool_path(name = "ar", path = "/absolute/path"),
tool_path(name = "cpp", path = "relative/path"),
tool_path(name = "gcc", path = "/some/path"),
tool_path(name = "gcov", path = "/some/path"),
tool_path(name = "gcovtool", path = "/some/path"),
tool_path(name = "ld", path = "/some/path"),
tool_path(name = "nm", path = "/some/path"),
tool_path(name = "objcopy", path = "/some/path"),
tool_path(name = "objdump", path = "/some/path"),
tool_path(name = "strip", path = "/some/path"),
tool_path(name = "dwp", path = "/some/path"),
tool_path(name = "llvm_profdata", path = "/some/path"),
],
cc_target_os = "os",
builtin_sysroot = "sysroot",
)
cc_toolchain_config_rule = rule(
implementation = _impl,
attrs = {},
provides = [CcToolchainConfigInfo],
fragments = ["cpp"],
)
""");
}
@Test
public void testSysroot_fromCrosstool_unset() throws Exception {
scratch.file("a/BUILD", "cc_toolchain_alias(name = 'b')");
scratch.file("libc1/BUILD", "filegroup(name = 'everything', srcs = ['header1.h'])");
scratch.file("libc1/header1.h", "#define FOO 1");
ConfiguredTarget target = getConfiguredTarget("//a:b");
CcToolchainProvider toolchainProvider = target.get(CcToolchainProvider.PROVIDER);
assertThat(toolchainProvider.getSysroot()).isEqualTo("/usr/grte/v1");
}
@Test
public void correctToolFilesUsed() throws Exception {
scratch.file(
"a/BUILD",
"""
cc_toolchain_alias(name = "a")
cc_library(
name = "l",
srcs = ["l.c"],
)
cc_library(
name = "asm",
srcs = ["a.s"],
)
cc_library(
name = "preprocessed-asm",
srcs = ["a.S"],
)
""");
getAnalysisMock()
.ccSupport()
.setupCcToolchainConfig(
mockToolsConfig,
CcToolchainConfig.builder().withFeatures(CppRuleClasses.SUPPORTS_DYNAMIC_LINKER));
useConfiguration("--incompatible_use_specific_tool_files");
ConfiguredTarget target = getConfiguredTarget("//a:a");
CcToolchainProvider toolchainProvider = target.get(CcToolchainProvider.PROVIDER);
RuleConfiguredTarget libTarget = (RuleConfiguredTarget) getConfiguredTarget("//a:l");
Artifact staticLib =
getOutputGroup(libTarget, "archive").toList().stream()
.collect(MoreCollectors.onlyElement());
ActionAnalysisMetadata staticAction = getGeneratingAction(staticLib);
assertThat(staticAction.getInputs().toList())
.containsAtLeastElementsIn(toolchainProvider.getArFiles().toList());
Artifact dynamicLib =
getOutputGroup(libTarget, "dynamic_library").toList().stream()
.collect(MoreCollectors.onlyElement());
ActionAnalysisMetadata dynamicAction = getGeneratingAction(dynamicLib);
assertThat(dynamicAction.getInputs().toList())
.containsAtLeastElementsIn(toolchainProvider.getLinkerFiles().toList());
ActionAnalysisMetadata cCompileAction =
libTarget.getActions().stream()
.filter((a) -> a.getMnemonic().equals("CppCompile"))
.collect(MoreCollectors.onlyElement());
assertThat(cCompileAction.getInputs().toList())
.containsAtLeastElementsIn(toolchainProvider.getCompilerFiles().toList());
ActionAnalysisMetadata asmAction =
((RuleConfiguredTarget) getConfiguredTarget("//a:asm"))
.getActions().stream()
.filter((a) -> a.getMnemonic().equals("CppCompile"))
.collect(MoreCollectors.onlyElement());
assertThat(asmAction.getInputs().toList())
.containsAtLeastElementsIn(toolchainProvider.getAsFiles().toList());
ActionAnalysisMetadata preprocessedAsmAction =
((RuleConfiguredTarget) getConfiguredTarget("//a:preprocessed-asm"))
.getActions().stream()
.filter((a) -> a.getMnemonic().equals("CppCompile"))
.collect(MoreCollectors.onlyElement());
assertThat(preprocessedAsmAction.getInputs().toList())
.containsAtLeastElementsIn(toolchainProvider.getCompilerFiles().toList());
}
@Test
public void testCcToolchainLoadedThroughMacro() throws Exception {
setupTestCcToolchainLoadedThroughMacro(/* loadMacro= */ true);
assertThat(getConfiguredTarget("//a:a")).isNotNull();
assertNoEvents();
}
private void setupTestCcToolchainLoadedThroughMacro(boolean loadMacro) throws Exception {
scratch.file("a/cc_toolchain_config.bzl", MockCcSupport.EMPTY_CC_TOOLCHAIN);
scratch.file(
"a/BUILD",
"load(':cc_toolchain_config.bzl', 'cc_toolchain_config')",
getAnalysisMock().ccSupport().getMacroLoadStatement(loadMacro, "cc_toolchain"),
getToolchainRule("a"));
}
private static String getToolchainRule(String targetName) {
return Joiner.on("\n")
.join(
"cc_toolchain(",
" name = '" + targetName + "',",
" toolchain_identifier = 'toolchain-identifier-k8',",
" toolchain_config = ':toolchain_config',",
" all_files = ':banana',",
" ar_files = ':empty',",
" as_files = ':empty',",
" compiler_files = ':empty',",
" dwp_files = ':empty',",
" linker_files = ':empty',",
" strip_files = ':empty',",
" objcopy_files = ':empty',",
" dynamic_runtime_lib = ':empty',",
" static_runtime_lib = ':empty')",
"filegroup(",
" name='empty')",
"filegroup(",
" name = 'banana',",
" srcs = ['banana1', 'banana2'])",
"cc_toolchain_config(name='toolchain_config')");
}
}