From ca0b81ab54f8d7dad04f805855cdaf856c3ecb4f Mon Sep 17 00:00:00 2001 From: rosica Date: Wed, 13 Jun 2018 07:36:46 -0700 Subject: [PATCH] Add "toolchain-identifier" attribute to cc_toolchain rule Currently the selection of C++ toolchain configuration depends on 2 different things: 1. CROSSTOOL file: a proto text file that contains multiple CrosstoolConfig.CToolchain messages, out of which we want to select the appropriate CToolchain; 2. cc_toolchain_suite rule, specified by --crosstool_top option: this rule contains "toolchains" map attribute. The map's keys are of type |, or just , and the values are labels of cc_toolchain rules (which contain additional C++ information). If there is an entry in cc_toolchain_suite.toolchains that corresponds to the --cpu and --compiler options, we use it, otherwise we loop through all the CToolchains in the CROSSTOOL file, select the one that corresponds to the --cpu and --compiler options, and then get the cc_toolchain label from cc_toolchain_suite.toolchains[toolchain.targetCpu|toolchain.compiler]. In both cases we read the CROSSTOOL file and pass all its information forward, to be used in creation of CppConfiguration and CcToolchainProvider creation. As part of the efforts of rewriting CROSSTOOL in Skylark, we need to make obtaining the cc_toolchain label independent of the CROSSTOOL file and toolchain selection. As a step towards that goal, we add a new "toolchain_identifier" attribute to cc_toolchain, which uniquely identifies a CToolchain in the CROSSTOOL file. Now the process of getting the CToolchain goes as follows: Check for existence of cc_toolchain_suite.toolchains[|], if --compiler is specified, otherwise check for cc_toolchain_suite.toolchains[]. 1. if a value is found, load the cc_toolchain rule and look for the toolchain_identifier attribute. 1.a if the attribute exists, loop through all the CToolchains in CROSSTOOL and select the one with the matching toolchain identifier. 1.b otherwise fall back to selecting the CToolchain from CROSSTOOL by matching the --cpu and --compiler values. 2. If a value is not found, select the CToolchain from CROSSTOOL by matching the --cpu and --compiler values, and construct the key as follows: |. In the future we will get rid of 2. by making sure that cc_toolchain_suite.toolchains[|] and cc_toolchain_suite.toolchains[] are always defined. 1.b will be removed by making the cc_toolchain.toolchain_identifier attribute mandatory After this deriving the cc_toolchain label will be independent of the CROSSTOOL file 1.a will ultimately be replaced by an attribute that points to a skylark_crosstool rule, that will contain all the information that CROSSTOOL contains, allowing us to remove CROSSTOOL altogether. Work towards issue #5380 RELNOTES: None. PiperOrigin-RevId: 200388550 --- .../build/lib/rules/cpp/CcToolchainRule.java | 5 +- .../build/lib/rules/cpp/CppConfiguration.java | 29 ++ .../lib/rules/cpp/CppConfigurationLoader.java | 35 +- .../cpp/CrosstoolConfigurationLoader.java | 59 +++- .../lib/rules/cpp/CcToolchainSuiteTest.java | 312 ++++++++++++++++++ 5 files changed, 424 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainRule.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainRule.java index a22c7a3f327d15..f5ca99384c657a 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainRule.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainRule.java @@ -176,7 +176,6 @@ public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment env) // TODO(b/78578234): Make this the default and remove the late-bound versions. .add(attr("libc_top", LABEL).allowedFileTypes()) .add(attr(LIBC_TOP_ATTR, LABEL).value(LIBC_TOP_VALUE)) - .add(attr(FDO_OPTIMIZE_ATTR, LABEL).singleArtifact().value(FDO_OPTIMIZE_VALUE)) .add( attr(FDO_PROFILE_ATTR, LABEL) @@ -194,6 +193,10 @@ public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment env) .value(CppRuleClasses.LIPO_CONTEXT_COLLECTOR) .skipPrereqValidatorCheck()) .add(attr("proto", Type.STRING)) + .add( + attr("toolchain_identifier", Type.STRING) + .nonconfigurable("Used in configuration creation") + .value("")) .build(); } diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java index 317d52db40b630..73d6c538c10cc4 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java @@ -55,6 +55,35 @@ * This class represents the C/C++ parts of the {@link BuildConfiguration}, including the host * architecture, target architecture, compiler version, and a standard library version. It has * information about the tools locations and the flags required for compiling. + * + *

