aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/test/java/com/google/devtools/build/lib
diff options
context:
space:
mode:
authorGravatar Dmitry Lomov <dslomov@google.com>2015-11-30 16:25:40 +0000
committerGravatar Kristina Chodorow <kchodorow@google.com>2015-11-30 18:30:44 +0000
commite0a69aa87489f7cd7318235af6f1f5482b06ac85 (patch)
treec1d1ac3393c06d2b85ddb3bce032c367583d6179 /src/test/java/com/google/devtools/build/lib
parentbcaf61d376ecdcefc20cf1f8c50a03e62428dc38 (diff)
Open-source crosstool configuration tests.
-- MOS_MIGRATED_REVID=108980978
Diffstat (limited to 'src/test/java/com/google/devtools/build/lib')
-rw-r--r--src/test/java/com/google/devtools/build/lib/BUILD1
-rw-r--r--src/test/java/com/google/devtools/build/lib/rules/cpp/CrosstoolConfigurationHelper.java111
-rw-r--r--src/test/java/com/google/devtools/build/lib/rules/cpp/CrosstoolConfigurationLoaderTest.java1010
-rw-r--r--src/test/java/com/google/devtools/build/lib/testutil/TestConstants.java2
4 files changed, 1124 insertions, 0 deletions
diff --git a/src/test/java/com/google/devtools/build/lib/BUILD b/src/test/java/com/google/devtools/build/lib/BUILD
index cb846a43e3..ee85750c95 100644
--- a/src/test/java/com/google/devtools/build/lib/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/BUILD
@@ -839,6 +839,7 @@ java_test(
":testutil",
"//src/main/java/com/google/devtools/build/lib:analysis-exec-rules-skyframe",
"//src/main/java/com/google/devtools/build/lib:bazel-core",
+ "//src/main/java/com/google/devtools/build/lib:cmdline",
"//src/main/java/com/google/devtools/build/lib:util",
"//src/main/java/com/google/devtools/build/lib:vfs",
"//src/main/java/com/google/devtools/build/lib/actions",
diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/CrosstoolConfigurationHelper.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/CrosstoolConfigurationHelper.java
new file mode 100644
index 0000000000..f28af6dc0f
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/CrosstoolConfigurationHelper.java
@@ -0,0 +1,111 @@
+// Copyright 2015 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 com.google.devtools.build.lib.testutil.TestConstants;
+import com.google.devtools.build.lib.vfs.FileSystemUtils;
+import com.google.devtools.build.lib.vfs.Path;
+import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig;
+import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.DefaultCpuToolchain;
+import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.ToolPath;
+import com.google.protobuf.TextFormat;
+
+import java.io.IOException;
+
+/**
+ * Helper class for the creation of crosstool toolchain factories.
+ */
+public class CrosstoolConfigurationHelper {
+ public static Path overwriteCrosstoolFile(Path workspace, String content) throws IOException {
+ Path crosstool = workspace.getRelative(TestConstants.MOCK_CROSSTOOL_PATH + "/CROSSTOOL");
+ long newMTime = crosstool.exists() ? crosstool.getLastModifiedTime() + 1 : -1;
+ crosstool.delete();
+ FileSystemUtils.createDirectoryAndParents(crosstool.getParentDirectory());
+ FileSystemUtils.writeContentAsLatin1(crosstool, content);
+ crosstool.setLastModifiedTime(newMTime);
+ return crosstool;
+ }
+
+ /**
+ * Overwrites the default CROSSTOOL file with one obtained by merging the simple complete
+ * toolchain with the given additional partial toolchain. Only {@code --cpu=piii} is valid.
+ */
+ public static void overwriteCrosstoolWithToolchain(
+ Path workspace, CrosstoolConfig.CToolchain partial) throws IOException {
+ CrosstoolConfig.CrosstoolRelease.Builder release =
+ CrosstoolConfig.CrosstoolRelease.newBuilder();
+ release.mergeFrom(simpleCompleteToolchainProto());
+ CrosstoolConfig.CToolchain.Builder toolchain = CrosstoolConfig.CToolchain.newBuilder();
+ toolchain.mergeFrom(release.getToolchain(0));
+ toolchain.mergeFrom(partial);
+ release.setToolchain(0, toolchain.build());
+ overwriteCrosstoolFile(workspace, TextFormat.printToString(release.build()));
+ }
+
+ /**
+ * Overwrites the default CROSSTOOL file with a reasonable toolchain.
+ */
+ public static void overwriteCrosstoolWithSimpleCompleteToolchain(Path workspace)
+ throws IOException {
+ overwriteCrosstoolFile(workspace, TextFormat.printToString(simpleCompleteToolchainProto()));
+ }
+
+ private static CrosstoolConfig.CrosstoolRelease simpleCompleteToolchainProto() {
+ CrosstoolConfig.CrosstoolRelease.Builder builder =
+ CrosstoolConfig.CrosstoolRelease.newBuilder()
+ .setMajorVersion("12")
+ .setMinorVersion("0")
+ .setDefaultTargetCpu("k8")
+ .addDefaultToolchain(
+ DefaultCpuToolchain.newBuilder()
+ .setCpu("k8")
+ .setToolchainIdentifier("k8-toolchain"));
+ CrosstoolConfig.CToolchain.Builder toolchainBuilder = newIncompleteToolchain();
+ toolchainBuilder
+ .setToolchainIdentifier("k8-toolchain")
+ .setHostSystemName("i686-unknown-linux-gnu")
+ .setTargetSystemName("i686-unknown-linux-gnu")
+ .setTargetCpu("k8")
+ .setTargetLibc("glibc-2.3.6-grte")
+ .setCompiler("gcc-4.3.1")
+ .setAbiVersion("gcc-3.4")
+ .setAbiLibcVersion("2.3.2")
+ .addCxxBuiltinIncludeDirectory("/include/directory");
+ builder.addToolchain(toolchainBuilder);
+ return builder.build();
+ }
+
+ private static CrosstoolConfig.CToolchain.Builder newIncompleteToolchain() {
+ CrosstoolConfig.CToolchain.Builder builder = CrosstoolConfig.CToolchain.newBuilder();
+ for (String tool :
+ new String[] {
+ "ar",
+ "cpp",
+ "gcc",
+ "gcov",
+ "ld",
+ "compat-ld",
+ "nm",
+ "objcopy",
+ "objdump",
+ "strip",
+ "dwp",
+ "gcov-tool"
+ }) {
+ builder.addToolPath(ToolPath.newBuilder().setName(tool).setPath(tool));
+ }
+ return builder;
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/CrosstoolConfigurationLoaderTest.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/CrosstoolConfigurationLoaderTest.java
new file mode 100644
index 0000000000..fbb98f0bc3
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/CrosstoolConfigurationLoaderTest.java
@@ -0,0 +1,1010 @@
+// Copyright 2015 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 com.google.common.base.Functions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.analysis.config.BuildOptions;
+import com.google.devtools.build.lib.analysis.config.CompilationMode;
+import com.google.devtools.build.lib.analysis.config.ConfigurationEnvironment;
+import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException;
+import com.google.devtools.build.lib.analysis.util.AnalysisMock;
+import com.google.devtools.build.lib.analysis.util.AnalysisTestCase;
+import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
+import com.google.devtools.build.lib.cmdline.PackageIdentifier;
+import com.google.devtools.build.lib.rules.cpp.CppConfiguration.Tool;
+import com.google.devtools.build.lib.testutil.TestConstants;
+import com.google.devtools.build.lib.vfs.PathFragment;
+import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.LipoMode;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * Tests for {@link CppConfigurationLoader}.
+ */
+public class CrosstoolConfigurationLoaderTest extends AnalysisTestCase {
+ private static final Collection<String> NO_FEATURES = Collections.emptySet();
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ private CppConfiguration create(CppConfigurationLoader loader, String... args) throws Exception {
+ ConfigurationEnvironment env =
+ new ConfigurationEnvironment.TargetProviderEnvironment(
+ skyframeExecutor.getPackageManager(), reporter, directories);
+ return loader.create(env, BuildOptions.of(AnalysisMock.get().getBuildOptions(), args));
+ }
+
+ private CppConfigurationLoader loader(String crosstoolFileContents) throws IOException {
+ CrosstoolConfigurationHelper.overwriteCrosstoolFile(
+ directories.getWorkspace(), crosstoolFileContents);
+ return new CppConfigurationLoader(Functions.<String>identity());
+ }
+
+ private CppConfigurationLoader loaderWithOptionalTool(String optionalTool) throws IOException {
+ return loader(
+ "major_version: \"12\""
+ + "minor_version: \"0\""
+ + "default_target_cpu: \"cpu\""
+ + "default_toolchain {"
+ + " cpu: \"cpu\""
+ + " toolchain_identifier: \"toolchain-identifier\""
+ + "}"
+ + "toolchain {"
+ + " toolchain_identifier: \"toolchain-identifier\""
+ + " host_system_name: \"host-system-name\""
+ + " target_system_name: \"target-system-name\""
+ + " target_cpu: \"piii\""
+ + " target_libc: \"target-libc\""
+ + " compiler: \"compiler\""
+ + " abi_version: \"abi-version\""
+ + " abi_libc_version: \"abi-libc-version\""
+ + " tool_path { name: \"ar\" path: \"path-to-ar\" }"
+ + " tool_path { name: \"cpp\" path: \"path-to-cpp\" }"
+ + " tool_path { name: \"gcc\" path: \"path-to-gcc\" }"
+ + " tool_path { name: \"gcov\" path: \"path-to-gcov\" }"
+ + " tool_path { name: \"ld\" path: \"path-to-ld\" }"
+ + " tool_path { name: \"nm\" path: \"path-to-nm\" }"
+ + " tool_path { name: \"objcopy\" path: \"path-to-objcopy\" }"
+ + " tool_path { name: \"objdump\" path: \"path-to-objdump\" }"
+ + " tool_path { name: \"strip\" path: \"path-to-strip\" }"
+ + " tool_path { name: \"dwp\" path: \"path-to-dwp\" }"
+ + optionalTool
+ + " supports_gold_linker: true"
+ + " supports_thin_archives: true"
+ + " supports_normalizing_ar: true"
+ + " supports_incremental_linker: true"
+ + " supports_fission: true"
+ + " compiler_flag: \"c\""
+ + " cxx_flag: \"cxx\""
+ + " unfiltered_cxx_flag: \"unfiltered\""
+ + " linker_flag: \"linker\""
+ + " dynamic_library_linker_flag: \"solinker\""
+ + " objcopy_embed_flag: \"objcopy\""
+ + " compilation_mode_flags {"
+ + " mode: FASTBUILD"
+ + " compiler_flag: \"fastbuild\""
+ + " cxx_flag: \"cxx-fastbuild\""
+ + " linker_flag: \"linker-fastbuild\""
+ + " }"
+ + " compilation_mode_flags {"
+ + " mode: DBG"
+ + " compiler_flag: \"dbg\""
+ + " cxx_flag: \"cxx-dbg\""
+ + " linker_flag: \"linker-dbg\""
+ + " }"
+ + " compilation_mode_flags {"
+ + " mode: COVERAGE"
+ + " compiler_flag: \"coverage\""
+ + " cxx_flag: \"cxx-coverage\""
+ + " linker_flag: \"linker-coverage\""
+ + " }"
+ + " compilation_mode_flags {"
+ + " mode: OPT"
+ + " compiler_flag: \"opt\""
+ + " cxx_flag: \"cxx-opt\""
+ + " linker_flag: \"linker-opt\""
+ + " }"
+ + " linking_mode_flags {"
+ + " mode: FULLY_STATIC"
+ + " linker_flag: \"fully static\""
+ + " }"
+ + " linking_mode_flags {"
+ + " mode: MOSTLY_STATIC"
+ + " linker_flag: \"mostly static\""
+ + " }"
+ + " linking_mode_flags {"
+ + " mode: DYNAMIC"
+ + " linker_flag: \"dynamic\""
+ + " }"
+ + " make_variable {"
+ + " name: \"SOME_MAKE_VARIABLE\""
+ + " value: \"make-variable-value\""
+ + " }"
+ + " cxx_builtin_include_directory: \"system-include-dir\""
+ + "}");
+ }
+
+ /**
+ * Checks that we do not accidentally change the proto format in incompatible
+ * ways. Do not modify the configuration file in this test, except if you are
+ * absolutely certain that it is backwards-compatible.
+ */
+ public void testSimpleCompleteConfiguration() throws Exception {
+ CppConfigurationLoader loader = loaderWithOptionalTool("");
+
+ CppConfiguration toolchain = create(loader, "--cpu=cpu");
+ assertEquals("toolchain-identifier", toolchain.getToolchainIdentifier());
+
+ assertEquals("host-system-name", toolchain.getHostSystemName());
+ assertEquals("compiler", toolchain.getCompiler());
+ assertEquals("target-libc", toolchain.getTargetLibc());
+ assertEquals("piii", toolchain.getTargetCpu());
+ assertEquals("target-system-name", toolchain.getTargetGnuSystemName());
+
+ assertEquals(getToolPath("/path-to-ar"), toolchain.getToolPathFragment(Tool.AR));
+
+ assertEquals("abi-version", toolchain.getAbi());
+ assertEquals("abi-libc-version", toolchain.getAbiGlibcVersion());
+
+ assertTrue(toolchain.supportsGoldLinker());
+ assertTrue(toolchain.supportsThinArchives());
+ assertFalse(toolchain.supportsStartEndLib());
+ assertFalse(toolchain.supportsInterfaceSharedObjects());
+ assertFalse(toolchain.supportsEmbeddedRuntimes());
+ assertFalse(toolchain.toolchainNeedsPic());
+ assertTrue(toolchain.supportsFission());
+
+ assertEquals(
+ ImmutableList.of(getToolPath("/system-include-dir")),
+ toolchain.getBuiltInIncludeDirectories());
+ assertNull(toolchain.getSysroot());
+
+ assertEquals(Arrays.asList("c", "fastbuild"), toolchain.getCompilerOptions(NO_FEATURES));
+ assertEquals(Arrays.<String>asList(), toolchain.getCOptions());
+ assertEquals(Arrays.asList("cxx", "cxx-fastbuild"), toolchain.getCxxOptions(NO_FEATURES));
+ assertEquals(Arrays.asList("unfiltered"), toolchain.getUnfilteredCompilerOptions(NO_FEATURES));
+
+ assertEquals(Arrays.<String>asList(), toolchain.getLinkOptions());
+ assertEquals(
+ Arrays.asList("linker", "-Wl,-S", "linker-fastbuild", "fully static"),
+ toolchain.getFullyStaticLinkOptions(NO_FEATURES, false));
+ assertEquals(
+ Arrays.asList("linker", "-Wl,-S", "linker-fastbuild", "dynamic"),
+ toolchain.getDynamicLinkOptions(NO_FEATURES, false));
+ assertEquals(
+ Arrays.asList("linker", "-Wl,-S", "linker-fastbuild", "mostly static", "solinker"),
+ toolchain.getFullyStaticLinkOptions(NO_FEATURES, true));
+ assertEquals(
+ Arrays.asList("linker", "-Wl,-S", "linker-fastbuild", "dynamic", "solinker"),
+ toolchain.getDynamicLinkOptions(NO_FEATURES, true));
+
+ assertEquals(Arrays.asList("objcopy"), toolchain.getObjCopyOptionsForEmbedding());
+ assertEquals(Arrays.<String>asList(), toolchain.getLdOptionsForEmbedding());
+ assertEquals(Arrays.asList("rcsD"), toolchain.getArFlags(/*thinArchives=*/ false));
+ assertEquals(Arrays.asList("rcsDT"), toolchain.getArFlags(/*thinArchives=*/ true));
+
+ assertThat(toolchain.getAdditionalMakeVariables().entrySet())
+ .containsExactlyElementsIn(
+ ImmutableMap.of(
+ "SOME_MAKE_VARIABLE", "make-variable-value",
+ "STACK_FRAME_UNLIMITED", "",
+ "CC_FLAGS", "")
+ .entrySet());
+
+ assertEquals(getToolPath("/path-to-ld"), toolchain.getLdExecutable());
+ assertEquals(getToolPath("/path-to-dwp"), toolchain.getToolPathFragment(Tool.DWP));
+ }
+
+ /**
+ * Tests all of the fields and a bunch of the combinations a config can hold,
+ * including non-default toolchains, missing sections and repeated entries
+ * (and their order in the end result.)
+ */
+ public void testComprehensiveCompleteConfiguration() throws Exception {
+ CppConfigurationLoader loader =
+ loader(
+ // Needs to include \n's; as a single line it hits a parser limitation.
+ "major_version: \"12\"\n"
+ + "minor_version: \"0\"\n"
+ + "default_target_cpu: \"piii\"\n"
+ + "default_toolchain {\n"
+ + " cpu: \"piii\"\n"
+ + " toolchain_identifier: \"toolchain-identifier-A\"\n"
+ + "}\n"
+ + "default_toolchain {\n"
+ + " cpu: \"k8\"\n"
+ + " toolchain_identifier: \"toolchain-identifier-B\"\n"
+ + "}\n"
+ + "toolchain {\n"
+ + " toolchain_identifier: \"toolchain-identifier-A\"\n"
+ + " host_system_name: \"host-system-name-A\"\n"
+ + " target_system_name: \"target-system-name-A\"\n"
+ + " target_cpu: \"piii\"\n"
+ + " target_libc: \"target-libc-A\"\n"
+ + " compiler: \"compiler-A\"\n"
+ + " abi_version: \"abi-version-A\"\n"
+ + " abi_libc_version: \"abi-libc-version-A\"\n"
+ + " tool_path { name: \"ar\" path: \"path/to/ar-A\" }\n"
+ + " tool_path { name: \"cpp\" path: \"path/to/cpp-A\" }\n"
+ + " tool_path { name: \"gcc\" path: \"path/to/gcc-A\" }\n"
+ + " tool_path { name: \"gcov\" path: \"path/to/gcov-A\" }\n"
+ + " tool_path { name: \"gcov-tool\" path: \"path-to-gcov-tool-A\" }"
+ + " tool_path { name: \"ld\" path: \"path/to/ld-A\" }\n"
+ + " tool_path { name: \"nm\" path: \"path/to/nm-A\" }\n"
+ + " tool_path { name: \"objcopy\" path: \"path/to/objcopy-A\" }\n"
+ + " tool_path { name: \"objdump\" path: \"path/to/objdump-A\" }\n"
+ + " tool_path { name: \"strip\" path: \"path/to/strip-A\" }\n"
+ + " tool_path { name: \"dwp\" path: \"path/to/dwp\" }\n"
+ + " supports_gold_linker: true\n"
+ + " supports_thin_archives: true\n"
+ + " supports_start_end_lib: true\n"
+ + " supports_normalizing_ar: true\n"
+ + " supports_embedded_runtimes: true\n"
+ + " needsPic: true\n"
+ + " compiler_flag: \"compiler-flag-A-1\"\n"
+ + " compiler_flag: \"compiler-flag-A-2\"\n"
+ + " cxx_flag: \"cxx-flag-A-1\"\n"
+ + " cxx_flag: \"cxx-flag-A-2\"\n"
+ + " unfiltered_cxx_flag: \"unfiltered-flag-A-1\"\n"
+ + " unfiltered_cxx_flag: \"unfiltered-flag-A-2\"\n"
+ + " linker_flag: \"linker-flag-A-1\"\n"
+ + " linker_flag: \"linker-flag-A-2\"\n"
+ + " dynamic_library_linker_flag: \"solinker-flag-A-1\"\n"
+ + " dynamic_library_linker_flag: \"solinker-flag-A-2\"\n"
+ + " objcopy_embed_flag: \"objcopy-embed-flag-A-1\"\n"
+ + " objcopy_embed_flag: \"objcopy-embed-flag-A-2\"\n"
+ + " ld_embed_flag: \"ld-embed-flag-A-1\"\n"
+ + " ld_embed_flag: \"ld-embed-flag-A-2\"\n"
+ + " ar_flag : \"ar-flag-A\"\n"
+ + " ar_thin_archives_flag : \"ar-thin-archives-flag-A\"\n"
+ + " compilation_mode_flags {\n"
+ + " mode: FASTBUILD\n"
+ + " compiler_flag: \"fastbuild-flag-A-1\"\n"
+ + " compiler_flag: \"fastbuild-flag-A-2\"\n"
+ + " cxx_flag: \"cxx-fastbuild-flag-A-1\"\n"
+ + " cxx_flag: \"cxx-fastbuild-flag-A-2\"\n"
+ + " linker_flag: \"linker-fastbuild-flag-A-1\"\n"
+ + " linker_flag: \"linker-fastbuild-flag-A-2\"\n"
+ + " }\n"
+ + " compilation_mode_flags {\n"
+ + " mode: DBG\n"
+ + " compiler_flag: \"dbg-flag-A-1\"\n"
+ + " compiler_flag: \"dbg-flag-A-2\"\n"
+ + " cxx_flag: \"cxx-dbg-flag-A-1\"\n"
+ + " cxx_flag: \"cxx-dbg-flag-A-2\"\n"
+ + " linker_flag: \"linker-dbg-flag-A-1\"\n"
+ + " linker_flag: \"linker-dbg-flag-A-2\"\n"
+ + " }\n"
+ + " compilation_mode_flags {\n"
+ + " mode: COVERAGE\n"
+ + " }\n"
+ + " # skip mode OPT to test handling its absence\n"
+ + " linking_mode_flags {\n"
+ + " mode: FULLY_STATIC\n"
+ + " linker_flag: \"fully-static-flag-A-1\"\n"
+ + " linker_flag: \"fully-static-flag-A-2\"\n"
+ + " }\n"
+ + " linking_mode_flags {\n"
+ + " mode: MOSTLY_STATIC\n"
+ + " }\n"
+ + " # skip linking mode DYNAMIC to test handling its absence\n"
+ + " make_variable {\n"
+ + " name: \"SOME_MAKE_VARIABLE-A-1\"\n"
+ + " value: \"make-variable-value-A-1\"\n"
+ + " }\n"
+ + " make_variable {\n"
+ + " name: \"SOME_MAKE_VARIABLE-A-2\"\n"
+ + " value: \"make-variable-value-A-2 with spaces in\"\n"
+ + " }\n"
+ + " cxx_builtin_include_directory: \"system-include-dir-A-1\"\n"
+ + " cxx_builtin_include_directory: \"system-include-dir-A-2\"\n"
+ + " builtin_sysroot: \"builtin-sysroot-A\"\n"
+ + " default_python_top: \"python-top-A\"\n"
+ + " default_python_version: \"python-version-A\"\n"
+ + " default_grte_top: \"//some:labelA\""
+ + " debian_extra_requires: \"a\""
+ + " debian_extra_requires: \"b\""
+ + "}\n"
+ + "toolchain {\n"
+ + " toolchain_identifier: \"toolchain-identifier-B\"\n"
+ + " host_system_name: \"host-system-name-B\"\n"
+ + " target_system_name: \"target-system-name-B\"\n"
+ + " target_cpu: \"piii\"\n"
+ + " target_libc: \"target-libc-B\"\n"
+ + " compiler: \"compiler-B\"\n"
+ + " abi_version: \"abi-version-B\"\n"
+ + " abi_libc_version: \"abi-libc-version-B\"\n"
+ + " tool_path { name: \"ar\" path: \"path/to/ar-B\" }\n"
+ + " tool_path { name: \"cpp\" path: \"path/to/cpp-B\" }\n"
+ + " tool_path { name: \"gcc\" path: \"path/to/gcc-B\" }\n"
+ + " tool_path { name: \"gcov\" path: \"path/to/gcov-B\" }\n"
+ + " tool_path { name: \"gcov-tool\" path: \"path/to/gcov-tool-B\" }\n"
+ + " tool_path { name: \"ld\" path: \"path/to/ld-B\" }\n"
+ + " tool_path { name: \"nm\" path: \"path/to/nm-B\" }\n"
+ + " tool_path { name: \"objcopy\" path: \"path/to/objcopy-B\" }\n"
+ + " tool_path { name: \"objdump\" path: \"path/to/objdump-B\" }\n"
+ + " tool_path { name: \"strip\" path: \"path/to/strip-B\" }\n"
+ + " tool_path { name: \"dwp\" path: \"path/to/dwp\" }\n"
+ + " supports_gold_linker: true\n"
+ + " supports_thin_archives: true\n"
+ + " supports_start_end_lib: true\n"
+ + " supports_normalizing_ar: true\n"
+ + " supports_embedded_runtimes: true\n"
+ + " needsPic: true\n"
+ + " compiler_flag: \"compiler-flag-B-1\"\n"
+ + " compiler_flag: \"compiler-flag-B-2\"\n"
+ + " optional_compiler_flag {\n"
+ + " default_setting_name: \"crosstool_fig\"\n"
+ + " flag: \"-Wfig\"\n"
+ + " }\n"
+ + " cxx_flag: \"cxx-flag-B-1\"\n"
+ + " cxx_flag: \"cxx-flag-B-2\"\n"
+ + " unfiltered_cxx_flag: \"unfiltered-flag-B-1\"\n"
+ + " unfiltered_cxx_flag: \"unfiltered-flag-B-2\"\n"
+ + " linker_flag: \"linker-flag-B-1\"\n"
+ + " linker_flag: \"linker-flag-B-2\"\n"
+ + " dynamic_library_linker_flag: \"solinker-flag-B-1\"\n"
+ + " dynamic_library_linker_flag: \"solinker-flag-B-2\"\n"
+ + " objcopy_embed_flag: \"objcopy-embed-flag-B-1\"\n"
+ + " objcopy_embed_flag: \"objcopy-embed-flag-B-2\"\n"
+ + " ld_embed_flag: \"ld-embed-flag-B-1\"\n"
+ + " ld_embed_flag: \"ld-embed-flag-B-2\"\n"
+ + " ar_flag : \"ar-flag-B\"\n"
+ + " ar_thin_archives_flag : \"ar-thin-archives-flag-B\"\n"
+ + " compilation_mode_flags {\n"
+ + " mode: FASTBUILD\n"
+ + " compiler_flag: \"fastbuild-flag-B-1\"\n"
+ + " compiler_flag: \"fastbuild-flag-B-2\"\n"
+ + " cxx_flag: \"cxx-fastbuild-flag-B-1\"\n"
+ + " cxx_flag: \"cxx-fastbuild-flag-B-2\"\n"
+ + " linker_flag: \"linker-fastbuild-flag-B-1\"\n"
+ + " linker_flag: \"linker-fastbuild-flag-B-2\"\n"
+ + " }\n"
+ + " compilation_mode_flags {\n"
+ + " mode: DBG\n"
+ + " compiler_flag: \"dbg-flag-B-1\"\n"
+ + " compiler_flag: \"dbg-flag-B-2\"\n"
+ + " cxx_flag: \"cxx-dbg-flag-B-1\"\n"
+ + " cxx_flag: \"cxx-dbg-flag-B-2\"\n"
+ + " linker_flag: \"linker-dbg-flag-B-1\"\n"
+ + " linker_flag: \"linker-dbg-flag-B-2\"\n"
+ + " }\n"
+ + " compilation_mode_flags {\n"
+ + " mode: COVERAGE\n"
+ + " }\n"
+ + " # skip mode OPT to test handling its absence\n"
+ + " lipo_mode_flags {"
+ + " mode: OFF"
+ + " compiler_flag: \"lipo_off\""
+ + " cxx_flag: \"cxx-lipo_off\""
+ + " linker_flag: \"linker-lipo_off\""
+ + " }"
+ + " lipo_mode_flags {"
+ + " mode: BINARY"
+ + " compiler_flag: \"lipo_binary\""
+ + " cxx_flag: \"cxx-lipo_binary\""
+ + " linker_flag: \"linker-lipo_binary\""
+ + " }"
+ + " linking_mode_flags {\n"
+ + " mode: FULLY_STATIC\n"
+ + " linker_flag: \"fully-static-flag-B-1\"\n"
+ + " linker_flag: \"fully-static-flag-B-2\"\n"
+ + " }\n"
+ + " linking_mode_flags {\n"
+ + " mode: MOSTLY_STATIC\n"
+ + " }\n"
+ + " # skip linking mode DYNAMIC to test handling its absence\n"
+ + " make_variable {\n"
+ + " name: \"SOME_MAKE_VARIABLE-B-1\"\n"
+ + " value: \"make-variable-value-B-1\"\n"
+ + " }\n"
+ + " make_variable {\n"
+ + " name: \"SOME_MAKE_VARIABLE-B-2\"\n"
+ + " value: \"make-variable-value-B-2 with spaces in\"\n"
+ + " }\n"
+ + " cxx_builtin_include_directory: \"system-include-dir-B-1\"\n"
+ + " cxx_builtin_include_directory: \"system-include-dir-B-2\"\n"
+ + " builtin_sysroot: \"builtin-sysroot-B\"\n"
+ + " default_python_top: \"python-top-B\"\n"
+ + " default_python_version: \"python-version-B\"\n"
+ + " default_grte_top: \"//some:labelB\"\n"
+ + " debian_extra_requires: \"c\""
+ + " debian_extra_requires: \"d\""
+ + "}\n"
+ + "default_setting {\n"
+ + " name: \"crosstool_fig\"\n"
+ + " default_value: false\n"
+ + "}\n"
+ + "toolchain {\n"
+ + " toolchain_identifier: \"toolchain-identifier-C\"\n"
+ + " host_system_name: \"host-system-name-C\"\n"
+ + " target_system_name: \"target-system-name-C\"\n"
+ + " target_cpu: \"piii\"\n"
+ + " target_libc: \"target-libc-C\"\n"
+ + " compiler: \"compiler-C\"\n"
+ + " abi_version: \"abi-version-C\"\n"
+ + " abi_libc_version: \"abi-libc-version-C\"\n"
+ + " tool_path { name: \"ar\" path: \"path/to/ar-C\" }"
+ + " tool_path { name: \"cpp\" path: \"path/to/cpp-C\" }"
+ + " tool_path { name: \"gcc\" path: \"path/to/gcc-C\" }"
+ + " tool_path { name: \"gcov\" path: \"path/to/gcov-C\" }"
+ + " tool_path { name: \"gcov-tool\" path: \"path/to/gcov-tool-C\" }"
+ + " tool_path { name: \"ld\" path: \"path/to/ld-C\" }"
+ + " tool_path { name: \"nm\" path: \"path/to/nm-C\" }"
+ + " tool_path { name: \"objcopy\" path: \"path/to/objcopy-C\" }"
+ + " tool_path { name: \"objdump\" path: \"path/to/objdump-C\" }"
+ + " tool_path { name: \"strip\" path: \"path/to/strip-C\" }"
+ + " tool_path { name: \"dwp\" path: \"path/to/dwp\" }\n"
+ + "}");
+
+ CppConfiguration toolchainA = create(loader, "--cpu=piii");
+ assertEquals("toolchain-identifier-A", toolchainA.getToolchainIdentifier());
+ assertEquals("host-system-name-A", toolchainA.getHostSystemName());
+ assertEquals("target-system-name-A", toolchainA.getTargetGnuSystemName());
+ assertEquals("piii", toolchainA.getTargetCpu());
+ assertEquals("target-libc-A", toolchainA.getTargetLibc());
+ assertEquals("compiler-A", toolchainA.getCompiler());
+ assertEquals("abi-version-A", toolchainA.getAbi());
+ assertEquals("abi-libc-version-A", toolchainA.getAbiGlibcVersion());
+ assertEquals(getToolPath("path/to/ar-A"), toolchainA.getToolPathFragment(Tool.AR));
+ assertEquals(getToolPath("path/to/cpp-A"), toolchainA.getToolPathFragment(Tool.CPP));
+ assertEquals(getToolPath("path/to/gcc-A"), toolchainA.getToolPathFragment(Tool.GCC));
+ assertEquals(getToolPath("path/to/gcov-A"), toolchainA.getToolPathFragment(Tool.GCOV));
+ assertEquals(getToolPath("path/to/ld-A"), toolchainA.getToolPathFragment(Tool.LD));
+ assertEquals(getToolPath("path/to/nm-A"), toolchainA.getToolPathFragment(Tool.NM));
+ assertEquals(getToolPath("path/to/objcopy-A"), toolchainA.getToolPathFragment(Tool.OBJCOPY));
+ assertEquals(getToolPath("path/to/objdump-A"), toolchainA.getToolPathFragment(Tool.OBJDUMP));
+ assertEquals(getToolPath("path/to/strip-A"), toolchainA.getToolPathFragment(Tool.STRIP));
+ assertTrue(toolchainA.supportsGoldLinker());
+ assertTrue(toolchainA.supportsThinArchives());
+ assertTrue(toolchainA.supportsStartEndLib());
+ assertTrue(toolchainA.supportsEmbeddedRuntimes());
+ assertTrue(toolchainA.toolchainNeedsPic());
+
+ assertEquals(
+ Arrays.asList(
+ "compiler-flag-A-1", "compiler-flag-A-2", "fastbuild-flag-A-1", "fastbuild-flag-A-2"),
+ toolchainA.getCompilerOptions(NO_FEATURES));
+ assertEquals(
+ Arrays.asList(
+ "cxx-flag-A-1", "cxx-flag-A-2", "cxx-fastbuild-flag-A-1", "cxx-fastbuild-flag-A-2"),
+ toolchainA.getCxxOptions(NO_FEATURES));
+ assertEquals(
+ Arrays.asList("--sysroot=some", "unfiltered-flag-A-1", "unfiltered-flag-A-2"),
+ toolchainA.getUnfilteredCompilerOptions(NO_FEATURES));
+ assertEquals(
+ Arrays.asList(
+ "linker-flag-A-1",
+ "linker-flag-A-2",
+ "-Wl,-S",
+ "linker-fastbuild-flag-A-1",
+ "linker-fastbuild-flag-A-2",
+ "solinker-flag-A-1",
+ "solinker-flag-A-2"),
+ toolchainA.getDynamicLinkOptions(NO_FEATURES, true));
+
+ // Only test a couple of compilation/lipo/linking mode combinations
+ // (but test each mode at least once.)
+ assertEquals(
+ Arrays.asList(
+ "linker-flag-A-1",
+ "linker-flag-A-2",
+ "-Wl,-S",
+ "linker-fastbuild-flag-A-1",
+ "linker-fastbuild-flag-A-2",
+ "fully-static-flag-A-1",
+ "fully-static-flag-A-2"),
+ toolchainA.configureLinkerOptions(
+ CompilationMode.FASTBUILD,
+ LipoMode.OFF,
+ LinkingMode.FULLY_STATIC,
+ new PathFragment("hello-world/ld"),
+ true));
+ assertEquals(
+ Arrays.asList(
+ "linker-flag-A-1",
+ "linker-flag-A-2",
+ "-Wl,-S",
+ "linker-dbg-flag-A-1",
+ "linker-dbg-flag-A-2"),
+ toolchainA.configureLinkerOptions(
+ CompilationMode.DBG,
+ LipoMode.OFF,
+ LinkingMode.DYNAMIC,
+ new PathFragment("hello-world/ld"),
+ true));
+ assertEquals(
+ Arrays.asList(
+ "linker-flag-A-1",
+ "linker-flag-A-2",
+ "-Wl,-S",
+ "fully-static-flag-A-1",
+ "fully-static-flag-A-2"),
+ toolchainA.configureLinkerOptions(
+ CompilationMode.OPT,
+ LipoMode.OFF,
+ LinkingMode.FULLY_STATIC,
+ new PathFragment("hello-world/ld"),
+ true));
+
+ assertEquals(
+ Arrays.asList(
+ "linker-flag-A-1",
+ "linker-flag-A-2",
+ "-Wl,-S",
+ "fully-static-flag-A-1",
+ "fully-static-flag-A-2"),
+ toolchainA.configureLinkerOptions(
+ CompilationMode.OPT,
+ LipoMode.BINARY,
+ LinkingMode.FULLY_STATIC,
+ new PathFragment("hello-world/ld"),
+ true));
+
+ assertEquals(
+ Arrays.asList("objcopy-embed-flag-A-1", "objcopy-embed-flag-A-2"),
+ toolchainA.getObjCopyOptionsForEmbedding());
+ assertEquals(
+ Arrays.asList("ld-embed-flag-A-1", "ld-embed-flag-A-2"),
+ toolchainA.getLdOptionsForEmbedding());
+ assertEquals(Arrays.asList("ar-flag-A"), toolchainA.getArFlags(/*thinArchives=*/ false));
+ assertEquals(
+ Arrays.asList("ar-thin-archives-flag-A"), toolchainA.getArFlags(/*thinArchives=*/ true));
+
+ assertThat(toolchainA.getAdditionalMakeVariables().entrySet())
+ .containsExactlyElementsIn(
+ ImmutableMap.<String, String>builder()
+ .put("SOME_MAKE_VARIABLE-A-1", "make-variable-value-A-1")
+ .put("SOME_MAKE_VARIABLE-A-2", "make-variable-value-A-2 with spaces in")
+ .put("CC_FLAGS", "--sysroot=some")
+ .put("STACK_FRAME_UNLIMITED", "")
+ .build()
+ .entrySet());
+ assertEquals(
+ Arrays.asList(
+ getToolPath("/system-include-dir-A-1"), getToolPath("/system-include-dir-A-2")),
+ toolchainA.getBuiltInIncludeDirectories());
+ assertEquals(new PathFragment("some"), toolchainA.getSysroot());
+
+ // Cursory testing of the "B" toolchain only; assume that if none of
+ // toolchain B bled through into toolchain A, the reverse also didn't occur. And
+ // we test more of it with the "C" toolchain below.
+ checkToolchainB(loader, LipoMode.OFF, "--cpu=k8", "--lipo=off");
+ checkToolchainB(loader, LipoMode.BINARY, "--cpu=k8", "--lipo=binary");
+
+ // Make sure nothing bled through to the nearly-empty "C" toolchain. This is also testing for
+ // all the defaults.
+ CppConfiguration toolchainC =
+ create(loader, "--compiler=compiler-C", "--glibc=target-libc-C", "--cpu=piii");
+ assertEquals("toolchain-identifier-C", toolchainC.getToolchainIdentifier());
+ assertEquals("host-system-name-C", toolchainC.getHostSystemName());
+ assertEquals("target-system-name-C", toolchainC.getTargetGnuSystemName());
+ assertEquals("piii", toolchainC.getTargetCpu());
+ assertEquals("target-libc-C", toolchainC.getTargetLibc());
+ assertEquals("compiler-C", toolchainC.getCompiler());
+ assertEquals("abi-version-C", toolchainC.getAbi());
+ assertEquals("abi-libc-version-C", toolchainC.getAbiGlibcVersion());
+ // Don't bother with testing the list of tools again.
+ assertFalse(toolchainC.supportsGoldLinker());
+ assertFalse(toolchainC.supportsThinArchives());
+ assertFalse(toolchainC.supportsStartEndLib());
+ assertFalse(toolchainC.supportsInterfaceSharedObjects());
+ assertFalse(toolchainC.supportsEmbeddedRuntimes());
+ assertFalse(toolchainC.toolchainNeedsPic());
+ assertFalse(toolchainC.supportsFission());
+
+ assertThat(toolchainC.getCompilerOptions(NO_FEATURES)).isEmpty();
+ assertThat(toolchainC.getCOptions()).isEmpty();
+ assertThat(toolchainC.getCxxOptions(NO_FEATURES)).isEmpty();
+ assertThat(toolchainC.getUnfilteredCompilerOptions(NO_FEATURES)).isEmpty();
+ assertEquals(Arrays.asList("-Wl,-S"), toolchainC.getDynamicLinkOptions(NO_FEATURES, true));
+ assertEquals(
+ Arrays.asList("-Wl,-S"),
+ toolchainC.configureLinkerOptions(
+ CompilationMode.FASTBUILD,
+ LipoMode.OFF,
+ LinkingMode.FULLY_STATIC,
+ new PathFragment("hello-world/ld"),
+ true));
+ assertEquals(
+ Arrays.asList("-Wl,-S"),
+ toolchainC.configureLinkerOptions(
+ CompilationMode.DBG,
+ LipoMode.OFF,
+ LinkingMode.DYNAMIC,
+ new PathFragment("hello-world/ld"),
+ true));
+ assertEquals(
+ Arrays.asList("-Wl,-S"),
+ toolchainC.configureLinkerOptions(
+ CompilationMode.OPT,
+ LipoMode.OFF,
+ LinkingMode.FULLY_STATIC,
+ new PathFragment("hello-world/ld"),
+ true));
+ assertThat(toolchainC.getObjCopyOptionsForEmbedding()).isEmpty();
+ assertThat(toolchainC.getLdOptionsForEmbedding()).isEmpty();
+
+ assertThat(toolchainC.getAdditionalMakeVariables().entrySet())
+ .containsExactlyElementsIn(
+ ImmutableMap.<String, String>builder()
+ .put("CC_FLAGS", "")
+ .put("STACK_FRAME_UNLIMITED", "")
+ .build()
+ .entrySet());
+ assertThat(toolchainC.getBuiltInIncludeDirectories()).isEmpty();
+ assertNull(toolchainC.getSysroot());
+ }
+
+ protected PathFragment getToolPath(String path) throws LabelSyntaxException {
+ PackageIdentifier packageIdentifier =
+ PackageIdentifier.create(
+ TestConstants.TOOLS_REPOSITORY,
+ new PathFragment(
+ new PathFragment(TestConstants.MOCK_CROSSTOOL_PATH), new PathFragment(path)));
+ return packageIdentifier.getPathFragment();
+ }
+
+ private void checkToolchainB(CppConfigurationLoader loader, LipoMode lipoMode, String... args)
+ throws Exception {
+ String lipoSuffix = lipoMode.toString().toLowerCase();
+ CppConfiguration toolchainB = create(loader, args);
+ assertEquals("toolchain-identifier-B", toolchainB.getToolchainIdentifier());
+ assertEquals(
+ Arrays.asList(
+ "linker-flag-B-1",
+ "linker-flag-B-2",
+ "-Wl,-S",
+ "linker-dbg-flag-B-1",
+ "linker-dbg-flag-B-2",
+ "linker-lipo_" + lipoSuffix),
+ toolchainB.configureLinkerOptions(
+ CompilationMode.DBG,
+ lipoMode,
+ LinkingMode.DYNAMIC,
+ new PathFragment("hello-world/ld"),
+ true));
+ assertEquals(
+ ImmutableList.<String>of(
+ "compiler-flag-B-1",
+ "compiler-flag-B-2",
+ "fastbuild-flag-B-1",
+ "fastbuild-flag-B-2",
+ "lipo_" + lipoSuffix,
+ "-Wfig"),
+ toolchainB.getCompilerOptions(ImmutableList.of("crosstool_fig")));
+ }
+
+ /**
+ * Tests that we can select a toolchain using a subset of the --compiler and
+ * --glibc flags, as long as they select a unique result. Also tests the error
+ * messages we get when they don't.
+ */
+ public void testCompilerLibcSearch() throws Exception {
+ CppConfigurationLoader loader =
+ loader(
+ // Needs to include \n's; as a single line it hits a parser limitation.
+ "major_version: \"12\"\n"
+ + "minor_version: \"0\"\n"
+ + "default_target_cpu: \"k8\"\n"
+ + "default_toolchain {\n"
+ + " cpu: \"piii\"\n"
+ + " toolchain_identifier: \"toolchain-identifier-AA-piii\"\n"
+ + "}\n"
+ + "default_toolchain {\n"
+ + " cpu: \"k8\"\n"
+ + " toolchain_identifier: \"toolchain-identifier-BB\"\n"
+ + "}\n"
+ + "toolchain {\n"
+ + " toolchain_identifier: \"toolchain-identifier-AA\"\n"
+ + " host_system_name: \"host-system-name-AA\"\n"
+ + " target_system_name: \"target-system-name-AA\"\n"
+ + " target_cpu: \"k8\"\n"
+ + " target_libc: \"target-libc-A\"\n"
+ + " compiler: \"compiler-A\"\n"
+ + " abi_version: \"abi-version-A\"\n"
+ + " abi_libc_version: \"abi-libc-version-A\"\n"
+ + "}\n"
+ // AA-piii is uniquely determined by libc and compiler.
+ + "toolchain {\n"
+ + " toolchain_identifier: \"toolchain-identifier-AA-piii\"\n"
+ + " host_system_name: \"host-system-name-AA\"\n"
+ + " target_system_name: \"target-system-name-AA\"\n"
+ + " target_cpu: \"piii\"\n"
+ + " target_libc: \"target-libc-A\"\n"
+ + " compiler: \"compiler-A\"\n"
+ + " abi_version: \"abi-version-A\"\n"
+ + " abi_libc_version: \"abi-libc-version-A\"\n"
+ + "}\n"
+ + "toolchain {\n"
+ + " toolchain_identifier: \"toolchain-identifier-AB\"\n"
+ + " host_system_name: \"host-system-name-AB\"\n"
+ + " target_system_name: \"target-system-name-AB\"\n"
+ + " target_cpu: \"k8\"\n"
+ + " target_libc: \"target-libc-A\"\n"
+ + " compiler: \"compiler-B\"\n"
+ + " abi_version: \"abi-version-B\"\n"
+ + " abi_libc_version: \"abi-libc-version-A\"\n"
+ + "}\n"
+ + "toolchain {\n"
+ + " toolchain_identifier: \"toolchain-identifier-BA\"\n"
+ + " host_system_name: \"host-system-name-BA\"\n"
+ + " target_system_name: \"target-system-name-BA\"\n"
+ + " target_cpu: \"k8\"\n"
+ + " target_libc: \"target-libc-B\"\n"
+ + " compiler: \"compiler-A\"\n"
+ + " abi_version: \"abi-version-A\"\n"
+ + " abi_libc_version: \"abi-libc-version-B\"\n"
+ + "}\n"
+ + "toolchain {\n"
+ + " toolchain_identifier: \"toolchain-identifier-BB\"\n"
+ + " host_system_name: \"host-system-name-BB\"\n"
+ + " target_system_name: \"target-system-name-BB\"\n"
+ + " target_cpu: \"k8\"\n"
+ + " target_libc: \"target-libc-B\"\n"
+ + " compiler: \"compiler-B\"\n"
+ + " abi_version: \"abi-version-B\"\n"
+ + " abi_libc_version: \"abi-libc-version-B\"\n"
+ + "}\n"
+ + "toolchain {\n"
+ + " toolchain_identifier: \"toolchain-identifier-BC\"\n"
+ + " host_system_name: \"host-system-name-BC\"\n"
+ + " target_system_name: \"target-system-name-BC\"\n"
+ + " target_cpu: \"k8\"\n"
+ + " target_libc: \"target-libc-B\"\n"
+ + " compiler: \"compiler-C\"\n"
+ + " abi_version: \"abi-version-C\"\n"
+ + " abi_libc_version: \"abi-libc-version-B\"\n"
+ + "}");
+
+ // Uses the default toolchain for k8.
+ assertEquals("toolchain-identifier-BB", create(loader, "--cpu=k8").getToolchainIdentifier());
+ // Defaults to --cpu=k8.
+ assertEquals(
+ "toolchain-identifier-BA",
+ create(loader, "--compiler=compiler-A", "--glibc=target-libc-B").getToolchainIdentifier());
+ // Uses the default toolchain for piii.
+ assertEquals(
+ "toolchain-identifier-AA-piii", create(loader, "--cpu=piii").getToolchainIdentifier());
+
+ // We can select the unique piii toolchain with either its compiler or glibc.
+ assertEquals(
+ "toolchain-identifier-AA-piii",
+ create(loader, "--cpu=piii", "--compiler=compiler-A").getToolchainIdentifier());
+ assertEquals(
+ "toolchain-identifier-AA-piii",
+ create(loader, "--cpu=piii", "--glibc=target-libc-A").getToolchainIdentifier());
+
+ // compiler-C uniquely identifies a toolchain, so we can use it.
+ assertEquals(
+ "toolchain-identifier-BC",
+ create(loader, "--compiler=compiler-C").getToolchainIdentifier());
+
+ try {
+ create(loader, "--compiler=nonexistent-compiler");
+ fail("Expected an error that no toolchain matched.");
+ } catch (InvalidConfigurationException e) {
+ assertThat(e)
+ .hasMessage(
+ "No toolchain found for --cpu='k8' --compiler='nonexistent-compiler'. "
+ + "Valid toolchains are: [\n"
+ + " --cpu='k8' --compiler='compiler-A' --glibc='target-libc-A',\n"
+ + " --cpu='piii' --compiler='compiler-A' --glibc='target-libc-A',\n"
+ + " --cpu='k8' --compiler='compiler-B' --glibc='target-libc-A',\n"
+ + " --cpu='k8' --compiler='compiler-A' --glibc='target-libc-B',\n"
+ + " --cpu='k8' --compiler='compiler-B' --glibc='target-libc-B',\n"
+ + " --cpu='k8' --compiler='compiler-C' --glibc='target-libc-B',\n"
+ + "]");
+ }
+
+ try {
+ create(loader, "--glibc=target-libc-A");
+ fail("Expected an error that multiple toolchains matched.");
+ } catch (InvalidConfigurationException e) {
+ assertThat(e)
+ .hasMessage(
+ "Multiple toolchains found for --cpu='k8' --glibc='target-libc-A': [\n"
+ + " --cpu='k8' --compiler='compiler-A' --glibc='target-libc-A',\n"
+ + " --cpu='k8' --compiler='compiler-B' --glibc='target-libc-A',\n"
+ + "]");
+ }
+ }
+
+ private void assertStringStartsWith(String expected, String text) {
+ if (!text.startsWith(expected)) {
+ fail("expected <" + expected + ">, but got <" + text + ">");
+ }
+ }
+
+ public void testIncompleteFile() throws Exception {
+ try {
+ CrosstoolConfigurationLoader.toReleaseConfiguration("/CROSSTOOL", "major_version: \"12\"");
+ fail();
+ } catch (IOException e) {
+ assertStringStartsWith(
+ "Could not read the crosstool configuration file "
+ + "'/CROSSTOOL', because of an incomplete protocol buffer",
+ e.getMessage());
+ }
+ }
+
+ /**
+ * Returns a test crosstool config with the specified tool missing from the tool_path
+ * set. Also allows injection of custom fields.
+ */
+ private static String getConfigWithMissingToolDef(Tool missingTool, String... customFields) {
+ StringBuilder s =
+ new StringBuilder(
+ "major_version: \"12\""
+ + "minor_version: \"0\""
+ + "default_target_cpu: \"cpu\""
+ + "default_toolchain {"
+ + " cpu: \"cpu\""
+ + " toolchain_identifier: \"toolchain-identifier\""
+ + "}"
+ + "toolchain {"
+ + " toolchain_identifier: \"toolchain-identifier\""
+ + " host_system_name: \"host-system-name\""
+ + " target_system_name: \"target-system-name\""
+ + " target_cpu: \"piii\""
+ + " target_libc: \"target-libc\""
+ + " compiler: \"compiler\""
+ + " abi_version: \"abi-version\""
+ + " abi_libc_version: \"abi-libc-version\"");
+
+ for (String customField : customFields) {
+ s.append(customField);
+ }
+ for (Tool tool : Tool.values()) {
+ if (tool != missingTool) {
+ String toolName = tool.getNamePart();
+ s.append(" tool_path { name: \"" + toolName + "\" path: \"path-to-" + toolName + "\" }");
+ }
+ }
+ s.append("}");
+ return s.toString();
+ }
+
+ public void testConfigWithMissingToolDefs() throws Exception {
+ CppConfigurationLoader loader = loader(getConfigWithMissingToolDef(Tool.STRIP));
+ try {
+ create(loader, "--cpu=cpu");
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertThat(e.getMessage()).contains("Tool path for 'strip' is missing");
+ }
+ }
+
+ /**
+ * For a fission-supporting crosstool: check the dwp tool path.
+ */
+ public void testFissionConfigWithMissingDwp() throws Exception {
+ CppConfigurationLoader loader =
+ loader(getConfigWithMissingToolDef(Tool.DWP, "supports_fission: true"));
+ try {
+ create(loader, "--cpu=cpu");
+ fail("Expected failed check on 'dwp' tool path");
+ } catch (IllegalArgumentException e) {
+ assertThat(e.getMessage()).contains("Tool path for 'dwp' is missing");
+ }
+ }
+
+ /**
+ * For a non-fission-supporting crosstool, there's no need to check the dwp tool path.
+ */
+ public void testNonFissionConfigWithMissingDwp() throws Exception {
+ CppConfigurationLoader loader =
+ loader(getConfigWithMissingToolDef(Tool.DWP, "supports_fission: false"));
+ // The following line throws an IllegalArgumentException if an expected tool path is missing.
+ create(loader, "--cpu=cpu");
+ }
+
+ public void testInvalidFile() throws Exception {
+ try {
+ CrosstoolConfigurationLoader.toReleaseConfiguration("/CROSSTOOL", "some xxx : yak \"");
+ fail();
+ } catch (IOException e) {
+ assertStringStartsWith(
+ "Could not read the crosstool configuration file "
+ + "'/CROSSTOOL', because of a parser error",
+ e.getMessage());
+ }
+ }
+
+ /**
+ * Tests interpretation of static_runtimes_filegroup / dynamic_runtimes_filegroup.
+ */
+ public void testCustomRuntimeLibraryPaths() throws Exception {
+ CppConfigurationLoader loader =
+ loader(
+ "major_version: \"v17\""
+ + "minor_version: \"0\""
+ + "default_target_cpu: \"cpu\""
+ + "default_toolchain {"
+ + " cpu: \"piii\""
+ + " toolchain_identifier: \"default-libs\""
+ + "}"
+ + "default_toolchain {"
+ + " cpu: \"k8\""
+ + " toolchain_identifier: \"custom-libs\""
+ + "}"
+ + "toolchain {" // "default-libs": runtime libraries in default locations.
+ + " toolchain_identifier: \"default-libs\""
+ + " host_system_name: \"host-system-name\""
+ + " target_system_name: \"target-system-name\""
+ + " target_cpu: \"piii\""
+ + " target_libc: \"target-libc\""
+ + " compiler: \"compiler\""
+ + " abi_version: \"abi-version\""
+ + " abi_libc_version: \"abi-libc-version\""
+ + " supports_embedded_runtimes: true"
+ + "}\n"
+ + "toolchain {" // "custom-libs" runtime libraries in toolchain-specified locations.
+ + " toolchain_identifier: \"custom-libs\""
+ + " host_system_name: \"host-system-name\""
+ + " target_system_name: \"target-system-name\""
+ + " target_cpu: \"k8\""
+ + " target_libc: \"target-libc\""
+ + " compiler: \"compiler\""
+ + " abi_version: \"abi-version\""
+ + " abi_libc_version: \"abi-libc-version\""
+ + " supports_embedded_runtimes: true"
+ + " static_runtimes_filegroup: \"static-group\""
+ + " dynamic_runtimes_filegroup: \"dynamic-group\""
+ + "}\n");
+
+ final String ctTop = TestConstants.TOOLS_REPOSITORY + "//" + TestConstants.MOCK_CROSSTOOL_PATH;
+
+ CppConfiguration defaultLibs = create(loader, "--cpu=piii");
+ assertEquals(
+ ctTop + ":static-runtime-libs-piii", defaultLibs.getStaticRuntimeLibsLabel().toString());
+ assertEquals(
+ ctTop + ":dynamic-runtime-libs-piii", defaultLibs.getDynamicRuntimeLibsLabel().toString());
+
+ CppConfiguration customLibs = create(loader, "--cpu=k8");
+ assertEquals(ctTop + ":static-group", customLibs.getStaticRuntimeLibsLabel().toString());
+ assertEquals(ctTop + ":dynamic-group", customLibs.getDynamicRuntimeLibsLabel().toString());
+ }
+
+ /*
+ * Crosstools should load fine with or without 'gcov-tool'. Those that define 'gcov-tool'
+ * should also add a make variable.
+ */
+ public void testOptionalGcovTool() throws Exception {
+ // Crosstool with gcov-tool
+ CppConfigurationLoader loader =
+ loaderWithOptionalTool(" tool_path { name: \"gcov-tool\" path: \"path-to-gcov-tool\" }");
+ CppConfiguration cppConfig = create(loader, "--cpu=cpu");
+ ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
+ cppConfig.addGlobalMakeVariables(builder);
+ assertNotNull(builder.build().get("GCOVTOOL"));
+
+ // Crosstool without gcov-tool
+ loader = loaderWithOptionalTool("");
+ cppConfig = create(loader, "--cpu=cpu");
+ builder = ImmutableMap.builder();
+ cppConfig.addGlobalMakeVariables(builder);
+ assertThat(builder.build()).doesNotContainKey("GCOVTOOL");
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/testutil/TestConstants.java b/src/test/java/com/google/devtools/build/lib/testutil/TestConstants.java
index 1c51bd59eb..b6d3e54ee2 100644
--- a/src/test/java/com/google/devtools/build/lib/testutil/TestConstants.java
+++ b/src/test/java/com/google/devtools/build/lib/testutil/TestConstants.java
@@ -68,4 +68,6 @@ public class TestConstants {
public static final String GCC_INCLUDE_PATH = "external/bazel_tools/tools/cpp/gcc3";
public static final String TOOLS_REPOSITORY = "@bazel_tools";
+
+ public static final String MOCK_CROSSTOOL_PATH = "tools/cpp";
}