blob: a10c1f3eed76cd040703e83cae486ac19e3854b2 [file] [log] [blame]
// 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 static com.google.common.truth.Truth.assertWithMessage;
import static com.google.devtools.build.lib.actions.util.ActionsTestUtil.baseArtifactNames;
import static com.google.devtools.build.lib.actions.util.ActionsTestUtil.baseNamesOf;
import com.google.common.collect.ImmutableList;
import com.google.common.truth.IterableSubject;
import com.google.devtools.build.lib.actions.Action;
import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.util.ActionsTestUtil;
import com.google.devtools.build.lib.analysis.AnalysisUtils;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.OutputGroupInfo;
import com.google.devtools.build.lib.analysis.RunEnvironmentInfo;
import com.google.devtools.build.lib.analysis.actions.SpawnAction;
import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget;
import com.google.devtools.build.lib.analysis.util.AnalysisMock;
import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.PackageIdentifier;
import com.google.devtools.build.lib.cmdline.RepositoryName;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.packages.util.Crosstool.CcToolchainConfig;
import com.google.devtools.build.lib.testutil.TestConstants;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.ModifiedFileSet;
import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.build.lib.vfs.Root;
import java.util.List;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** A test for {@link CcCommon}. */
@RunWith(JUnit4.class)
public class CcCommonTest extends BuildViewTestCase {
private static final String STATIC_LIB = "statically/libstatically.a";
@Before
public final void createBuildFiles() throws Exception {
// Having lots of setUp code leads to bad running time. Don't add anything here!
scratch.file(
"empty/BUILD",
"""
cc_library(name = "emptylib")
cc_binary(name = "emptybinary")
""");
scratch.file(
"foo/BUILD",
"""
cc_library(
name = "foo",
srcs = ["foo.cc"],
)
""");
scratch.file(
"bar/BUILD",
"""
cc_library(
name = "bar",
srcs = ["bar.cc"],
)
""");
}
@Test
public void testSameCcFileTwice() throws Exception {
scratch.file(
"a/BUILD",
"""
cc_library(
name = "a",
srcs = [
"a1",
"a2",
],
)
filegroup(
name = "a1",
srcs = ["a.cc"],
)
filegroup(
name = "a2",
srcs = ["a.cc"],
)
""");
reporter.removeHandler(failFastHandler);
getConfiguredTarget("//a:a");
assertContainsEvent("Artifact 'a/a.cc' is duplicated");
}
@Test
public void testSameHeaderFileTwice() throws Exception {
scratch.file(
"a/BUILD",
"""
package(features = ["parse_headers"])
cc_library(
name = "a",
srcs = [
"a.cc",
"a1",
"a2",
],
)
filegroup(
name = "a1",
srcs = ["a.h"],
)
filegroup(
name = "a2",
srcs = ["a.h"],
)
""");
reporter.removeHandler(failFastHandler);
getConfiguredTarget("//a:a");
assertNoEvents();
}
@Test
public void testEmptyLibrary() throws Exception {
ConfiguredTarget emptylib = getConfiguredTarget("//empty:emptylib");
// We create .a for empty libraries, for simplicity (in Blaze).
// But we avoid creating .so files for empty libraries,
// because those have a potentially significant run-time startup cost.
assertThat(
emptylib
.get(CcInfo.PROVIDER)
.getCcLinkingContext()
.getDynamicLibrariesForRuntime(/* linkingStatically= */ false)
.isEmpty())
.isTrue();
}
@Test
public void testEmptyBinary() throws Exception {
ConfiguredTarget emptybin = getConfiguredTarget("//empty:emptybinary");
assertThat(baseNamesOf(getFilesToBuild(emptybin)))
.isEqualTo("emptybinary");
}
private List<String> getCopts(String target) throws Exception {
ConfiguredTarget cLib = getConfiguredTarget(target);
Artifact object = getOutputGroup(cLib, OutputGroupInfo.FILES_TO_COMPILE).getSingleton();
CppCompileAction compileAction = (CppCompileAction) getGeneratingAction(object);
return compileAction.getCompilerOptions();
}
@Test
public void testCopts() throws Exception {
scratch.file(
"copts/BUILD",
"""
cc_library(
name = "c_lib",
srcs = ["foo.cc"],
copts = [
"-Wmy-warning",
"-frun-faster",
],
)
""");
assertThat(getCopts("//copts:c_lib")).containsAtLeast("-Wmy-warning", "-frun-faster");
}
@Test
public void testCoptsTokenization() throws Exception {
scratch.file(
"copts/BUILD",
"""
cc_library(
name = "c_lib",
srcs = ["foo.cc"],
copts = ["-Wmy-warning -frun-faster"],
)
""");
List<String> copts = getCopts("//copts:c_lib");
assertThat(copts).containsAtLeast("-Wmy-warning", "-frun-faster");
}
@Test
public void testCoptsNoTokenization() throws Exception {
scratch.file(
"copts/BUILD",
"""
package(features = ["no_copts_tokenization"])
cc_library(
name = "c_lib",
srcs = ["foo.cc"],
copts = ["-Wmy-warning -frun-faster"],
)
""");
List<String> copts = getCopts("//copts:c_lib");
assertThat(copts).contains("-Wmy-warning -frun-faster");
}
/**
* Test that we handle ".a" files in cc_library srcs correctly when linking dynamically. In
* particular, if srcs contains only the ".a" file for a library, with no corresponding ".so",
* then we need to link in the ".a" file even when we're linking dynamically. If srcs contains
* both ".a" and ".so" then we should only link in the ".so".
*/
@Test
public void testArchiveInCcLibrarySrcs() throws Exception {
getAnalysisMock()
.ccSupport()
.setupCcToolchainConfig(
mockToolsConfig,
CcToolchainConfig.builder().withFeatures(CppRuleClasses.SUPPORTS_DYNAMIC_LINKER));
useConfiguration("--platforms=" + TestConstants.PLATFORM_LABEL);
ConfiguredTarget archiveInSrcsTest =
scratchConfiguredTarget(
"archive_in_srcs",
"archive_in_srcs_test",
"cc_test(name = 'archive_in_srcs_test',",
" srcs = ['archive_in_srcs_test.cc'],",
" deps = [':archive_in_srcs_lib'],",
" linkstatic = 0,)",
"cc_library(name = 'archive_in_srcs_lib',",
" srcs = ['libstatic.a', 'libboth.a', 'libboth.so'])");
List<String> artifactNames = baseArtifactNames(getLinkerInputs(archiveInSrcsTest));
assertThat(artifactNames).containsAtLeast("libboth.so", "libstatic.a");
assertThat(artifactNames).doesNotContain("libboth.a");
}
private Iterable<Artifact> getLinkerInputs(ConfiguredTarget target) {
Artifact executable = getExecutable(target);
SpawnAction linkAction = (SpawnAction) getGeneratingAction(executable);
return linkAction.getInputs().toList();
}
@Test
public void testDylibLibrarySuffixIsStripped() throws Exception {
ConfiguredTarget archiveInSrcsTest =
scratchConfiguredTarget(
"archive_in_src_darwin",
"archive_in_srcs",
"cc_binary(name = 'archive_in_srcs',",
" srcs = ['libarchive.34.dylib'])");
Artifact executable = getExecutable(archiveInSrcsTest);
SpawnAction linkAction = (SpawnAction) getGeneratingAction(executable);
assertThat(linkAction.getArguments()).contains("-larchive.34");
}
@Test
public void testLinkStaticStatically() throws Exception {
ConfiguredTarget statically =
scratchConfiguredTarget(
"statically",
"statically",
"cc_library(name = 'statically',",
" srcs = ['statically.cc'],",
" linkstatic=1)");
assertThat(
statically
.get(CcInfo.PROVIDER)
.getCcLinkingContext()
.getDynamicLibrariesForRuntime(/* linkingStatically= */ false)
.isEmpty())
.isTrue();
Artifact staticallyDotA = getFilesToBuild(statically).getSingleton();
assertThat(getGeneratingAction(staticallyDotA).getMnemonic()).isEqualTo("CppArchive");
PathFragment dotAPath = staticallyDotA.getExecPath();
assertThat(dotAPath.getPathString()).endsWith(STATIC_LIB);
}
@Test
public void testIsolatedDefines() throws Exception {
ConfiguredTarget isolatedDefines =
scratchConfiguredTarget(
"isolated_defines",
"defineslib",
"cc_library(name = 'defineslib',",
" srcs = ['defines.cc'],",
" defines = ['FOO', 'BAR'])");
assertThat(isolatedDefines.get(CcInfo.PROVIDER).getCcCompilationContext().getDefines())
.containsExactly("FOO", "BAR")
.inOrder();
}
@Test
public void testExpandedDefinesAgainstDeps() throws Exception {
ConfiguredTarget expandedDefines =
scratchConfiguredTarget(
"expanded_defines",
"expand_deps",
"cc_library(name = 'expand_deps',",
" srcs = ['defines.cc'],",
" deps = ['//foo'],",
" defines = ['FOO=$(location //foo)'])");
assertThat(expandedDefines.get(CcInfo.PROVIDER).getCcCompilationContext().getDefines())
.containsExactly(
String.format("FOO=%s/foo/libfoo.a", getRuleContext(expandedDefines).getBinFragment()));
}
@Test
public void testExpandedDefinesAgainstSrcs() throws Exception {
ConfiguredTarget expandedDefines =
scratchConfiguredTarget(
"expanded_defines",
"expand_srcs",
"cc_library(name = 'expand_srcs',",
" srcs = ['defines.cc'],",
" defines = ['FOO=$(location defines.cc)'])");
assertThat(expandedDefines.get(CcInfo.PROVIDER).getCcCompilationContext().getDefines())
.containsExactly("FOO=expanded_defines/defines.cc");
}
@Test
public void testExpandedDefinesAgainstData() throws Exception {
scratch.file("data/BUILD", "filegroup(name = 'data', srcs = ['data.txt'])");
ConfiguredTarget expandedDefines =
scratchConfiguredTarget(
"expanded_defines",
"expand_srcs",
"cc_library(name = 'expand_srcs',",
" srcs = ['defines.cc'],",
" data = ['//data'],",
" defines = ['FOO=$(location //data)'])");
assertThat(expandedDefines.get(CcInfo.PROVIDER).getCcCompilationContext().getDefines())
.containsExactly("FOO=data/data.txt");
}
@Test
public void testExpandedDefinesDuplicateTargets() throws Exception {
scratch.file("data/BUILD", "cc_library(name = 'a', srcs = ['foo.cc'])");
ConfiguredTarget expandedDefines =
scratchConfiguredTarget(
"expanded_defines",
"expand_srcs",
"cc_library(name = 'expand_srcs',",
" srcs = ['defines.cc'],",
" data = ['//data:a'],",
" deps = ['//data:a'],",
" defines = ['FOO=$(location //data:a)'])");
String depPath =
getFilesToBuild(getConfiguredTarget("//data:a")).getSingleton().getExecPathString();
assertThat(expandedDefines.get(CcInfo.PROVIDER).getCcCompilationContext().getDefines())
.containsExactly(String.format("FOO=%s", depPath));
}
@Test
public void testStartEndLib() throws Exception {
getAnalysisMock()
.ccSupport()
.setupCcToolchainConfig(
mockToolsConfig,
CcToolchainConfig.builder().withFeatures(CppRuleClasses.SUPPORTS_START_END_LIB));
useConfiguration(
// Prevent Android from trying to setup ARM crosstool by forcing it on system cpu.
"--fat_apk_cpu=k8", "--start_end_lib");
scratch.file(
"test/BUILD",
"""
cc_library(
name = "lib",
srcs = ["lib.c"],
)
cc_binary(
name = "bin",
srcs = ["bin.c"],
)
""");
ConfiguredTarget target = getConfiguredTarget("//test:bin");
SpawnAction action = (SpawnAction) getGeneratingAction(getExecutable(target));
for (Artifact input : action.getInputs().toList()) {
String name = input.getFilename();
assertThat(!CppFileTypes.ARCHIVE.matches(name) && !CppFileTypes.PIC_ARCHIVE.matches(name))
.isTrue();
}
}
@Test
public void testStartEndLibThroughFeature() throws Exception {
AnalysisMock.get()
.ccSupport()
.setupCcToolchainConfig(
mockToolsConfig,
CcToolchainConfig.builder().withFeatures(CppRuleClasses.SUPPORTS_START_END_LIB));
useConfiguration("--start_end_lib");
scratch.file(
"test/BUILD",
"""
cc_library(
name = "lib",
srcs = ["lib.c"],
)
cc_binary(
name = "bin",
srcs = ["bin.c"],
)
""");
ConfiguredTarget target = getConfiguredTarget("//test:bin");
SpawnAction action = (SpawnAction) getGeneratingAction(getExecutable(target));
for (Artifact input : action.getInputs().toList()) {
String name = input.getFilename();
assertThat(!CppFileTypes.ARCHIVE.matches(name) && !CppFileTypes.PIC_ARCHIVE.matches(name))
.isTrue();
}
}
@Test
public void testTempsWithDifferentExtensions() throws Exception {
AnalysisMock.get()
.ccSupport()
.setupCcToolchainConfig(
mockToolsConfig, CcToolchainConfig.builder().withFeatures(CppRuleClasses.SUPPORTS_PIC));
invalidatePackages();
useConfiguration("--platforms=" + TestConstants.PLATFORM_LABEL, "--save_temps");
scratch.file(
"ananas/BUILD",
"""
cc_library(
name = "ananas",
srcs = [
"1.c",
"2.cc",
"3.cpp",
"4.S",
"5.h",
"6.hpp",
"7.inc",
"8.inl",
"9.tlh",
"A.tli",
],
)
""");
ConfiguredTarget ananas = getConfiguredTarget("//ananas:ananas");
Iterable<String> temps =
ActionsTestUtil.baseArtifactNames(getOutputGroup(ananas, OutputGroupInfo.TEMP_FILES));
assertThat(temps)
.containsExactly(
"1.pic.i", "1.pic.s",
"2.pic.ii", "2.pic.s",
"3.pic.ii", "3.pic.s");
}
/**
* Returns the {@link IterableSubject} for the {@link OutputGroupInfo#TEMP_FILES} generated when
* {@code testTarget} is built for {@code cpu}.
*/
private IterableSubject assertTempsForTarget(String testTarget) throws Exception {
useConfiguration("--save_temps");
ConfiguredTarget target = getConfiguredTarget(testTarget);
assertThat(target).isNotNull();
List<String> temps =
ActionsTestUtil.baseArtifactNames(getOutputGroup(target, OutputGroupInfo.TEMP_FILES));
// Return the IterableSubject for the temp files.
return assertWithMessage("k8").that(temps);
}
@Test
public void testTempsForCcWithPic() throws Exception {
AnalysisMock.get()
.ccSupport()
.setupCcToolchainConfig(
mockToolsConfig, CcToolchainConfig.builder().withFeatures(CppRuleClasses.SUPPORTS_PIC));
invalidatePackages();
assertTempsForTarget("//foo:foo").containsExactly("foo.pic.ii", "foo.pic.s");
}
@Test
public void testTempsForCcWithoutPic() throws Exception {
assertTempsForTarget("//foo:foo").containsExactly("foo.ii", "foo.s");
}
@Test
public void testTempsForCWithPic() throws Exception {
AnalysisMock.get()
.ccSupport()
.setupCcToolchainConfig(
mockToolsConfig, CcToolchainConfig.builder().withFeatures(CppRuleClasses.SUPPORTS_PIC));
invalidatePackages();
useConfiguration();
scratch.file("csrc/BUILD", "cc_library(name='csrc', srcs=['foo.c'])");
assertTempsForTarget("//csrc:csrc").containsExactly("foo.pic.i", "foo.pic.s");
}
@Test
public void testTempsForCWithoutPic() throws Exception {
scratch.file("csrc/BUILD", "cc_library(name='csrc', srcs=['foo.c'])");
assertTempsForTarget("//csrc:csrc").containsExactly("foo.i", "foo.s");
}
@Test
public void testAlwaysLinkYieldsLo() throws Exception {
ConfiguredTarget alwaysLink =
scratchConfiguredTarget(
"always_link",
"always_link",
"cc_library(name = 'always_link',",
" alwayslink = 1,",
" srcs = ['always_link.cc'])");
assertThat(baseNamesOf(getFilesToBuild(alwaysLink))).contains("libalways_link.lo");
}
@Test
public void testPicModeAssembly() throws Exception {
AnalysisMock.get()
.ccSupport()
.setupCcToolchainConfig(
mockToolsConfig,
CcToolchainConfig.builder()
.withFeatures(CppRuleClasses.SUPPORTS_PIC, CppRuleClasses.PIC));
invalidatePackages();
useConfiguration("--platforms=" + TestConstants.PLATFORM_LABEL);
scratch.file("a/BUILD", "cc_library(name='preprocess', srcs=['preprocess.S'])");
List<String> argv = getCppCompileAction("//a:preprocess").getArguments();
assertThat(argv).contains("-fPIC");
}
private CppCompileAction getCppCompileAction(String label) throws Exception {
ConfiguredTarget target = getConfiguredTarget(label);
List<CppCompileAction> compilationSteps =
actionsTestUtil()
.findTransitivePrerequisitesOf(
getFilesToBuild(target).toList().get(0), CppCompileAction.class);
return compilationSteps.get(0);
}
@Test
public void testIsolatedIncludes() throws Exception {
// Tests the (immediate) effect of declaring the includes attribute on a
// cc_library.
scratch.file(
"bang/BUILD",
"""
cc_library(
name = "bang",
srcs = ["bang.cc"],
includes = ["bang_includes"],
)
""");
ConfiguredTarget foo = getConfiguredTarget("//bang:bang");
String includesRoot = "bang/bang_includes";
assertThat(foo.get(CcInfo.PROVIDER).getCcCompilationContext().getSystemIncludeDirs())
.containsAtLeast(
PathFragment.create(includesRoot),
targetConfig.getGenfilesFragment(RepositoryName.MAIN).getRelative(includesRoot));
}
@Test
public void testDisabledGenfilesDontShowUpInSystemIncludePaths() throws Exception {
scratch.file(
"bang/BUILD",
"""
cc_library(
name = "bang",
srcs = ["bang.cc"],
includes = ["bang_includes"],
)
""");
String includesRoot = "bang/bang_includes";
useConfiguration("--noincompatible_merge_genfiles_directory");
ConfiguredTarget foo = getConfiguredTarget("//bang:bang");
PathFragment genfilesDir =
targetConfig.getGenfilesFragment(RepositoryName.MAIN).getRelative(includesRoot);
assertThat(foo.get(CcInfo.PROVIDER).getCcCompilationContext().getSystemIncludeDirs())
.contains(genfilesDir);
useConfiguration("--incompatible_merge_genfiles_directory");
foo = getConfiguredTarget("//bang:bang");
assertThat(foo.get(CcInfo.PROVIDER).getCcCompilationContext().getSystemIncludeDirs())
.doesNotContain(genfilesDir);
}
@Test
public void testUseIsystemForIncludes() throws Exception {
// Tests the effect of --use_isystem_for_includes.
useConfiguration("--incompatible_merge_genfiles_directory=false");
scratch.file(
"no_includes/BUILD",
"""
cc_library(
name = "no_includes",
srcs = ["no_includes.cc"],
)
""");
ConfiguredTarget noIncludes = getConfiguredTarget("//no_includes:no_includes");
scratch.file(
"bang/BUILD",
"""
cc_library(
name = "bang",
srcs = ["bang.cc"],
includes = ["bang_includes"],
)
""");
ConfiguredTarget foo = getConfiguredTarget("//bang:bang");
String includesRoot = "bang/bang_includes";
List<PathFragment> expected =
new ImmutableList.Builder<PathFragment>()
.addAll(
noIncludes.get(CcInfo.PROVIDER).getCcCompilationContext().getSystemIncludeDirs())
.add(PathFragment.create(includesRoot))
.add(targetConfig.getGenfilesFragment(RepositoryName.MAIN).getRelative(includesRoot))
.add(targetConfig.getBinFragment(RepositoryName.MAIN).getRelative(includesRoot))
.build();
assertThat(foo.get(CcInfo.PROVIDER).getCcCompilationContext().getSystemIncludeDirs())
.containsExactlyElementsIn(expected);
}
@Test
public void testCcTestDisallowsAlwaysLink() throws Exception {
scratch.file(
"cc/common/BUILD",
"""
cc_library(
name = "lib1",
srcs = ["foo1.cc"],
deps = ["//left"],
)
cc_test(
name = "testlib",
deps = [":lib1"],
alwayslink = 1,
)
""");
reporter.removeHandler(failFastHandler);
getPackageManager().getPackage(reporter, PackageIdentifier.createInMainRepo("cc/common"));
assertContainsEvent(
"//cc/common:testlib: no such attribute 'alwayslink'" + " in 'cc_test' rule");
}
@Test
public void testCcTestBuiltWithFissionHasDwp() throws Exception {
// Tests that cc_tests built statically and with Fission will have the .dwp file
// in their runfiles.
getAnalysisMock()
.ccSupport()
.setupCcToolchainConfig(
mockToolsConfig,
CcToolchainConfig.builder().withFeatures(CppRuleClasses.PER_OBJECT_DEBUG_INFO));
useConfiguration(
"--platforms=" + TestConstants.PLATFORM_LABEL,
"--build_test_dwp",
"--dynamic_mode=off",
"--fission=yes");
ConfiguredTarget target =
scratchConfiguredTarget(
"mypackage", "mytest", "cc_test(name = 'mytest', srcs = ['mytest.cc'])");
NestedSet<Artifact> runfiles = collectRunfiles(target);
assertThat(baseArtifactNames(runfiles)).contains("mytest.dwp");
}
@Test
@Ignore("(b/484481656): Starlark does not support warnings.")
public void testCcLibraryBadIncludesWarnedAndIgnored() throws Exception {
checkWarning(
"badincludes",
"flaky_lib",
// message:
"in includes attribute of cc_library rule //badincludes:flaky_lib: "
+ "ignoring invalid absolute path '//third_party/procps/proc'",
// build file:
"cc_library(name = 'flaky_lib',",
" srcs = [ 'ok.cc' ],",
" includes = [ '//third_party/procps/proc' ])");
}
@Test
@Ignore("(b/484481656): Starlark does not support warnings.")
public void testCcLibraryUplevelIncludesWarned() throws Exception {
checkWarning(
"third_party/uplevel",
"lib",
// message:
"in includes attribute of cc_library rule //third_party/uplevel:lib: '../bar' resolves to "
+ "'third_party/bar' not below the relative path of its package 'third_party/uplevel'. "
+ "This will be an error in the future",
// build file:
"licenses(['unencumbered'])",
"cc_library(name = 'lib',",
" srcs = ['foo.cc'],",
" includes = ['../bar'])");
}
@Test
public void testCcLibraryThirdPartyIncludesNotWarned() throws Exception {
eventCollector.clear();
ConfiguredTarget target =
scratchConfiguredTarget(
"third_party/pkg",
"lib",
"licenses(['unencumbered'])",
"cc_library(name = 'lib',",
" srcs = ['foo.cc'],",
" includes = ['./'])");
assertThat(view.hasErrors(target)).isFalse();
assertNoEvents();
}
@Test
public void testCcLibraryExternalIncludesNotWarned() throws Exception {
eventCollector.clear();
FileSystemUtils.appendIsoLatin1(
scratch.resolve("WORKSPACE"),
"local_repository(",
" name = 'pkg',",
" path = '/foo')");
getSkyframeExecutor()
.invalidateFilesUnderPathForTesting(
reporter,
new ModifiedFileSet.Builder().modify(PathFragment.create("WORKSPACE")).build(),
Root.fromPath(rootDirectory));
scratch.resolve("/foo/bar").createDirectoryAndParents();
scratch.file("/foo/WORKSPACE", "workspace(name = 'pkg')");
scratch.file(
"/foo/bar/BUILD",
"""
cc_library(
name = "lib",
srcs = ["foo.cc"],
includes = ["./"],
)
""");
Label label = Label.parseCanonical("@pkg//bar:lib");
ConfiguredTarget target = view.getConfiguredTargetForTesting(reporter, label, targetConfig);
assertThat(view.hasErrors(target)).isFalse();
assertNoEvents();
}
@Test
public void testCcLibraryRootIncludesError() throws Exception {
checkError(
"third_party/root",
"lib",
// message:
"attribute includes: '../..' resolves to the "
+ "workspace root, which would allow this rule and all of its transitive dependents to "
+ "include any file in your workspace. Please include only what you need",
// build file:
"licenses(['unencumbered'])",
"cc_library(name = 'lib',",
" srcs = ['foo.cc'],",
" includes = ['../..'])");
}
@Test
public void testStaticallyLinkedBinaryNeedsSharedObject() throws Exception {
scratch.file(
"third_party/sophos/BUILD",
"""
licenses(["notice"])
cc_library(
name = "savi",
srcs = ["lib/libsavi.so"],
)
""");
ConfiguredTarget wrapsophos =
scratchConfiguredTarget(
"quality/malware/support",
"wrapsophos",
"cc_library(name = 'sophosengine',",
" srcs = [ 'sophosengine.cc' ],",
" deps = [ '//third_party/sophos:savi' ])",
"cc_binary(name = 'wrapsophos',",
" srcs = [ 'wrapsophos.cc' ],",
" deps = [ ':sophosengine' ],",
" linkstatic=1)");
List<String> artifactNames = baseArtifactNames(getLinkerInputs(wrapsophos));
assertThat(artifactNames).contains("libsavi.so");
}
@Test
public void testExpandLabelInLinkoptsAgainstSrc() throws Exception {
scratch.file(
"coolthing/BUILD",
"""
genrule(
name = "build-that",
srcs = ["foo"],
outs = ["nicelib.a"],
cmd = "cat $< > $@",
)
""");
// In reality the linkopts might contain several externally-provided
// '.a' files with cyclic dependencies amongst them, but in this test
// it suffices to show that one label in linkopts was resolved.
scratch.file(
"myapp/BUILD",
"""
cc_binary(
name = "myapp",
srcs = ["//coolthing:nicelib.a"],
linkopts = ["//coolthing:nicelib.a"],
)
""");
ConfiguredTarget theLib = getConfiguredTarget("//coolthing:build-that");
ConfiguredTarget theApp = getConfiguredTarget("//myapp:myapp");
// make sure we did not print warnings about the linkopt
assertNoEvents();
// make sure the binary is dependent on the static lib
Action linkAction = getGeneratingAction(getFilesToBuild(theApp).getSingleton());
ImmutableList<Artifact> filesToBuild = getFilesToBuild(theLib).toList();
assertThat(linkAction.getInputs().toSet()).containsAtLeastElementsIn(filesToBuild);
}
@Test
public void testCcLibraryWithDashStaticOnDarwin() throws Exception {
getAnalysisMock().ccSupport().setupCcToolchainConfigForCpu(mockToolsConfig, "darwin_x86_64");
mockToolsConfig.create(
"platforms/BUILD",
"platform(",
" name = 'darwin_x86_64',",
" constraint_values = [",
" '" + TestConstants.CONSTRAINTS_PACKAGE_ROOT + "os:macos',",
" '" + TestConstants.CONSTRAINTS_PACKAGE_ROOT + "cpu:x86_64',",
" ],",
")");
useConfiguration("--cpu=darwin_x86_64", "--platforms=//platforms:darwin_x86_64");
checkError(
"badlib",
"lib_with_dash_static",
// message:
"in linkopts attribute of cc_library rule @@//badlib:lib_with_dash_static: "
+ "Apple builds do not support statically linked binaries",
// build file:
"cc_library(name = 'lib_with_dash_static',",
" srcs = [ 'ok.cc' ],",
" linkopts = [ '-static' ])");
}
@Test
public void testStampTests() throws Exception {
scratch.file(
"test/BUILD",
"""
cc_test(
name = "a",
srcs = ["a.cc"],
)
cc_test(
name = "b",
srcs = ["b.cc"],
stamp = 0,
)
cc_test(
name = "c",
srcs = ["c.cc"],
stamp = 1,
)
cc_binary(
name = "d",
srcs = ["d.cc"],
)
cc_binary(
name = "e",
srcs = ["e.cc"],
stamp = 0,
)
cc_binary(
name = "f",
srcs = ["f.cc"],
stamp = 1,
)
""");
assertStamping(false, "//test:a");
assertStamping(false, "//test:b");
assertStamping(true, "//test:c");
assertStamping(true, "//test:d");
assertStamping(false, "//test:e");
assertStamping(true, "//test:f");
useConfiguration("--stamp");
assertStamping(false, "//test:a");
assertStamping(false, "//test:b");
assertStamping(true, "//test:c");
assertStamping(true, "//test:d");
assertStamping(false, "//test:e");
assertStamping(true, "//test:f");
useConfiguration("--nostamp");
assertStamping(false, "//test:a");
assertStamping(false, "//test:b");
assertStamping(true, "//test:c");
assertStamping(false, "//test:d");
assertStamping(false, "//test:e");
assertStamping(true, "//test:f");
}
private void assertStamping(boolean enabled, String label) throws Exception {
assertThat(AnalysisUtils.isStampingEnabled(getRuleContext(getConfiguredTarget(label))))
.isEqualTo(enabled);
}
@Test
public void testIncludeRelativeHeadersAboveExecRoot() throws Exception {
checkError(
"test",
"bad_relative_include",
"Path references a path above the execution root.",
"cc_library(name='bad_relative_include', srcs=[], includes=['../..'])");
}
@Test
@Ignore("(b/484481656): Starlark does not support warnings.")
public void testIncludeAbsoluteHeaders() throws Exception {
checkWarning(
"test",
"bad_absolute_include",
"ignoring invalid absolute path",
"cc_library(name='bad_absolute_include', srcs=[], includes=['/usr/include/'])");
}
/** Tests that shared libraries of the form "libfoo.so.1.2" are permitted within "srcs". */
@Test
public void testVersionedSharedLibrarySupport() throws Exception {
ConfiguredTarget target =
scratchConfiguredTarget(
"mypackage",
"mybinary",
"cc_binary(name = 'mybinary',",
" srcs = ['mybinary.cc'],",
" deps = [':mylib'])",
"cc_library(name = 'mylib',",
" srcs = ['libshared.so', 'libshared.so.1.1', 'foo.cc'])");
List<String> artifactNames = baseArtifactNames(getLinkerInputs(target));
assertThat(artifactNames).containsAtLeast("libshared.so", "libshared.so.1.1");
}
@Test
public void testLibraryInHdrs() throws Exception {
scratchConfiguredTarget("a", "a",
"cc_library(name='a', srcs=['a.cc'], hdrs=[':b'])",
"cc_library(name='b', srcs=['b.cc'])");
}
@Test
public void testExpandedLinkopts() throws Exception {
scratch.file(
"a/BUILD",
"""
genrule(
name = "linker",
outs = ["a.lds"],
cmd = "generate",
)
cc_binary(
name = "bin",
srcs = ["b.cc"],
linkopts = ["-Wl,@$(location a.lds)"],
deps = ["a.lds"],
)
""");
ConfiguredTarget target = getConfiguredTarget("//a:bin");
SpawnAction action = (SpawnAction) getGeneratingAction(getFilesToBuild(target).getSingleton());
assertThat(action.getArguments())
.contains(
String.format(
"-Wl,@%s/a/a.lds",
getTargetConfiguration()
.getGenfilesDirectory(RepositoryName.MAIN)
.getExecPath()
.getPathString()));
}
@Test
public void testExpandedEnv() throws Exception {
scratch.file(
"a/BUILD",
"""
genrule(
name = "linker",
outs = ["a.lds"],
cmd = "generate",
)
cc_test(
name = "bin_test",
srcs = ["b.cc"],
env = {"SOME_KEY": "-Wl,@$(location a.lds)"},
deps = ["a.lds"],
)
""");
ConfiguredTarget starlarkTarget = getConfiguredTarget("//a:bin_test");
RunEnvironmentInfo provider = starlarkTarget.get(RunEnvironmentInfo.PROVIDER);
assertThat(provider.getEnvironment()).containsEntry("SOME_KEY", "-Wl,@a/a.lds");
}
@Test
public void testProvidesLinkerScriptToLinkAction() throws Exception {
scratch.file(
"a/BUILD",
"""
cc_binary(
name = "bin",
srcs = ["b.cc"],
linkopts = ["-Wl,@$(location a.lds)"],
deps = ["a.lds"],
)
""");
ConfiguredTarget target = getConfiguredTarget("//a:bin");
SpawnAction action = (SpawnAction) getGeneratingAction(getFilesToBuild(target).getSingleton());
NestedSet<Artifact> linkInputs = action.getInputs();
assertThat(ActionsTestUtil.baseArtifactNames(linkInputs)).contains("a.lds");
}
@Test
public void testIncludeManglingSmoke() throws Exception {
scratch.file(
"third_party/a/BUILD",
"""
licenses(["notice"])
cc_library(
name = "a",
hdrs = ["v1/b/c.h"],
include_prefix = "lib",
strip_include_prefix = "v1",
)
""");
ConfiguredTarget lib = getConfiguredTarget("//third_party/a");
CcCompilationContext ccCompilationContext = lib.get(CcInfo.PROVIDER).getCcCompilationContext();
assertThat(ActionsTestUtil.prettyArtifactNames(ccCompilationContext.getDeclaredIncludeSrcs()))
.containsExactly("third_party/a/_virtual_includes/a/lib/b/c.h", "third_party/a/v1/b/c.h");
assertThat(ccCompilationContext.getIncludeDirs())
.containsExactly(
getTargetConfiguration()
.getBinFragment(RepositoryName.MAIN)
.getRelative("third_party/a/_virtual_includes/a"));
}
@Test
public void testUpLevelReferencesInIncludeMangling() throws Exception {
scratch.file(
"third_party/a/BUILD",
"""
licenses(["notice"])
cc_library(
name = "sip",
srcs = ["a.h"],
strip_include_prefix = "a/../b",
)
cc_library(
name = "ip",
srcs = ["a.h"],
include_prefix = "a/../b",
)
cc_library(
name = "ipa",
srcs = ["a.h"],
include_prefix = "/foo",
)
""");
reporter.removeHandler(failFastHandler);
getConfiguredTarget("//third_party/a:sip");
assertContainsEvent("should not contain uplevel references");
eventCollector.clear();
getConfiguredTarget("//third_party/a:ip");
assertContainsEvent("should not contain uplevel references");
eventCollector.clear();
getConfiguredTarget("//third_party/a:ipa");
assertContainsEvent("should be a relative path");
}
@Test
public void testAbsoluteAndRelativeStripPrefix() throws Exception {
scratch.file(
"third_party/a/BUILD",
"""
licenses(["notice"])
cc_library(
name = "relative",
hdrs = ["v1/b.h"],
strip_include_prefix = "v1",
)
cc_library(
name = "absolute",
hdrs = ["v1/b.h"],
strip_include_prefix = "/third_party",
)
""");
CcCompilationContext relative =
getConfiguredTarget("//third_party/a:relative")
.get(CcInfo.PROVIDER)
.getCcCompilationContext();
CcCompilationContext absolute =
getConfiguredTarget("//third_party/a:absolute")
.get(CcInfo.PROVIDER)
.getCcCompilationContext();
assertThat(ActionsTestUtil.prettyArtifactNames(relative.getDeclaredIncludeSrcs()))
.containsExactly("third_party/a/_virtual_includes/relative/b.h", "third_party/a/v1/b.h");
assertThat(ActionsTestUtil.prettyArtifactNames(absolute.getDeclaredIncludeSrcs()))
.containsExactly(
"third_party/a/_virtual_includes/absolute/a/v1/b.h", "third_party/a/v1/b.h");
}
@Test
public void testEmptyPackageStripPrefix() throws Exception {
if (!AnalysisMock.get().isThisBazel()) {
return;
}
scratch.file(
"BUILD",
"licenses(['notice'])",
"cc_library(name='a', hdrs=['b.h'], strip_include_prefix='.')");
CcCompilationContext ccContext =
getConfiguredTarget("//:a").get(CcInfo.PROVIDER).getCcCompilationContext();
assertThat(ActionsTestUtil.prettyArtifactNames(ccContext.getDeclaredIncludeSrcs()))
.containsExactly("b.h");
}
@Test
public void testArtifactNotUnderStripPrefix() throws Exception {
scratch.file(
"third_party/a/BUILD",
"""
licenses(["notice"])
cc_library(
name = "a",
hdrs = ["v1/b.h"],
strip_include_prefix = "v2",
)
""");
reporter.removeHandler(failFastHandler);
getConfiguredTarget("//third_party/a:a");
assertContainsEvent(
"header 'third_party/a/v1/b.h' is not under the specified strip prefix 'third_party/a/v2'");
}
@Test
public void testSymlinkActionIsNotRegisteredWhenIncludePrefixDoesntChangePath() throws Exception {
scratch.file(
"third_party/BUILD",
"""
licenses(["notice"])
cc_library(
name = "a",
hdrs = ["a.h"],
include_prefix = "third_party",
)
""");
CcCompilationContext ccCompilationContext =
getConfiguredTarget("//third_party:a").get(CcInfo.PROVIDER).getCcCompilationContext();
assertThat(ActionsTestUtil.prettyArtifactNames(ccCompilationContext.getDeclaredIncludeSrcs()))
.doesNotContain("third_party/_virtual_includes/a/third_party/a.h");
}
@Test
public void
testConfigureFeaturesDoesntCrashOnCollidingFeaturesExceptionButReportsRuleErrorCleanly()
throws Exception {
reporter.removeHandler(failFastHandler);
getAnalysisMock()
.ccSupport()
.setupCcToolchainConfig(
mockToolsConfig,
CcToolchainConfig.builder().withFeatures("same_symbol_provided_configuration"));
useConfiguration("--features=a1", "--features=a2");
scratch.file("x/BUILD", "cc_library(name = 'foo', srcs = ['a.cc'])");
scratch.file("x/a.cc");
getConfiguredTarget("//x:foo");
assertContainsEvent("Symbol a is provided by all of the following features: a1 a2");
}
@Test
public void testSupportsPicFeatureResultsInPICObjectGenerated() throws Exception {
getAnalysisMock()
.ccSupport()
.setupCcToolchainConfig(
mockToolsConfig,
CcToolchainConfig.builder()
.withFeatures(CppRuleClasses.NO_LEGACY_FEATURES, CppRuleClasses.SUPPORTS_PIC)
.withActionConfigs(
CppActionNames.CPP_LINK_STATIC_LIBRARY,
CppActionNames.CPP_COMPILE,
CppActionNames.CPP_LINK_NODEPS_DYNAMIC_LIBRARY));
useConfiguration("--platforms=" + TestConstants.PLATFORM_LABEL);
scratch.file("x/BUILD", "cc_library(name = 'foo', srcs = ['a.cc'])");
scratch.file("x/a.cc");
RuleConfiguredTarget ccLibrary = (RuleConfiguredTarget) getConfiguredTarget("//x:foo");
ImmutableList<ActionAnalysisMetadata> actions = ccLibrary.getActions();
ImmutableList<String> outputs =
actions.stream()
.map(ActionAnalysisMetadata::getPrimaryOutput)
.map(Artifact::getFilename)
.collect(ImmutableList.toImmutableList());
assertThat(outputs).contains("a.pic.o");
}
@Test
public void testWhenSupportsPicDisabledPICObjectAreNotGenerated() throws Exception {
getAnalysisMock()
.ccSupport()
.setupCcToolchainConfig(
mockToolsConfig,
CcToolchainConfig.builder()
.withFeatures(CppRuleClasses.NO_LEGACY_FEATURES)
.withActionConfigs(
CppActionNames.CPP_LINK_STATIC_LIBRARY,
CppActionNames.CPP_COMPILE,
CppActionNames.CPP_LINK_NODEPS_DYNAMIC_LIBRARY));
useConfiguration("--features=-supports_pic");
scratch.file("x/BUILD", "cc_library(name = 'foo', srcs = ['a.cc'])");
scratch.file("x/a.cc");
RuleConfiguredTarget ccLibrary = (RuleConfiguredTarget) getConfiguredTarget("//x:foo");
ImmutableList<ActionAnalysisMetadata> actions = ccLibrary.getActions();
ImmutableList<String> outputs =
actions.stream()
.map(ActionAnalysisMetadata::getPrimaryOutput)
.map(Artifact::getFilename)
.collect(ImmutableList.toImmutableList());
assertThat(outputs).doesNotContain("a.pic.o");
}
@Test
public void testWhenSupportsPicDisabledButForcePicSetPICAreGenerated() throws Exception {
getAnalysisMock()
.ccSupport()
.setupCcToolchainConfig(
mockToolsConfig,
CcToolchainConfig.builder()
.withFeatures(CppRuleClasses.NO_LEGACY_FEATURES, CppRuleClasses.SUPPORTS_PIC)
.withActionConfigs(
CppActionNames.CPP_LINK_STATIC_LIBRARY,
CppActionNames.CPP_COMPILE,
CppActionNames.CPP_LINK_NODEPS_DYNAMIC_LIBRARY));
useConfiguration("--force_pic", "--platforms=" + TestConstants.PLATFORM_LABEL);
scratch.file("x/BUILD", "cc_library(name = 'foo', srcs = ['a.cc'])");
scratch.file("x/a.cc");
RuleConfiguredTarget ccLibrary = (RuleConfiguredTarget) getConfiguredTarget("//x:foo");
ImmutableList<ActionAnalysisMetadata> actions = ccLibrary.getActions();
ImmutableList<String> outputs =
actions.stream()
.map(ActionAnalysisMetadata::getPrimaryOutput)
.map(Artifact::getFilename)
.collect(ImmutableList.toImmutableList());
assertThat(outputs).contains("a.pic.o");
}
@Test
public void testPreferPicForOptBinaryFeature() throws Exception {
getAnalysisMock()
.ccSupport()
.setupCcToolchainConfig(
mockToolsConfig,
CcToolchainConfig.builder()
.withFeatures(
CppRuleClasses.NO_LEGACY_FEATURES,
CppRuleClasses.SUPPORTS_PIC,
CppRuleClasses.PREFER_PIC_FOR_OPT_BINARIES)
.withActionConfigs(
CppActionNames.CPP_LINK_STATIC_LIBRARY,
CppActionNames.CPP_COMPILE,
CppActionNames.CPP_LINK_NODEPS_DYNAMIC_LIBRARY));
useConfiguration("--platforms=" + TestConstants.PLATFORM_LABEL, "--compilation_mode=opt");
scratch.file("x/BUILD", "cc_library(name = 'foo', srcs = ['a.cc'])");
scratch.file("x/a.cc");
RuleConfiguredTarget ccLibrary = (RuleConfiguredTarget) getConfiguredTarget("//x:foo");
ImmutableList<ActionAnalysisMetadata> actions = ccLibrary.getActions();
ImmutableList<String> outputs =
actions.stream()
.map(ActionAnalysisMetadata::getPrimaryOutput)
.map(Artifact::getFilename)
.collect(ImmutableList.toImmutableList());
assertThat(outputs).doesNotContain("a.o");
assertThat(outputs).contains("a.pic.o");
}
@Test
public void testPreferPicForOptBinaryFeatureNeedsPicSupport() throws Exception {
getAnalysisMock()
.ccSupport()
.setupCcToolchainConfig(
mockToolsConfig,
CcToolchainConfig.builder()
.withFeatures(
CppRuleClasses.NO_LEGACY_FEATURES, CppRuleClasses.PREFER_PIC_FOR_OPT_BINARIES)
.withActionConfigs(
CppActionNames.CPP_LINK_STATIC_LIBRARY,
CppActionNames.CPP_COMPILE,
CppActionNames.CPP_LINK_NODEPS_DYNAMIC_LIBRARY));
useConfiguration("--platforms=" + TestConstants.PLATFORM_LABEL, "--compilation_mode=opt");
scratch.file("x/BUILD", "cc_library(name = 'foo', srcs = ['a.cc'])");
scratch.file("x/a.cc");
RuleConfiguredTarget ccLibrary = (RuleConfiguredTarget) getConfiguredTarget("//x:foo");
ImmutableList<ActionAnalysisMetadata> actions = ccLibrary.getActions();
ImmutableList<String> outputs =
actions.stream()
.map(ActionAnalysisMetadata::getPrimaryOutput)
.map(Artifact::getFilename)
.collect(ImmutableList.toImmutableList());
assertThat(outputs).doesNotContain("a.pic.o");
assertThat(outputs).contains("a.o");
}
@Test
public void testWhenSupportsPicNotPresentAndForcePicPassedIsError() throws Exception {
reporter.removeHandler(failFastHandler);
getAnalysisMock()
.ccSupport()
.setupCcToolchainConfig(
mockToolsConfig,
CcToolchainConfig.builder()
.withFeatures(CppRuleClasses.NO_LEGACY_FEATURES)
.withActionConfigs(
CppActionNames.CPP_LINK_STATIC_LIBRARY,
CppActionNames.CPP_LINK_NODEPS_DYNAMIC_LIBRARY,
CppActionNames.CPP_COMPILE));
useConfiguration("--force_pic", "--features=-supports_pic");
scratch.file("x/BUILD", "cc_library(name = 'foo', srcs = ['a.cc'])");
scratch.file("x/a.cc");
getConfiguredTarget("//x:foo");
assertContainsEvent(
"PIC compilation is requested but the toolchain does not support it"
+ " (feature named 'supports_pic' is not enabled");
}
@Test
public void testCompilationParameterFile() throws Exception {
AnalysisMock.get()
.ccSupport()
.setupCcToolchainConfig(
mockToolsConfig,
CcToolchainConfig.builder().withFeatures(CppRuleClasses.COMPILER_PARAM_FILE));
scratch.file("a/BUILD", "cc_library(name='foo', srcs=['foo.cc'])");
CppCompileAction cppCompileAction = getCppCompileAction("//a:foo");
assertThat(
cppCompileAction.getArguments().stream()
.map(x -> removeOutDirectory(x))
.collect(ImmutableList.toImmutableList()))
.containsExactly("/usr/bin/mock-gcc", "@/k8-fastbuild/bin/a/_objs/foo/foo.o.params");
}
@Test
public void testCppCompileActionArgvIgnoreParamFile() throws Exception {
AnalysisMock.get()
.ccSupport()
.setupCcToolchainConfig(
mockToolsConfig,
CcToolchainConfig.builder().withFeatures(CppRuleClasses.COMPILER_PARAM_FILE));
scratch.file("a/BUILD", "cc_library(name='foo', srcs=['foo.cc'])");
CppCompileAction cppCompileAction = getCppCompileAction("//a:foo");
ImmutableList<String> argv =
cppCompileAction.getStarlarkArgv().stream()
.map(x -> removeOutDirectory(x))
.collect(ImmutableList.toImmutableList());
assertThat(argv).contains("/usr/bin/mock-gcc");
assertThat(argv).contains("-o");
assertThat(argv).contains("/k8-fastbuild/bin/a/_objs/foo/foo.o");
}
@Test
public void testClangClParameters() throws Exception {
if (!AnalysisMock.get().isThisBazel()) {
return;
}
AnalysisMock.get()
.ccSupport()
.setupCcToolchainConfig(
mockToolsConfig,
CcToolchainConfig.builder()
.withFeatures(
CppRuleClasses.TARGETS_WINDOWS,
CppRuleClasses.COPY_DYNAMIC_LIBRARIES_TO_BINARY));
scratch.file(
"a/BUILD",
"""
cc_library(
name = "foo",
srcs = ["foo.cc"],
copts = [
"/imsvc",
"SYSTEM_INCLUDE_1",
"-imsvcSYSTEM_INCLUDE_2",
"/ISTANDARD_INCLUDE",
"/FI",
"forced_include_1",
"-FIforced_include_2",
],
)
""");
CppCompileAction cppCompileAction = getCppCompileAction("//a:foo");
PathFragment systemInclude1 = PathFragment.create("SYSTEM_INCLUDE_1");
PathFragment systemInclude2 = PathFragment.create("SYSTEM_INCLUDE_2");
PathFragment standardInclude = PathFragment.create("STANDARD_INCLUDE");
assertThat(cppCompileAction.getSystemIncludeDirs()).contains(systemInclude1);
assertThat(cppCompileAction.getSystemIncludeDirs()).contains(systemInclude2);
assertThat(cppCompileAction.getSystemIncludeDirs()).doesNotContain(standardInclude);
assertThat(cppCompileAction.getIncludeDirs()).doesNotContain(systemInclude1);
assertThat(cppCompileAction.getIncludeDirs()).doesNotContain(systemInclude2);
assertThat(cppCompileAction.getIncludeDirs()).contains(standardInclude);
}
@Test
public void testCcLibraryLoadedThroughMacro() throws Exception {
setupTestCcLibraryLoadedThroughMacro(/* loadMacro= */ true);
assertThat(getConfiguredTarget("//a:a")).isNotNull();
assertNoEvents();
}
@Test
public void testCcLibraryNotLoadedThroughMacro() throws Exception {
setupTestCcLibraryLoadedThroughMacro(/* loadMacro= */ false);
reporter.removeHandler(failFastHandler);
assertThat(getConfiguredTarget("//a:a")).isNotNull();
}
private void setupTestCcLibraryLoadedThroughMacro(boolean loadMacro) throws Exception {
scratch.file(
"a/BUILD",
getAnalysisMock().ccSupport().getMacroLoadStatement(loadMacro, "cc_library"),
"cc_library(name='a', srcs=['a.cc'])");
}
@Test
public void testFdoProfileLoadedThroughMacro() throws Exception {
setuptestFdoProfileLoadedThroughMacro(/* loadMacro= */ true);
assertThat(getConfiguredTarget("//a:a")).isNotNull();
assertNoEvents();
}
private void setuptestFdoProfileLoadedThroughMacro(boolean loadMacro) throws Exception {
scratch.file(
"a/BUILD",
getAnalysisMock().ccSupport().getMacroLoadStatement(loadMacro, "fdo_profile"),
"fdo_profile(name='a', profile='profile.xfdo')");
}
@Test
public void testFdoPrefetchHintsLoadedThroughMacro() throws Exception {
setupTestFdoPrefetchHintsLoadedThroughMacro(/* loadMacro= */ true);
assertThat(getConfiguredTarget("//a:a")).isNotNull();
assertNoEvents();
}
private void setupTestFdoPrefetchHintsLoadedThroughMacro(boolean loadMacro) throws Exception {
scratch.file(
"a/BUILD",
getAnalysisMock().ccSupport().getMacroLoadStatement(loadMacro, "fdo_prefetch_hints"),
"fdo_prefetch_hints(",
" name = 'a',",
" profile = 'profile.afdo',",
")");
}
private static String removeOutDirectory(String s) {
return s.replace("blaze-out", "").replace("bazel-out", "");
}
@Test
public void testNoCoptsDisabled() throws Exception {
if (analysisMock.isThisBazel()) {
return;
}
reporter.removeHandler(failFastHandler);
scratch.file("x/BUILD", "cc_library(name = 'foo', srcs = ['a.cc'], nocopts = 'abc')");
useConfiguration("--incompatible_disable_nocopts");
getConfiguredTarget("//x:foo");
assertContainsEvent(
"This attribute was removed. See https://github.com/bazelbuild/bazel/issues/8706 for"
+ " details.");
}
@Test
public void testLinkExtra() throws Exception {
ConfiguredTarget target =
scratchConfiguredTarget(
"mypackage",
"mybinary",
"cc_binary(name = 'mybinary',",
" srcs = ['mybinary.cc'])");
List<String> artifactNames = baseArtifactNames(getLinkerInputs(target));
assertThat(artifactNames).contains("liblink_extra_lib.a");
}
@Test
public void testNoLinkExtra() throws Exception {
ConfiguredTarget target =
scratchConfiguredTarget(
"mypackage",
"mybinary",
"cc_library(name = 'empty_lib')",
"cc_binary(name = 'mybinary',",
" srcs = ['mybinary.cc'],",
" link_extra_lib = ':empty_lib')");
List<String> artifactNames = baseArtifactNames(getLinkerInputs(target));
assertThat(artifactNames).doesNotContain("liblink_extra_lib.a");
}
@Test
public void testGenerateLinkMap() throws Exception {
AnalysisMock.get()
.ccSupport()
.setupCcToolchainConfig(
mockToolsConfig,
CcToolchainConfig.builder().withFeatures(CppRuleClasses.GENERATE_LINKMAP_FEATURE_NAME));
useConfiguration("--cpu=k8");
ConfiguredTarget generateLinkMapTest =
scratchConfiguredTarget(
"generate_linkmap",
"generate_linkmap_test",
"cc_binary(name = 'generate_linkmap_test',",
" features = ['generate_linkmap'],",
" srcs = ['generate_linkmap_test.cc'],",
" )");
Iterable<String> temps =
ActionsTestUtil.baseArtifactNames(getOutputGroup(generateLinkMapTest, "linkmap"));
assertThat(temps).containsExactly("generate_linkmap_test.map");
}
}