blob: 6d4f41d501ade85c647d11cb28431f50717426a1 [file] [log] [blame]
// Copyright 2017 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.assertThrows;
import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.config.CompilationMode;
import com.google.devtools.build.lib.analysis.util.AnalysisMock;
import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig;
import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.ToolPath;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/**
* Unit tests for {@code CcToolchainProvider}
*/
@RunWith(JUnit4.class)
public class CcToolchainProviderTest extends BuildViewTestCase {
@Test
public void testSkylarkCallables() throws Exception {
AnalysisMock.get()
.ccSupport()
.setupCrosstool(
mockToolsConfig,
CrosstoolConfig.CToolchain.newBuilder()
.addCompilerFlag("-foo_compiler")
.addCxxFlag("-foo_cxx")
.setBuiltinSysroot("/usr/local/custom-sysroot")
.addToolPath(ToolPath.newBuilder().setName("ar").setPath("foo/ar/path").build())
.buildPartial());
useConfiguration("--cpu=k8", "--force_pic");
scratch.file(
"test/rule.bzl",
"def _impl(ctx):",
" provider = ctx.attr._cc_toolchain[cc_common.CcToolchainInfo]",
" return struct(",
" dirs = provider.built_in_include_directories,",
" link_options = provider.link_options_do_not_use,",
" unfiltered_compiler_options = provider.unfiltered_compiler_options([]),",
" sysroot = provider.sysroot,",
" cpu = provider.cpu,",
" compiler_options = provider.compiler_options(),",
" cxx_options = provider.cxx_options(),",
" ar_executable = provider.ar_executable,",
" use_pic_for_dynamic_libraries = provider.use_pic_for_dynamic_libraries,",
" )",
"",
"my_rule = rule(",
" _impl,",
" attrs = {'_cc_toolchain': attr.label(default=Label('//test:toolchain')) }",
")");
scratch.file("test/BUILD",
"load(':rule.bzl', 'my_rule')",
"cc_toolchain_alias(name = 'toolchain')",
"my_rule(name = 'target')");
ConfiguredTarget ct = getConfiguredTarget("//test:target");
@SuppressWarnings("unchecked")
List<String> compilerOptions = (List<String>) ct.get("compiler_options");
assertThat(compilerOptions).contains("-foo_compiler");
@SuppressWarnings("unchecked")
List<String> cxxOptions = (List<String>) ct.get("cxx_options");
assertThat(cxxOptions).contains("-foo_cxx");
assertThat((String) ct.get("ar_executable")).endsWith("foo/ar/path");
assertThat(ct.get("cpu")).isEqualTo("k8");
assertThat(ct.get("sysroot")).isEqualTo("/usr/local/custom-sysroot");
@SuppressWarnings("unchecked")
List<String> linkOptions = (List<String>) ct.get("link_options");
assertThat(linkOptions).contains("--sysroot=/usr/local/custom-sysroot");
@SuppressWarnings("unchecked")
List<String> unfilteredCompilerOptions = (List<String>) ct.get("unfiltered_compiler_options");
assertThat(unfilteredCompilerOptions).contains("--sysroot=/usr/local/custom-sysroot");
@SuppressWarnings("unchecked")
boolean usePicForDynamicLibraries = (boolean) ct.get("use_pic_for_dynamic_libraries");
assertThat(usePicForDynamicLibraries).isTrue();
}
@Test
public void testDisablingMostlyStaticLinkOptions() throws Exception {
testDisablingLinkingApiMethod("provider.mostly_static_link_options(False)");
}
@Test
public void testDisablingFullyStaticLinkOptions() throws Exception {
testDisablingLinkingApiMethod("provider.fully_static_link_options(True)");
}
@Test
public void testDisablingDynamicLinkOptions() throws Exception {
testDisablingLinkingApiMethod("provider.dynamic_link_options(False)");
}
@Test
public void testDisablingLinkOptions() throws Exception {
testDisablingLinkingApiMethod("provider.link_options_do_not_use");
}
@Test
public void testDisablingMostlyStaticLinkOptionsFromConfiguration() throws Exception {
testDisablingLinkingApiMethod("ctx.fragments.cpp.mostly_static_link_options([], False)");
}
@Test
public void testDisablingFullyStaticLinkOptionsFromConfiguration() throws Exception {
testDisablingLinkingApiMethod("ctx.fragments.cpp.fully_static_link_options([], True)");
}
@Test
public void testDisablingDynamicLinkOptionsFromConfiguration() throws Exception {
testDisablingLinkingApiMethod("ctx.fragments.cpp.dynamic_link_options([], False)");
}
@Test
public void testDisablingLinkOptionsFromConfiguration() throws Exception {
testDisablingLinkingApiMethod("ctx.fragments.cpp.link_options");
}
private void testDisablingLinkingApiMethod(String method) throws Exception {
useConfiguration("--experimental_disable_legacy_cc_linking_api");
scratch.file(
"test/rule.bzl",
"def _impl(ctx):",
" provider = ctx.attr._cc_toolchain[cc_common.CcToolchainInfo]",
" return struct(",
" link_options = " + method + ",",
" )",
"",
"my_rule = rule(",
" _impl,",
" fragments = [ 'cpp' ],",
" attrs = {'_cc_toolchain': attr.label(default=Label('//test:toolchain')) }",
")");
scratch.file(
"test/BUILD",
"load(':rule.bzl', 'my_rule')",
"cc_toolchain_alias(name = 'toolchain')",
"my_rule(name = 'target')");
AssertionError e =
assertThrows(AssertionError.class, () -> getConfiguredTarget("//test:target"));
assertThat(e)
.hasMessageThat()
.contains(
"Skylark APIs accessing linking flags has been removed. "
+ "Use the new API on cc_common.");
}
@Test
public void testDisablingCompilerOptions() throws Exception {
testDisablingCompilationApiMethod("provider.compiler_options()");
}
@Test
public void testDisablingCxxOptions() throws Exception {
testDisablingCompilationApiMethod("provider.cxx_options()");
}
@Test
public void testDisablingCOptions() throws Exception {
testDisablingCompilationApiMethod("provider.c_options()");
}
@Test
public void testDisablingUnfilteredOptions() throws Exception {
testDisablingCompilationApiMethod("provider.unfiltered_compiler_options([])");
}
@Test
public void testDisablingCompilerOptionsFromConfiguration() throws Exception {
testDisablingCompilationApiMethod("ctx.fragments.cpp.compiler_options([])");
}
@Test
public void testDisablingCxxOptionsFromConfiguration() throws Exception {
testDisablingCompilationApiMethod("ctx.fragments.cpp.cxx_options([])");
}
@Test
public void testDisablingCOptionsFromConfiguration() throws Exception {
testDisablingCompilationApiMethod("ctx.fragments.cpp.c_options");
}
@Test
public void testDisablingUnfilteredOptionsFromConfiguration() throws Exception {
testDisablingCompilationApiMethod("ctx.fragments.cpp.unfiltered_compiler_options([])");
}
private void testDisablingCompilationApiMethod(String method) throws Exception {
useConfiguration("--experimental_disable_legacy_cc_compilation_api");
scratch.file(
"test/rule.bzl",
"def _impl(ctx):",
" provider = ctx.attr._cc_toolchain[cc_common.CcToolchainInfo]",
" return struct(",
" compile_options = " + method + ",",
" )",
"",
"my_rule = rule(",
" _impl,",
" fragments = [ 'cpp' ],",
" attrs = {'_cc_toolchain': attr.label(default=Label('//test:toolchain')) }",
")");
scratch.file(
"test/BUILD",
"load(':rule.bzl', 'my_rule')",
"cc_toolchain_alias(name = 'toolchain')",
"my_rule(name = 'target')");
AssertionError e =
assertThrows(AssertionError.class, () -> getConfiguredTarget("//test:target"));
assertThat(e)
.hasMessageThat()
.contains(
"Skylark APIs accessing compilation flags has been removed. "
+ "Use the new API on cc_common.");
}
@Test
public void testDisablingCompilationModeFlags() throws Exception {
AnalysisMock.get()
.ccSupport()
.setupCrosstool(
mockToolsConfig,
"compilation_mode_flags { mode: OPT compiler_flag: '-foo_from_compilation_mode' }",
"compilation_mode_flags { mode: OPT cxx_flag: '-bar_from_compilation_mode' }",
"compilation_mode_flags { mode: OPT linker_flag: '-baz_from_compilation_mode' }");
scratch.file("a/BUILD", "cc_library(name='a', srcs=['a.cc'])");
useConfiguration("-c", "opt");
CcToolchainProvider ccToolchainProvider = getCcToolchainProvider();
assertThat(ccToolchainProvider.getCompilerOptions()).contains("-foo_from_compilation_mode");
assertThat(ccToolchainProvider.getLegacyCxxOptions()).contains("-bar_from_compilation_mode");
assertThat(ccToolchainProvider.getLegacyMostlyStaticLinkFlags(CompilationMode.OPT))
.contains("-baz_from_compilation_mode");
useConfiguration("-c", "opt", "--experimental_disable_compilation_mode_flags");
ccToolchainProvider = getCcToolchainProvider();
assertThat(ccToolchainProvider.getCompilerOptions())
.doesNotContain("-foo_from_compilation_mode");
assertThat(ccToolchainProvider.getLegacyCxxOptions())
.doesNotContain("-bar_from_compilation_mode");
assertThat(ccToolchainProvider.getLegacyMostlyStaticLinkFlags(CompilationMode.OPT))
.doesNotContain("-baz_from_compilation_mode");
}
private CcToolchainProvider getCcToolchainProvider() throws Exception {
ConfiguredTarget target = getConfiguredTarget("//a");
RuleContext ruleContext = getRuleContext(target);
return CppHelper.getToolchainUsingDefaultCcToolchainAttribute(ruleContext);
}
@Test
public void testDisablingLinkingModeFlags() throws Exception {
AnalysisMock.get()
.ccSupport()
.setupCrosstool(
mockToolsConfig,
"linking_mode_flags { mode: MOSTLY_STATIC linker_flag: '-foo_from_linking_mode' }");
scratch.file("a/BUILD", "cc_library(name='a', srcs=['a.cc'])");
useConfiguration();
CcToolchainProvider ccToolchainProvider = getCcToolchainProvider();
assertThat(ccToolchainProvider.getLegacyMostlyStaticLinkFlags(CompilationMode.OPT))
.contains("-foo_from_linking_mode");
useConfiguration("--experimental_disable_linking_mode_flags");
ccToolchainProvider = getCcToolchainProvider();
assertThat(ccToolchainProvider.getLegacyMostlyStaticLinkFlags(CompilationMode.OPT))
.doesNotContain("-foo_from_linking_mode");
}
@Test
public void testDisablingLegacyCrosstoolFields() throws Exception {
AnalysisMock.get()
.ccSupport()
.setupCrosstool(
mockToolsConfig,
"compiler_flag: '-foo_compiler_flag'",
"cxx_flag: '-foo_cxx_flag'",
"unfiltered_cxx_flag: '-foo_unfiltered_cxx_flag'",
"linker_flag: '-foo_linker_flag'",
"dynamic_library_linker_flag: '-foo_dynamic_library_linker_flag'",
"test_only_linker_flag: '-foo_test_only_linker_flag'");
scratch.file("a/BUILD", "cc_library(name='a', srcs=['a.cc'])");
useConfiguration();
CcToolchainProvider ccToolchainProvider = getCcToolchainProvider();
assertThat(ccToolchainProvider.getLegacyCompileOptions()).contains("-foo_compiler_flag");
assertThat(ccToolchainProvider.getLegacyCxxOptions()).contains("-foo_cxx_flag");
assertThat(ccToolchainProvider.getUnfilteredCompilerOptions())
.contains("-foo_unfiltered_cxx_flag");
assertThat(ccToolchainProvider.getLegacyLinkOptions()).contains("-foo_linker_flag");
assertThat(ccToolchainProvider.getSharedLibraryLinkOptions(/* flags= */ ImmutableList.of()))
.contains("-foo_dynamic_library_linker_flag");
assertThat(ccToolchainProvider.getTestOnlyLinkOptions()).contains("-foo_test_only_linker_flag");
useConfiguration("--experimental_disable_legacy_crosstool_fields");
ccToolchainProvider = getCcToolchainProvider();
assertThat(ccToolchainProvider.getLegacyCompileOptions()).doesNotContain("-foo_compiler_flag");
assertThat(ccToolchainProvider.getLegacyCxxOptions()).doesNotContain("-foo_cxx_flag");
assertThat(ccToolchainProvider.getUnfilteredCompilerOptions())
.doesNotContain("-foo_unfiltered_cxx_flag");
assertThat(ccToolchainProvider.getLegacyLinkOptions()).doesNotContain("-foo_linker_flag");
assertThat(ccToolchainProvider.getSharedLibraryLinkOptions(/* flags= */ ImmutableList.of()))
.doesNotContain("-foo_dynamic_library_linker_flag");
assertThat(ccToolchainProvider.getTestOnlyLinkOptions())
.doesNotContain("-foo_test_only_linker_flag");
}
}