Before {@link CppConfiguration} is created, two things need to be done: + * + *

    + *
  1. choosing a {@link CcToolchainRule} label from {@code toolchains} map attribute of {@link + * CcToolchainSuiteRule}. + *
  2. selection of a {@link + * com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.CToolchain} from the + * CROSSTOOL file. + *
+ * + *

The process goes as follows: + * + *

Check for existence of {@link CcToolchainSuiteRule}.toolchains[|], if + * --compiler is specified, otherwise check for {@link CcToolchainSuiteRule}.toolchains[]. + * + *

    + *
  • if a value is found, load the {@link CcToolchainRule} rule and look for the {@code + * toolchain_identifier} attribute. + *
  • + *
      + *
    • if the attribute exists, loop through all the {@code CToolchain}s in CROSSTOOL and + * select the one with the matching toolchain identifier. + *
    • otherwise fall back to selecting the CToolchain from CROSSTOOL by matching the --cpu + * and --compiler values. + *
    + *
  • If a value is not found, select the CToolchain from CROSSTOOL by matching the --cpu and + * --compiler values, and construct the key as follows: |. + *
*/ @AutoCodec @Immutable diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfigurationLoader.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfigurationLoader.java index e20e3a0d4c8088..48ec524c0b0973 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfigurationLoader.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfigurationLoader.java @@ -32,6 +32,7 @@ import com.google.devtools.build.lib.packages.NonconfigurableAttributeMapper; import com.google.devtools.build.lib.packages.Rule; import com.google.devtools.build.lib.packages.Target; +import com.google.devtools.build.lib.syntax.Type; import com.google.devtools.build.lib.vfs.FileSystemUtils; import com.google.devtools.build.lib.vfs.PathFragment; import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig; @@ -142,9 +143,6 @@ protected CppConfigurationParameters createParameters( if (file == null) { return null; } - CrosstoolConfig.CToolchain toolchain = - CrosstoolConfigurationLoader.selectToolchain( - file.getProto(), options, cpuTransformer.getTransformer()); PathFragment fdoPath = null; Label fdoProfileLabel = null; @@ -168,18 +166,17 @@ protected CppConfigurationParameters createParameters( Label ccToolchainLabel; Target crosstoolTop; - + CrosstoolConfig.CToolchain toolchain = null; try { crosstoolTop = env.getTarget(crosstoolTopLabel); } catch (NoSuchThingException e) { throw new IllegalStateException(e); // Should have been found out during redirect chasing } + String desiredCpu = cpuTransformer.getTransformer().apply(options.get(Options.class).cpu); if (crosstoolTop instanceof Rule && ((Rule) crosstoolTop).getRuleClass().equals("cc_toolchain_suite")) { Rule ccToolchainSuite = (Rule) crosstoolTop; - - String desiredCpu = cpuTransformer.getTransformer().apply(options.get(Options.class).cpu); String key = desiredCpu + (cppOptions.cppCompiler == null ? "" : ("|" + cppOptions.cppCompiler)); Map toolchains = @@ -187,13 +184,21 @@ protected CppConfigurationParameters createParameters( .get("toolchains", BuildType.LABEL_DICT_UNARY); ccToolchainLabel = toolchains.get(key); if (ccToolchainLabel == null) { + // If the cc_toolchain_suite does not contain entry for --cpu|--compiler (or only --cpu if + // --compiler is not present) we select the toolchain by looping through all the toolchains + // in the CROSSTOOL file and selecting the one that matches --cpu (and --compiler, if + // present). Then we use the toolchain.target_cpu|toolchain.compiler key to get the + // cc_toolchain label. + toolchain = + CrosstoolConfigurationLoader.selectToolchain( + file.getProto(), options, cpuTransformer.getTransformer()); ccToolchainLabel = toolchains.get(toolchain.getTargetCpu() + "|" + toolchain.getCompiler()); } if (ccToolchainLabel == null) { String errorMessage = String.format( "cc_toolchain_suite '%s' does not contain a toolchain for CPU '%s'", - crosstoolTopLabel, toolchain.getTargetCpu()); + crosstoolTopLabel, desiredCpu); if (cppOptions.cppCompiler != null) { errorMessage = errorMessage + " and compiler " + cppOptions.cppCompiler; } @@ -221,6 +226,22 @@ protected CppConfigurationParameters createParameters( "The label '%s' is not a cc_toolchain rule", ccToolchainLabel)); } + if (toolchain == null) { + // If cc_toolchain_suite contains an entry for the given --cpu and --compiler options, we + // select the toolchain by its identifier if "toolchain_identifier" attribute is present. + // Otherwise, we fall back to going through the CROSSTOOL file to select the toolchain using + // the legacy selection mechanism. + String identifier = + NonconfigurableAttributeMapper.of((Rule) ccToolchain) + .get("toolchain_identifier", Type.STRING); + toolchain = + identifier.isEmpty() + ? CrosstoolConfigurationLoader.selectToolchain( + file.getProto(), options, cpuTransformer.getTransformer()) + : CrosstoolConfigurationLoader.getToolchainByIdentifier( + file.getProto(), identifier, desiredCpu, cppOptions.cppCompiler); + } + Label sysrootLabel = getSysrootLabel(toolchain, cppOptions.libcTopLabel); return new CppConfigurationParameters( diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CrosstoolConfigurationLoader.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CrosstoolConfigurationLoader.java index caed2d37b6ecb7..a475aeb1a2f2e3 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CrosstoolConfigurationLoader.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CrosstoolConfigurationLoader.java @@ -18,6 +18,7 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; +import com.google.common.base.Strings; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.io.BaseEncoding; @@ -375,7 +376,7 @@ public static CrosstoolConfig.CToolchain selectToolchain( + cpuBuilder + "]"); } - checkToolChain(selectedIdentifier, desiredCpu); + checkToolchain(selectedIdentifier, desiredCpu); for (CrosstoolConfig.CToolchain toolchain : release.getToolchainList()) { if (toolchain.getToolchainIdentifier().equals(selectedIdentifier)) { @@ -406,15 +407,14 @@ private static void describeToolchainList(StringBuilder message, } /** - * Makes sure that {@code selectedIdentifier} is a valid identifier for a toolchain, - * i.e. it starts with a letter or an underscore and continues with only dots, dashes, - * spaces, letters, digits or underscores (i.e. matches the following regular expression: - * "[a-zA-Z_][\.\- \w]*"). + * Makes sure that {@code selectedIdentifier} is a valid identifier for a toolchain, i.e. it + * starts with a letter or an underscore and continues with only dots, dashes, spaces, letters, + * digits or underscores (i.e. matches the following regular expression: "[a-zA-Z_][\.\- \w]*"). * - * @throws InvalidConfigurationException if selectedIdentifier does not match the - * aforementioned regular expression. + * @throws InvalidConfigurationException if selectedIdentifier does not match the aforementioned + * regular expression. */ - private static void checkToolChain(String selectedIdentifier, String cpu) + private static void checkToolchain(String selectedIdentifier, String cpu) throws InvalidConfigurationException { // If you update this regex, please do so in the javadoc comment too, and also in the // crosstool_config.proto file. @@ -438,4 +438,47 @@ public static CrosstoolConfig.CrosstoolRelease getCrosstoolReleaseProto( selectToolchain(file.getProto(), options, cpuTransformer); return file.getProto(); } + + /** + * Selects a crosstool toolchain based on the toolchain identifier. + * + * @throws InvalidConfigurationException if no matching toolchain can be found, if multiple + * toolchains with the same identifier are found, or if the target_cpu or compiler of the + * selected toolchain are not the same as --cpu and --compiler options. + */ + public static CrosstoolConfig.CToolchain getToolchainByIdentifier( + CrosstoolConfig.CrosstoolRelease proto, + String toolchainIdentifier, + String cpu, + @Nullable String compiler) + throws InvalidConfigurationException { + checkToolchain(toolchainIdentifier, cpu); + CrosstoolConfig.CToolchain selectedToolchain = null; + for (CrosstoolConfig.CToolchain toolchain : proto.getToolchainList()) { + if (toolchain.getToolchainIdentifier().equals(toolchainIdentifier)) { + if (selectedToolchain != null) { + throw new InvalidConfigurationException( + String.format("Multiple toolchains with '%s' identifier", toolchainIdentifier)); + } + selectedToolchain = toolchain; + } + } + if (selectedToolchain == null) { + throw new InvalidConfigurationException( + String.format("Toolchain identifier '%s' was not found", toolchainIdentifier)); + } + if ((compiler != null && !selectedToolchain.getCompiler().equals(compiler)) + || !selectedToolchain.getTargetCpu().equals(cpu)) { + throw new InvalidConfigurationException( + String.format( + "The selected toolchain's cpu and compiler must match the command line options:\n" + + " --cpu: %s, toolchain.target_cpu: %s\n" + + " --compiler: %s, toolchain.compiler: %s", + cpu, + selectedToolchain.getTargetCpu(), + Strings.nullToEmpty(compiler), + selectedToolchain.getCompiler())); + } + return selectedToolchain; + } } diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/CcToolchainSuiteTest.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/CcToolchainSuiteTest.java index f6925f2d855d32..869601122dd020 100644 --- a/src/test/java/com/google/devtools/build/lib/rules/cpp/CcToolchainSuiteTest.java +++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/CcToolchainSuiteTest.java @@ -380,4 +380,316 @@ public void testCcToolchainLabelFromAttributes() throws Exception { .contains("The label '//cc:invalid-label' is not a cc_toolchain rule"); } } + + @Test + public void testCcToolchainFromToolchainIdentifier() throws Exception { + scratch.file( + "cc/BUILD", + "filegroup(name='empty')", + "filegroup(name='everything')", + "TOOLCHAIN_NAMES = [", + " 'k8',", + " 'ppc',", + " 'darwin',", + " 'windows']", + "[cc_toolchain(", + " name = NAME,", + " 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'],", + ") for NAME in TOOLCHAIN_NAMES]", + "[cc_toolchain(", + " name = NAME + '-override',", + " 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'],", + " toolchain_identifier = NAME + '-from-attribute'", + ") for NAME in TOOLCHAIN_NAMES]", + "cc_toolchain(", + " name = 'invalid',", + " 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'],", + " toolchain_identifier = 'invalid-toolchain',", + ")", + "cc_toolchain(", + " name = 'duplicate',", + " 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'],", + " toolchain_identifier = 'duplicate-toolchain',", + ")", + "cc_toolchain(", + " name = 'wrong-compiler',", + " 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'],", + " toolchain_identifier = 'wrong-compiler-toolchain',", + ")", + "cc_toolchain_suite(", + " name = 'suite',", + " toolchains = {", + " 'k8': ':k8-override',", + " 'k8|compiler': ':k8',", + " 'k8|compiler-from-attribute': ':k8-override',", + " 'ppc|compiler': ':invalid',", + " 'ppc|compiler-from-attribute': ':ppc-override',", + " 'k8|compiler1': ':duplicate',", + " 'k8|right-compiler': ':wrong-compiler',", + " 'x64_windows' : ':windows',", + " 'x64_windows|compiler' : ':windows',", + " 'x64_windows|compiler-from-attribute' : ':windows',", + " 'x64_windows|compiler1' : ':windows',", + " 'x64_windows|right-compiler' : ':windows',", + " 'darwin' : ':darwin',", + " 'darwin|compiler' : ':darwin',", + " 'darwin|compiler-from-attribute' : ':darwin',", + " 'darwin|compiler1' : ':darwin',", + " 'darwin|right-compiler' : ':darwin',", + " },", + " proto = \"\"\"", + "major_version: 'v1'", + "minor_version: '0'", + "default_target_cpu: 'k8'", + "default_toolchain {", + " cpu: 'k8'", + " toolchain_identifier: 'k8-toolchain-identifier'", + "}", + "default_toolchain {", + " cpu: 'ppc'", + " toolchain_identifier: 'ppc-toolchain-identifier'", + "}", + "default_toolchain {", + " cpu: 'darwin'", + " toolchain_identifier: 'darwin-toolchain-identifier'", + "}", + "default_toolchain {", + " cpu: 'x64_windows'", + " toolchain_identifier: 'windows-toolchain-identifier'", + "}", + "toolchain {", + " compiler: 'compiler'", + " target_cpu: 'k8'", + " toolchain_identifier: 'k8-toolchain-identifier'", + " host_system_name: 'linux'", + " target_system_name: 'linux'", + " abi_version: 'cpu-abi'", + " abi_libc_version: ''", + " target_libc: 'local'", + " builtin_sysroot: 'sysroot'", + " default_grte_top: '//cc:grtetop'", + "}", + "toolchain {", + " compiler: 'compiler-from-attribute'", + " target_cpu: 'k8'", + " toolchain_identifier: 'k8-from-attribute'", + " host_system_name: 'linux'", + " target_system_name: 'linux'", + " abi_version: 'cpu-abi'", + " abi_libc_version: ''", + " target_libc: 'local'", + " builtin_sysroot: 'sysroot'", + " default_grte_top: '//cc:grtetop'", + "}", + "toolchain {", + " compiler: 'compiler'", + " target_cpu: 'ppc'", + " toolchain_identifier: 'ppc-toolchain-identifier'", + " host_system_name: 'linux'", + " target_system_name: 'linux'", + " abi_version: 'cpu-abi'", + " abi_libc_version: ''", + " target_libc: 'local'", + " builtin_sysroot: 'sysroot'", + " default_grte_top: '//cc:grtetop'", + "}", + "toolchain {", + " compiler: 'compiler-from-attribute'", + " target_cpu: 'ppc'", + " toolchain_identifier: 'ppc-from-attribute'", + " host_system_name: 'linux'", + " target_system_name: 'linux'", + " abi_version: 'cpu-abi'", + " abi_libc_version: ''", + " target_libc: 'local'", + " builtin_sysroot: 'sysroot'", + " default_grte_top: '//cc:grtetop'", + "}", + "toolchain {", + " compiler: 'compiler'", + " target_cpu: 'darwin'", + " toolchain_identifier: 'darwin-toolchain-identifier'", + " host_system_name: 'linux'", + " target_system_name: 'linux'", + " abi_version: ''", + " abi_libc_version: ''", + " target_libc: ''", + " builtin_sysroot: 'sysroot'", + " default_grte_top: '//cc:grtetop'", + "}", + "toolchain {", + " compiler: 'compiler-from-attribute'", + " target_cpu: 'darwin'", + " toolchain_identifier: 'darwin-from-attribute'", + " host_system_name: 'linux'", + " target_system_name: 'linux'", + " abi_version: 'cpu-abi'", + " abi_libc_version: ''", + " target_libc: 'local'", + " builtin_sysroot: 'sysroot'", + " default_grte_top: '//cc:grtetop'", + "}", + "toolchain {", + " compiler: 'compiler'", + " target_cpu: 'x64_windows'", + " toolchain_identifier: 'windows-toolchain-identifier'", + " host_system_name: 'windows'", + " target_system_name: 'windows'", + " abi_version: ''", + " abi_libc_version: ''", + " target_libc: ''", + " builtin_sysroot: 'sysroot'", + " default_grte_top: '//cc:grtetop'", + "}", + "toolchain {", + " compiler: 'compiler-from-attribute'", + " target_cpu: 'x64_windows'", + " toolchain_identifier: 'windows-from-attribute'", + " host_system_name: 'linux'", + " target_system_name: 'linux'", + " abi_version: 'cpu-abi'", + " abi_libc_version: ''", + " target_libc: 'local'", + " builtin_sysroot: 'sysroot'", + " default_grte_top: '//cc:grtetop'", + "}", + "toolchain {", + " compiler: 'compiler1'", + " target_cpu: 'k8'", + " toolchain_identifier: 'duplicate-toolchain'", + " host_system_name: 'linux'", + " target_system_name: 'linux'", + " abi_version: 'cpu-abi'", + " abi_libc_version: ''", + " target_libc: 'local'", + " builtin_sysroot: 'sysroot'", + " default_grte_top: '//cc:grtetop'", + "}", + "toolchain {", + " compiler: 'compiler2'", + " target_cpu: 'k8'", + " toolchain_identifier: 'duplicate-toolchain'", + " host_system_name: 'linux'", + " target_system_name: 'linux'", + " abi_version: 'cpu-abi'", + " abi_libc_version: ''", + " target_libc: 'local'", + " builtin_sysroot: 'sysroot'", + " default_grte_top: '//cc:grtetop'", + "}", + "toolchain {", + " compiler: 'wrong-compiler'", + " target_cpu: 'k8'", + " toolchain_identifier: 'wrong-compiler-toolchain'", + " host_system_name: 'linux'", + " target_system_name: 'linux'", + " abi_version: 'cpu-abi'", + " abi_libc_version: ''", + " target_libc: 'local'", + " builtin_sysroot: 'sysroot'", + " default_grte_top: '//cc:grtetop'", + "}", + "\"\"\"", + ")"); + + scratch.file("a/BUILD", "cc_binary(name='b', srcs=['b.cc'])"); + + useConfiguration("--crosstool_top=//cc:suite", "--cpu=k8"); + ConfiguredTarget c = getConfiguredTarget("//a:b"); + CppConfiguration config = getConfiguration(c).getFragment(CppConfiguration.class); + assertThat(config.getToolchainIdentifier()).isEqualTo("k8-from-attribute"); + + useConfiguration("--crosstool_top=//cc:suite", "--cpu=ppc"); + c = getConfiguredTarget("//a:b"); + config = getConfiguration(c).getFragment(CppConfiguration.class); + assertThat(config.getToolchainIdentifier()).isEqualTo("ppc-toolchain-identifier"); + + useConfiguration( + "--crosstool_top=//cc:suite", "--compiler=compiler-from-attribute", "--cpu=ppc"); + config = getConfiguration(getConfiguredTarget("//a:b")).getFragment(CppConfiguration.class); + assertThat(config.getToolchainIdentifier()).isEqualTo("ppc-from-attribute"); + + try { + useConfiguration("--crosstool_top=//cc:suite", "--compiler=compiler", "--cpu=ppc"); + getConfiguration(getConfiguredTarget("//a:b")).getFragment(CppConfiguration.class); + fail("expected failure because ppc|compiler entry points to an invalid toolchain identifier"); + } catch (InvalidConfigurationException e) { + assertThat(e) + .hasMessageThat() + .contains("Toolchain identifier 'invalid-toolchain' was not found"); + } + + try { + useConfiguration("--crosstool_top=//cc:suite", "--compiler=compiler1", "--cpu=k8"); + getConfiguration(getConfiguredTarget("//a:b")).getFragment(CppConfiguration.class); + fail("expected failure because of duplicate toolchain identifier"); + } catch (InvalidConfigurationException e) { + assertThat(e) + .hasMessageThat() + .contains("Multiple toolchains with 'duplicate-toolchain' identifier"); + } + + try { + useConfiguration("--crosstool_top=//cc:suite", "--compiler=right-compiler", "--cpu=k8"); + getConfiguration(getConfiguredTarget("//a:b")).getFragment(CppConfiguration.class); + fail("expected failure because toolchain.compiler does not equal --compiler"); + } catch (InvalidConfigurationException e) { + assertThat(e) + .hasMessageThat() + .contains( + "The selected toolchain's cpu and compiler must match the command line options:\n" + + " --cpu: k8, toolchain.target_cpu: k8\n" + + " --compiler: right-compiler, toolchain.compiler: wrong-compiler"); + } + } }