| // 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 com.google.devtools.build.lib.testutil.MoreAsserts.assertDoesNotContainSublist; |
| import static org.junit.Assert.fail; |
| |
| import com.google.common.collect.ImmutableList; |
| import com.google.devtools.build.lib.actions.util.ActionsTestUtil; |
| import com.google.devtools.build.lib.analysis.ConfiguredTarget; |
| import com.google.devtools.build.lib.analysis.RuleContext; |
| import com.google.devtools.build.lib.analysis.platform.ToolchainInfo; |
| import com.google.devtools.build.lib.analysis.util.BuildViewTestCase; |
| import com.google.devtools.build.lib.packages.util.MockCcSupport; |
| 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.testutil.TestConstants; |
| import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig; |
| import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.CToolchain; |
| import com.google.devtools.common.options.OptionsParsingException; |
| import com.google.protobuf.TextFormat; |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.List; |
| 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 { |
| private static final String CPP_TOOLCHAIN_TYPE = |
| TestConstants.TOOLS_REPOSITORY + "//tools/cpp:toolchain_type"; |
| |
| @Test |
| public void testFilesToBuild() throws Exception { |
| scratch.file("a/BUILD", |
| "filegroup(", |
| " name='empty')", |
| "filegroup(", |
| " name = 'banana',", |
| " srcs = ['banana1', 'banana2'])", |
| "cc_toolchain(", |
| " name = 'b',", |
| " cpu = 'banana',", |
| " 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_libs = [':empty'],", |
| " static_runtime_libs = [':empty'])"); |
| |
| ConfiguredTarget b = getConfiguredTarget("//a:b"); |
| assertThat(ActionsTestUtil.baseArtifactNames(getFilesToBuild(b))) |
| .containsExactly("banana1", "banana2"); |
| } |
| |
| @Test |
| public void testInterfaceSharedObjects() throws Exception { |
| scratch.file( |
| "a/BUILD", |
| "filegroup(", |
| " name='empty')", |
| "filegroup(", |
| " name = 'banana',", |
| " srcs = ['banana1', 'banana2'])", |
| "cc_toolchain(", |
| " name = 'b',", |
| " cpu = 'banana',", |
| " 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_libs = [':empty'],", |
| " static_runtime_libs = [':empty'])"); |
| getAnalysisMock() |
| .ccSupport() |
| .setupCrosstool( |
| mockToolsConfig, |
| CrosstoolConfig.CToolchain.newBuilder() |
| .setSupportsInterfaceSharedObjects(false) |
| .buildPartial()); |
| useConfiguration(); |
| |
| ConfiguredTarget target = getConfiguredTarget("//a:b"); |
| CcToolchainProvider toolchainProvider = |
| (CcToolchainProvider) target.get(ToolchainInfo.PROVIDER); |
| assertThat( |
| CppHelper.useInterfaceSharedObjects( |
| getConfiguration(target).getFragment(CppConfiguration.class), toolchainProvider)) |
| .isFalse(); |
| |
| useConfiguration("--interface_shared_objects"); |
| target = getConfiguredTarget("//a:b"); |
| toolchainProvider = (CcToolchainProvider) target.get(ToolchainInfo.PROVIDER); |
| assertThat( |
| CppHelper.useInterfaceSharedObjects( |
| getConfiguration(target).getFragment(CppConfiguration.class), toolchainProvider)) |
| .isFalse(); |
| |
| getAnalysisMock() |
| .ccSupport() |
| .setupCrosstool( |
| mockToolsConfig, |
| CrosstoolConfig.CToolchain.newBuilder() |
| .setSupportsInterfaceSharedObjects(true) |
| .buildPartial()); |
| useConfiguration(); |
| |
| target = getConfiguredTarget("//a:b"); |
| toolchainProvider = (CcToolchainProvider) target.get(ToolchainInfo.PROVIDER); |
| assertThat( |
| CppHelper.useInterfaceSharedObjects( |
| getConfiguration(target).getFragment(CppConfiguration.class), toolchainProvider)) |
| .isTrue(); |
| |
| useConfiguration("--nointerface_shared_objects"); |
| target = getConfiguredTarget("//a:b"); |
| toolchainProvider = (CcToolchainProvider) target.get(ToolchainInfo.PROVIDER); |
| assertThat( |
| CppHelper.useInterfaceSharedObjects( |
| getConfiguration(target).getFragment(CppConfiguration.class), toolchainProvider)) |
| .isFalse(); |
| } |
| |
| @Test |
| public void testFission() throws Exception { |
| scratch.file( |
| "a/BUILD", |
| "filegroup(", |
| " name='empty')", |
| "filegroup(", |
| " name = 'banana',", |
| " srcs = ['banana1', 'banana2'])", |
| "cc_toolchain(", |
| " name = 'b',", |
| " cpu = 'banana',", |
| " 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_libs = [':empty'],", |
| " static_runtime_libs = [':empty'])"); |
| |
| // Default configuration: disabled. |
| getAnalysisMock() |
| .ccSupport() |
| .setupCrosstool( |
| mockToolsConfig, |
| CrosstoolConfig.CToolchain.newBuilder().setSupportsFission(true).buildPartial()); |
| useConfiguration(); |
| ConfiguredTarget target = getConfiguredTarget("//a:b"); |
| CcToolchainProvider toolchainProvider = |
| (CcToolchainProvider) target.get(ToolchainInfo.PROVIDER); |
| |
| assertThat(toolchainProvider.useFission()).isFalse(); |
| |
| // Mode-specific settings. |
| useConfiguration("-c", "dbg", "--fission=dbg"); |
| target = getConfiguredTarget("//a:b"); |
| toolchainProvider = (CcToolchainProvider) target.get(ToolchainInfo.PROVIDER); |
| assertThat(toolchainProvider.useFission()).isTrue(); |
| |
| useConfiguration("-c", "dbg", "--fission=opt"); |
| target = getConfiguredTarget("//a:b"); |
| toolchainProvider = (CcToolchainProvider) target.get(ToolchainInfo.PROVIDER); |
| assertThat(toolchainProvider.useFission()).isFalse(); |
| |
| useConfiguration("-c", "dbg", "--fission=opt,dbg"); |
| target = getConfiguredTarget("//a:b"); |
| toolchainProvider = (CcToolchainProvider) target.get(ToolchainInfo.PROVIDER); |
| assertThat(toolchainProvider.useFission()).isTrue(); |
| |
| useConfiguration("-c", "fastbuild", "--fission=opt,dbg"); |
| target = getConfiguredTarget("//a:b"); |
| toolchainProvider = (CcToolchainProvider) target.get(ToolchainInfo.PROVIDER); |
| assertThat(toolchainProvider.useFission()).isFalse(); |
| |
| useConfiguration("-c", "fastbuild", "--fission=opt,dbg"); |
| target = getConfiguredTarget("//a:b"); |
| toolchainProvider = (CcToolchainProvider) target.get(ToolchainInfo.PROVIDER); |
| assertThat(toolchainProvider.useFission()).isFalse(); |
| |
| // Universally enabled |
| useConfiguration("-c", "dbg", "--fission=yes"); |
| target = getConfiguredTarget("//a:b"); |
| toolchainProvider = (CcToolchainProvider) target.get(ToolchainInfo.PROVIDER); |
| assertThat(toolchainProvider.useFission()).isTrue(); |
| |
| useConfiguration("-c", "opt", "--fission=yes"); |
| target = getConfiguredTarget("//a:b"); |
| toolchainProvider = (CcToolchainProvider) target.get(ToolchainInfo.PROVIDER); |
| assertThat(toolchainProvider.useFission()).isTrue(); |
| |
| useConfiguration("-c", "fastbuild", "--fission=yes"); |
| target = getConfiguredTarget("//a:b"); |
| toolchainProvider = (CcToolchainProvider) target.get(ToolchainInfo.PROVIDER); |
| assertThat(toolchainProvider.useFission()).isTrue(); |
| |
| // Universally disabled |
| useConfiguration("-c", "dbg", "--fission=no"); |
| target = getConfiguredTarget("//a:b"); |
| toolchainProvider = (CcToolchainProvider) target.get(ToolchainInfo.PROVIDER); |
| assertThat(toolchainProvider.useFission()).isFalse(); |
| |
| useConfiguration("-c", "opt", "--fission=no"); |
| target = getConfiguredTarget("//a:b"); |
| toolchainProvider = (CcToolchainProvider) target.get(ToolchainInfo.PROVIDER); |
| assertThat(toolchainProvider.useFission()).isFalse(); |
| |
| useConfiguration("-c", "fastbuild", "--fission=no"); |
| target = getConfiguredTarget("//a:b"); |
| toolchainProvider = (CcToolchainProvider) target.get(ToolchainInfo.PROVIDER); |
| assertThat(toolchainProvider.useFission()).isFalse(); |
| } |
| |
| @Test |
| public void testPic() throws Exception { |
| scratch.file( |
| "a/BUILD", |
| "filegroup(", |
| " name='empty')", |
| "filegroup(", |
| " name = 'banana',", |
| " srcs = ['banana1', 'banana2'])", |
| "cc_toolchain(", |
| " name = 'b',", |
| " cpu = 'banana',", |
| " 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_libs = [':empty'],", |
| " static_runtime_libs = [':empty'])"); |
| |
| assertThat(usePicForBinariesWithConfiguration("--cpu=piii")).isFalse(); |
| assertThat(usePicForBinariesWithConfiguration("--cpu=piii", "-c", "opt")).isFalse(); |
| assertThat(usePicForBinariesWithConfiguration("--cpu=k8")).isTrue(); |
| assertThat(usePicForBinariesWithConfiguration("--cpu=k8", "-c", "opt")).isFalse(); |
| } |
| |
| private boolean usePicForBinariesWithConfiguration(String... configuration) throws Exception { |
| useConfiguration(configuration); |
| ConfiguredTarget target = getConfiguredTarget("//a:b"); |
| CcToolchainProvider toolchainProvider = |
| (CcToolchainProvider) target.get(ToolchainInfo.PROVIDER); |
| RuleContext ruleContext = getRuleContext(target); |
| return CppHelper.usePicForBinaries(ruleContext, toolchainProvider); |
| } |
| |
| @Test |
| public void testBadDynamicRuntimeLib() throws Exception { |
| scratch.file("a/BUILD", |
| "filegroup(name='dynamic', srcs=['not-an-so', 'so.so'])", |
| "filegroup(name='static', srcs=['not-an-a', 'a.a'])", |
| "cc_toolchain(", |
| " name = 'a',", |
| " module_map = 'map',", |
| " ar_files = 'ar-a',", |
| " as_files = 'as-a',", |
| " cpu = 'cherry',", |
| " compiler_files = 'compile-a',", |
| " dwp_files = 'dwp-a',", |
| " coverage_files = 'gcov-a',", |
| " linker_files = 'link-a',", |
| " strip_files = 'strip-a',", |
| " objcopy_files = 'objcopy-a',", |
| " all_files = 'all-a',", |
| " dynamic_runtime_libs = [':dynamic'],", |
| " static_runtime_libs = [':static'])"); |
| |
| getAnalysisMock().ccSupport().setupCrosstool(mockToolsConfig, |
| CrosstoolConfig.CToolchain.newBuilder() |
| .setSupportsEmbeddedRuntimes(true) |
| .buildPartial()); |
| |
| useConfiguration(); |
| |
| getConfiguredTarget("//a:a"); |
| } |
| |
| @Test |
| public void testTurnOffDynamicLinkWhenLipoBinary() throws Exception { |
| scratch.file( |
| "a/BUILD", |
| "filegroup(", |
| " name='empty')", |
| "filegroup(", |
| " name = 'banana',", |
| " srcs = ['banana1', 'banana2'])", |
| "cc_toolchain(", |
| " name = 'b',", |
| " cpu = 'banana',", |
| " 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_libs = [':empty'],", |
| " static_runtime_libs = [':empty'])"); |
| scratch.file("foo/BUILD", "cc_binary(name='foo')"); |
| |
| useConfiguration("--lipo=binary", "--lipo_context=//foo", "--compilation_mode=opt"); |
| ConfiguredTarget target = getConfiguredTarget("//a:b"); |
| CcToolchainProvider toolchainProvider = |
| (CcToolchainProvider) target.get(ToolchainInfo.PROVIDER); |
| assertThat( |
| CppHelper.getDynamicMode( |
| getConfiguration(target).getFragment(CppConfiguration.class), toolchainProvider)) |
| .isEqualTo(DynamicMode.OFF); |
| |
| useConfiguration("--lipo=off", "--lipo_context=//foo"); |
| target = getConfiguredTarget("//a:b"); |
| toolchainProvider = (CcToolchainProvider) target.get(ToolchainInfo.PROVIDER); |
| assertThat( |
| CppHelper.getDynamicMode( |
| getConfiguration(target).getFragment(CppConfiguration.class), toolchainProvider)) |
| .isEqualTo(DynamicMode.DEFAULT); |
| } |
| |
| @Test |
| public void testDynamicMode() throws Exception { |
| scratch.file( |
| "a/BUILD", |
| "filegroup(", |
| " name='empty')", |
| "filegroup(", |
| " name = 'banana',", |
| " srcs = ['banana1', 'banana2'])", |
| "cc_toolchain(", |
| " name = 'b',", |
| " cpu = 'banana',", |
| " 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_libs = [':empty'],", |
| " static_runtime_libs = [':empty'])"); |
| |
| // Check defaults. |
| useConfiguration(); |
| ConfiguredTarget target = getConfiguredTarget("//a:b"); |
| CcToolchainProvider toolchainProvider = |
| (CcToolchainProvider) target.get(ToolchainInfo.PROVIDER); |
| |
| assertThat( |
| CppHelper.getDynamicMode( |
| getConfiguration(target).getFragment(CppConfiguration.class), toolchainProvider)) |
| .isEqualTo(DynamicMode.DEFAULT); |
| |
| // Test "off" |
| useConfiguration("--dynamic_mode=off"); |
| target = getConfiguredTarget("//a:b"); |
| toolchainProvider = (CcToolchainProvider) target.get(ToolchainInfo.PROVIDER); |
| |
| assertThat( |
| CppHelper.getDynamicMode( |
| getConfiguration(target).getFragment(CppConfiguration.class), toolchainProvider)) |
| .isEqualTo(DynamicMode.OFF); |
| |
| // Test "fully" |
| useConfiguration("--dynamic_mode=fully"); |
| target = getConfiguredTarget("//a:b"); |
| toolchainProvider = (CcToolchainProvider) target.get(ToolchainInfo.PROVIDER); |
| |
| assertThat( |
| CppHelper.getDynamicMode( |
| getConfiguration(target).getFragment(CppConfiguration.class), toolchainProvider)) |
| .isEqualTo(DynamicMode.FULLY); |
| |
| // Check an invalid value for disable_dynamic. |
| try { |
| useConfiguration("--dynamic_mode=very"); |
| fail("OptionsParsingException not thrown."); // COV_NF_LINE |
| } catch (OptionsParsingException e) { |
| assertThat(e) |
| .hasMessageThat() |
| .isEqualTo( |
| "While parsing option --dynamic_mode=very: Not a valid dynamic mode: 'very' " |
| + "(should be off, default or fully)"); |
| } |
| } |
| |
| private void writeDummyCcToolchain() throws IOException { |
| scratch.file( |
| "a/BUILD", |
| "filegroup(", |
| " name='empty')", |
| "filegroup(", |
| " name = 'banana',", |
| " srcs = ['banana1', 'banana2'])", |
| "cc_toolchain(", |
| " name = 'b',", |
| " cpu = 'banana',", |
| " 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_libs = [':empty'],", |
| " static_runtime_libs = [':empty'])"); |
| } |
| |
| // Regression test for bug 2088255: |
| // "StringIndexOutOfBoundsException in BuildConfiguration.<init>()" |
| @Test |
| public void testShortLibcVersion() throws Exception { |
| writeDummyCcToolchain(); |
| |
| getAnalysisMock() |
| .ccSupport() |
| .setupCrosstool( |
| mockToolsConfig, |
| CrosstoolConfig.CToolchain.newBuilder().setTargetLibc("2.3.6").buildPartial()); |
| |
| useConfiguration(); |
| |
| ConfiguredTarget target = getConfiguredTarget("//a:b"); |
| CcToolchainProvider toolchainProvider = |
| (CcToolchainProvider) target.get(ToolchainInfo.PROVIDER); |
| |
| assertThat(toolchainProvider.getTargetLibc()).isEqualTo("2.3.6"); |
| } |
| |
| @Test |
| public void testParamDfDoubleQueueThresholdFactor() throws Exception { |
| writeDummyCcToolchain(); |
| useConfiguration(); |
| |
| scratch.file("lib/BUILD", "cc_library(", " name = 'lib',", " srcs = ['a.cc'],", ")"); |
| |
| ConfiguredTarget lib = getConfiguredTarget("//lib"); |
| CcToolchainProvider toolchain = |
| CppHelper.getToolchainUsingDefaultCcToolchainAttribute(getRuleContext(lib)); |
| |
| assertDoesNotContainSublist( |
| toolchain.getLegacyCompileOptionsWithCopts(), |
| "--param", |
| "df-double-quote-threshold-factor=0"); |
| } |
| |
| @Test |
| public void testMergesDefaultCoptsWithUserProvidedOnes() throws Exception { |
| writeDummyCcToolchain(); |
| scratch.file("lib/BUILD", "cc_library(name = 'lib', srcs = ['a.cc'])"); |
| |
| ConfiguredTarget lib = getConfiguredTarget("//lib"); |
| CcToolchainProvider toolchain = |
| CppHelper.getToolchainUsingDefaultCcToolchainAttribute(getRuleContext(lib)); |
| |
| List<String> expected = new ArrayList<>(); |
| expected.addAll(toolchain.getLegacyCompileOptionsWithCopts()); |
| expected.add("-Dfoo"); |
| |
| useConfiguration("--copt", "-Dfoo"); |
| lib = getConfiguredTarget("//lib"); |
| toolchain = CppHelper.getToolchainUsingDefaultCcToolchainAttribute(getRuleContext(lib)); |
| assertThat(ImmutableList.copyOf(toolchain.getLegacyCompileOptionsWithCopts())) |
| .isEqualTo(ImmutableList.copyOf(expected)); |
| } |
| |
| public void assertInvalidIncludeDirectoryMessage(String entry, String messageRegex) |
| throws Exception { |
| try { |
| scratch.overwriteFile( |
| "a/BUILD", |
| "filegroup(", |
| " name='empty')", |
| "cc_toolchain(", |
| " name = 'b',", |
| " cpu = 'k8',", |
| " 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_libs = [':empty'],", |
| " static_runtime_libs = [':empty'])"); |
| |
| getAnalysisMock() |
| .ccSupport() |
| .setupCrosstool( |
| mockToolsConfig, |
| CrosstoolConfig.CToolchain.newBuilder() |
| .addCxxBuiltinIncludeDirectory(entry) |
| .buildPartial()); |
| |
| useConfiguration(); |
| |
| ConfiguredTarget target = getConfiguredTarget("//a:b"); |
| CcToolchainProvider toolchainProvider = |
| (CcToolchainProvider) target.get(ToolchainInfo.PROVIDER); |
| // Must call this function to actually see if there's an error with the directories. |
| toolchainProvider.getBuiltInIncludeDirectories(); |
| |
| fail("C++ configuration creation succeeded unexpectedly"); |
| } catch (AssertionError e) { |
| assertThat(e).hasMessageThat().containsMatch(messageRegex); |
| } |
| } |
| |
| @Test |
| public void testInvalidIncludeDirectory() throws Exception { |
| assertInvalidIncludeDirectoryMessage("%package(//a", "has an unrecognized %prefix%"); |
| assertInvalidIncludeDirectoryMessage("%package(//a@@a)%", "The package '//a@@a' is not valid"); |
| assertInvalidIncludeDirectoryMessage( |
| "%package(//a)%foo", "The path in the package.*is not valid"); |
| assertInvalidIncludeDirectoryMessage( |
| "%package(//a)%/../bar", "The include path.*is not normalized"); |
| } |
| |
| @Test |
| public void testModuleMapAttribute() throws Exception { |
| scratchConfiguredTarget("modules/map", "c", |
| "cc_toolchain(", |
| " name = 'c',", |
| " module_map = 'map',", |
| " cpu = 'cherry',", |
| " 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_libs = ['dynamic-runtime-libs-cherry'],", |
| " static_runtime_libs = ['static-runtime-libs-cherry'])"); |
| } |
| |
| @Test |
| public void testModuleMapAttributeOptional() throws Exception { |
| scratchConfiguredTarget("modules/map", "c", |
| "cc_toolchain(", |
| " name = 'c',", |
| " cpu = 'cherry',", |
| " 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_libs = ['dynamic-runtime-libs-cherry'],", |
| " static_runtime_libs = ['static-runtime-libs-cherry'])"); |
| } |
| |
| @Test |
| public void testFailWithMultipleModuleMaps() throws Exception { |
| checkError("modules/multiple", "c", "expected a single artifact", |
| "filegroup(name = 'multiple-maps', srcs = ['a.cppmap', 'b.cppmap'])", |
| "cc_toolchain(", |
| " name = 'c',", |
| " module_map = ':multiple-maps',", |
| " cpu = 'cherry',", |
| " 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_libs = ['dynamic-runtime-libs-cherry'],", |
| " static_runtime_libs = ['static-runtime-libs-cherry'])"); |
| } |
| |
| @Test |
| public void testToolchainAlias() throws Exception { |
| ConfiguredTarget reference = scratchConfiguredTarget("a", "ref", |
| "cc_toolchain_alias(name='ref')"); |
| assertThat(reference.get(ToolchainInfo.PROVIDER.getKey())).isNotNull(); |
| } |
| |
| @Test |
| public void testFdoOptimizeInvalidUseGeneratedArtifact() throws Exception { |
| reporter.removeHandler(failFastHandler); |
| scratch.file( |
| "a/BUILD", |
| "filegroup(", |
| " name='empty')", |
| "filegroup(", |
| " name = 'banana',", |
| " srcs = ['banana1', 'banana2'])", |
| "cc_toolchain(", |
| " name = 'b',", |
| " cpu = 'banana',", |
| " 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_libs = [':empty'],", |
| " static_runtime_libs = [':empty'])", |
| "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"); |
| } |
| |
| @Test |
| public void testFdoOptimizeUnexpectedExtension() throws Exception { |
| reporter.removeHandler(failFastHandler); |
| scratch.file( |
| "a/BUILD", |
| "filegroup(", |
| " name='empty')", |
| "filegroup(", |
| " name = 'banana',", |
| " srcs = ['banana1', 'banana2'])", |
| "cc_toolchain(", |
| " name = 'b',", |
| " cpu = 'banana',", |
| " 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_libs = [':empty'],", |
| " static_runtime_libs = [':empty'])", |
| "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", |
| "filegroup(", |
| " name='empty')", |
| "filegroup(", |
| " name = 'banana',", |
| " srcs = ['banana1', 'banana2'])", |
| "cc_toolchain(", |
| " name = 'b',", |
| " cpu = 'banana',", |
| " 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_libs = [':empty'],", |
| " static_runtime_libs = [':empty'])", |
| "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"); |
| } |
| |
| @Test |
| public void testInlineCtoolchain_withoutToolchainResolution() throws Exception { |
| scratch.file( |
| "a/BUILD", |
| "filegroup(", |
| " name='empty')", |
| "cc_toolchain(", |
| " name = 'b',", |
| " cpu = 'banana',", |
| " all_files = ':empty',", |
| " ar_files = ':empty',", |
| " as_files = ':empty',", |
| " compiler_files = ':empty',", |
| " dwp_files = ':empty',", |
| " linker_files = ':empty',", |
| " strip_files = ':empty',", |
| " objcopy_files = ':empty',", |
| " dynamic_runtime_libs = [':empty'],", |
| " static_runtime_libs = [':empty'],", |
| " proto=\"\"\"", |
| " toolchain_identifier: \"banana\"", |
| " abi_version: \"banana\"", |
| " abi_libc_version: \"banana\"", |
| " compiler: \"banana\"", |
| " host_system_name: \"banana\"", |
| " target_system_name: \"banana\"", |
| " target_cpu: \"banana\"", |
| " target_libc: \"banana\"", |
| " \"\"\")"); |
| |
| getAnalysisMock() |
| .ccSupport() |
| .setupCrosstool(mockToolsConfig, CrosstoolConfig.CToolchain.newBuilder() |
| .setAbiVersion("orange") |
| .buildPartial()); |
| |
| useConfiguration(); |
| |
| ConfiguredTarget target = getConfiguredTarget("//a:b"); |
| CcToolchainProvider toolchainProvider = |
| (CcToolchainProvider) target.get(ToolchainInfo.PROVIDER); |
| |
| // Without toolchain resolution, this should get the toolchain from the CROSSTOOL, not the |
| // static version in the target. |
| assertThat(toolchainProvider.getAbi()).isEqualTo("orange"); |
| } |
| |
| @Test |
| public void testInlineCtoolchain_withToolchainResolution() throws Exception { |
| scratch.file( |
| "a/BUILD", |
| "filegroup(", |
| " name='empty')", |
| "cc_toolchain(", |
| " name = 'b',", |
| " cpu = 'banana',", |
| " all_files = ':empty',", |
| " ar_files = ':empty',", |
| " as_files = ':empty',", |
| " compiler_files = ':empty',", |
| " dwp_files = ':empty',", |
| " linker_files = ':empty',", |
| " strip_files = ':empty',", |
| " objcopy_files = ':empty',", |
| " dynamic_runtime_libs = [':empty'],", |
| " static_runtime_libs = [':empty'],", |
| " proto=\"\"\"", |
| " toolchain_identifier: \"banana\"", |
| " abi_version: \"banana\"", |
| " abi_libc_version: \"banana\"", |
| " compiler: \"banana\"", |
| " host_system_name: \"banana\"", |
| " target_system_name: \"banana\"", |
| " target_cpu: \"banana\"", |
| " target_libc: \"banana\"", |
| " \"\"\")"); |
| |
| getAnalysisMock() |
| .ccSupport() |
| .setupCrosstool(mockToolsConfig, CrosstoolConfig.CToolchain.newBuilder() |
| .setAbiVersion("orange") |
| .buildPartial()); |
| |
| useConfiguration("--enabled_toolchain_types=" + CPP_TOOLCHAIN_TYPE); |
| |
| ConfiguredTarget target = getConfiguredTarget("//a:b"); |
| CcToolchainProvider toolchainProvider = |
| (CcToolchainProvider) target.get(ToolchainInfo.PROVIDER); |
| assertThat(toolchainProvider.getAbi()).isEqualTo("banana"); |
| } |
| |
| @Test |
| public void testSupportsDynamicLinkerCheckFeatures() throws Exception { |
| writeDummyCcToolchain(); |
| |
| getAnalysisMock() |
| .ccSupport() |
| .setupCrosstool(mockToolsConfig, MockCcSupport.DYNAMIC_LINKING_MODE_FEATURE); |
| |
| // To make sure the toolchain doesn't define linking_mode_flags { mode: DYNAMIC } as that would |
| // also result in supportsDynamicLinker returning true |
| useConfiguration("--compiler=compiler_no_dyn_linker"); |
| |
| ConfiguredTarget target = getConfiguredTarget("//a:b"); |
| CcToolchainProvider toolchainProvider = |
| (CcToolchainProvider) target.get(ToolchainInfo.PROVIDER); |
| |
| assertThat(toolchainProvider.supportsDynamicLinker()).isTrue(); |
| } |
| |
| // Tests CcCommon::enableStaticLinkCppRuntimesFeature when supports_embedded_runtimes is not |
| // present at all in the toolchain. |
| @Test |
| public void testStaticLinkCppRuntimesSetViaSupportsEmbeddedRuntimesUnset() throws Exception { |
| writeDummyCcToolchain(); |
| getAnalysisMock().ccSupport().setupCrosstool(mockToolsConfig); |
| useConfiguration(); |
| ConfiguredTarget target = getConfiguredTarget("//a:b"); |
| CcToolchainProvider toolchainProvider = |
| (CcToolchainProvider) target.get(ToolchainInfo.PROVIDER); |
| FeatureConfiguration featureConfiguration = |
| CcCommon.configureFeaturesOrReportRuleError(getRuleContext(target), toolchainProvider); |
| assertThat(toolchainProvider.supportsEmbeddedRuntimes()) |
| .isEqualTo(featureConfiguration.isEnabled(CppRuleClasses.STATIC_LINK_CPP_RUNTIMES)); |
| } |
| |
| // Tests CcCommon::enableStaticLinkCppRuntimesFeature when supports_embedded_runtimes is false |
| // in the toolchain. |
| @Test |
| public void testStaticLinkCppRuntimesSetViaSupportsEmbeddedRuntimesFalse() throws Exception { |
| writeDummyCcToolchain(); |
| getAnalysisMock().ccSupport().setupCrosstoolWithEmbeddedRuntimes(mockToolsConfig); |
| useConfiguration(); |
| ConfiguredTarget target = getConfiguredTarget("//a:b"); |
| CcToolchainProvider toolchainProvider = |
| (CcToolchainProvider) target.get(ToolchainInfo.PROVIDER); |
| FeatureConfiguration featureConfiguration = |
| CcCommon.configureFeaturesOrReportRuleError(getRuleContext(target), toolchainProvider); |
| assertThat(toolchainProvider.supportsEmbeddedRuntimes()) |
| .isEqualTo(featureConfiguration.isEnabled(CppRuleClasses.STATIC_LINK_CPP_RUNTIMES)); |
| } |
| |
| private FeatureConfiguration configureFeaturesForStaticLinkCppRuntimesTest( |
| String partialToolchain, String configurationToUse) throws Exception { |
| writeDummyCcToolchain(); |
| CToolchain.Builder toolchainBuilder = CToolchain.newBuilder(); |
| TextFormat.merge(partialToolchain, toolchainBuilder); |
| getAnalysisMock() |
| .ccSupport() |
| .setupCrosstool( |
| mockToolsConfig, |
| /* addEmbeddedRuntimes= */ true, |
| /* addModuleMap= */ false, |
| /* staticRuntimesLabel= */ null, |
| /* dynamicRuntimesLabel= */ null, |
| toolchainBuilder.buildPartial()); |
| useConfiguration(configurationToUse); |
| ConfiguredTarget target = getConfiguredTarget("//a:b"); |
| CcToolchainProvider toolchainProvider = |
| (CcToolchainProvider) target.get(ToolchainInfo.PROVIDER); |
| return CcCommon.configureFeaturesOrReportRuleError(getRuleContext(target), toolchainProvider); |
| } |
| |
| // Tests CcCommon::enableStaticLinkCppRuntimesFeature when supports_embedded_runtimes is true in |
| // the toolchain and the feature is not present at all. |
| @Test |
| public void testSupportsEmbeddedRuntimesNoFeatureAtAll() throws Exception { |
| FeatureConfiguration featureConfiguration = |
| configureFeaturesForStaticLinkCppRuntimesTest("supports_embedded_runtimes: true", ""); |
| assertThat(featureConfiguration.isEnabled(CppRuleClasses.STATIC_LINK_CPP_RUNTIMES)).isTrue(); |
| } |
| |
| // Tests CcCommon::enableStaticLinkCppRuntimesFeature when supports_embedded_runtimes is true in |
| // the toolchain and the feature is enabled. |
| @Test |
| public void testSupportsEmbeddedRuntimesFeatureEnabled() throws Exception { |
| FeatureConfiguration featureConfiguration = |
| configureFeaturesForStaticLinkCppRuntimesTest( |
| "supports_embedded_runtimes: true", "--features=static_link_cpp_runtimes"); |
| assertThat(featureConfiguration.isEnabled(CppRuleClasses.STATIC_LINK_CPP_RUNTIMES)).isTrue(); |
| } |
| |
| // Tests CcCommon::enableStaticLinkCppRuntimesFeature when supports_embedded_runtimes is true in |
| // the toolchain and the feature is disabled. |
| @Test |
| public void testStaticLinkCppRuntimesOverridesSupportsEmbeddedRuntimes() throws Exception { |
| FeatureConfiguration featureConfiguration = |
| configureFeaturesForStaticLinkCppRuntimesTest( |
| "supports_embedded_runtimes: true feature { name: 'static_link_cpp_runtimes' }", |
| "--features=-static_link_cpp_runtimes"); |
| assertThat(featureConfiguration.isEnabled(CppRuleClasses.STATIC_LINK_CPP_RUNTIMES)).isFalse(); |
| } |
| } |