private void createHeaderAction( String outputName, Builder result, AnalysisEnvironment env, CppCompileActionBuilder builder, boolean generateDotd) { String outputNameBase = CppHelper.getCompileArtifactName( ruleContext, ArtifactCategory.GENERATED_HEADER, outputName); builder .setOutputs(ArtifactCategory.PROCESSED_HEADER, outputNameBase, generateDotd) // If we generate pic actions, we prefer the header actions to use the pic artifacts. .setPicMode(this.getGeneratePicActions()); setupCompileBuildVariables( builder, this.getGeneratePicActions(), /*ccRelativeName=*/ null, /*autoFdoImportPath=*/ null, /*gcnoFile=*/ null, /*dwoFile=*/ null, ImmutableMap.<String, String>of()); semantics.finalizeCompileActionBuilder(ruleContext, builder); CppCompileAction compileAction = builder.build(); env.registerAction(compileAction); Artifact tokenFile = compileAction.getOutputFile(); result.addHeaderTokenFile(tokenFile); }
@Test public void testIncludePathOrder() throws Exception { scratch.file( "foo/BUILD", "cc_library(", " name = 'bar',", " includes = ['bar'],", ")", "cc_library(", " name = 'foo',", " srcs = ['foo.cc'],", " includes = ['foo'],", " deps = [':bar'],", ")"); ConfiguredTarget target = getConfiguredTarget("//foo"); CppCompileAction action = getCppCompileAction(target); String genfilesDir = target.getConfiguration().getGenfilesFragment().toString(); // Local include paths come first. assertContainsSublist( action.getCompilerOptions(), ImmutableList.of( "-isystem", "foo/foo", "-isystem", genfilesDir + "/foo/foo", "-isystem", "foo/bar", "-isystem", genfilesDir + "/foo/bar", "-isystem", TestConstants.GCC_INCLUDE_PATH)); }
@Test public void testDisablingHeaderModulesWhenDependingOnModuleBuildTransitively() throws Exception { AnalysisMock.get() .ccSupport() .setupCrosstool(mockToolsConfig, MockCcSupport.HEADER_MODULES_FEATURE_CONFIGURATION); useConfiguration(); scratch.file( "module/BUILD", "package(features = ['header_modules'])", "cc_library(", " name = 'module',", " srcs = ['a.cc', 'a.h'],", ")"); scratch.file( "nomodule/BUILD", "package(features = ['-header_modules'])", "cc_library(", " name = 'nomodule',", " srcs = ['a.cc', 'a.h'],", " deps = ['//module']", ")"); CppCompileAction moduleAction = getCppCompileAction("//module:module"); assertThat(moduleAction.getCompilerOptions()).contains("module_name://module:module"); CppCompileAction noModuleAction = getCppCompileAction("//nomodule:nomodule"); assertThat(noModuleAction.getCompilerOptions()).doesNotContain("module_name://module:module"); }
private List<String> getCompilationModeFlags(String... flags) throws Exception { AnalysisMock.get().ccSupport().setupCrosstool(mockToolsConfig, COMPILATION_MODE_FEATURES); useConfiguration(flags); scratch.overwriteFile("mode/BUILD", "cc_library(name = 'a', srcs = ['a.cc'])"); getConfiguredTarget("//mode:a"); Artifact objectArtifact = getBinArtifact("_objs/a/mode/a.pic.o", "//mode:a"); CppCompileAction action = (CppCompileAction) getGeneratingAction(objectArtifact); return action.getCompilerOptions(); }
/** Create the actions for "--save_temps". */ private ImmutableList<Artifact> createTempsActions( Artifact source, String outputName, CppCompileActionBuilder builder, boolean usePic, boolean generateDotd, PathFragment ccRelativeName) { if (!cppConfiguration.getSaveTemps()) { return ImmutableList.of(); } String path = source.getFilename(); boolean isCFile = CppFileTypes.C_SOURCE.matches(path); boolean isCppFile = CppFileTypes.CPP_SOURCE.matches(path); if (!isCFile && !isCppFile) { return ImmutableList.of(); } ArtifactCategory category = isCFile ? ArtifactCategory.PREPROCESSED_C_SOURCE : ArtifactCategory.PREPROCESSED_CPP_SOURCE; String outputArtifactNameBase = getOutputNameBaseWith(outputName, usePic); CppCompileActionBuilder dBuilder = new CppCompileActionBuilder(builder); dBuilder.setOutputs(category, outputArtifactNameBase, generateDotd); setupCompileBuildVariables( dBuilder, usePic, ccRelativeName, source.getExecPath(), null, null, ImmutableMap.<String, String>of()); semantics.finalizeCompileActionBuilder(ruleContext, dBuilder); CppCompileAction dAction = dBuilder.build(); ruleContext.registerAction(dAction); CppCompileActionBuilder sdBuilder = new CppCompileActionBuilder(builder); sdBuilder.setOutputs(ArtifactCategory.GENERATED_ASSEMBLY, outputArtifactNameBase, generateDotd); setupCompileBuildVariables( sdBuilder, usePic, ccRelativeName, source.getExecPath(), null, null, ImmutableMap.<String, String>of()); semantics.finalizeCompileActionBuilder(ruleContext, sdBuilder); CppCompileAction sdAction = sdBuilder.build(); ruleContext.registerAction(sdAction); return ImmutableList.of(dAction.getOutputFile(), sdAction.getOutputFile()); }
@Test public void testTopLevelHeaderModules() throws Exception { AnalysisMock.get() .ccSupport() .setupCrosstool( mockToolsConfig, MockCcSupport.HEADER_MODULES_FEATURE_CONFIGURATION + "feature { name: 'header_module_includes_dependencies' }"); useConfiguration(); setupPackagesForModuleTests(/*useHeaderModules=*/ false); getConfiguredTarget("//module:j"); Artifact jObjectArtifact = getBinArtifact("_objs/j/module/j.pic.o", "//module:j"); CppCompileAction jObjectAction = (CppCompileAction) getGeneratingAction(jObjectArtifact); assertThat(getHeaderModuleFlags(jObjectAction.getCompilerOptions())) .containsExactly("g.pic.pcm"); }
private void createFakeSourceAction( String outputName, CcCompilationOutputs.Builder result, AnalysisEnvironment env, CppCompileActionBuilder builder, ArtifactCategory outputCategory, boolean addObject, PathFragment ccRelativeName, PathFragment execPath, boolean usePic, boolean generateDotd) { String outputNameBase = getOutputNameBaseWith(outputName, usePic); String tempOutputName = ruleContext .getConfiguration() .getBinFragment() .getRelative(CppHelper.getObjDirectory(ruleContext.getLabel())) .getRelative( CppHelper.getCompileArtifactName( ruleContext, outputCategory, getOutputNameBaseWith(outputName + ".temp", usePic))) .getPathString(); builder .setPicMode(usePic) .setOutputs(outputCategory, outputNameBase, generateDotd) .setTempOutputFile(new PathFragment(tempOutputName)); setupCompileBuildVariables( builder, usePic, ccRelativeName, execPath, /*gcnoFile=*/ null, /*dwoFile=*/ null, ImmutableMap.<String, String>of()); semantics.finalizeCompileActionBuilder(ruleContext, builder); CppCompileAction action = builder.build(); env.registerAction(action); if (addObject) { if (usePic) { result.addPicObjectFile(action.getOutputFile()); } else { result.addObjectFile(action.getOutputFile()); } } }
@Test public void testDefinesOrder() throws Exception { scratch.file( "foo/BUILD", "cc_library(", " name = 'bar',", " defines = ['BAR'],", ")", "cc_library(", " name = 'foo',", " srcs = ['foo.cc'],", " defines = ['FOO'],", " deps = [':bar'],", ")"); CppCompileAction action = getCppCompileAction("//foo"); // Inherited defines come first. assertContainsSublist(action.getCompilerOptions(), ImmutableList.of("-DBAR", "-DFOO")); }
@Test public void testCompileUsingHeaderModulesTransitivelyWithTranstiveModuleMaps() throws Exception { AnalysisMock.get() .ccSupport() .setupCrosstool( mockToolsConfig, MockCcSupport.HEADER_MODULES_FEATURE_CONFIGURATION + "feature { name: 'transitive_module_maps' }"); useConfiguration("--features=transitive_module_maps"); setupPackagesForModuleTests(/*useHeaderModules=*/ true); getConfiguredTarget("//nomodule:f"); Artifact fObjectArtifact = getBinArtifact("_objs/f/nomodule/f.pic.o", "//nomodule:f"); CppCompileAction fObjectAction = (CppCompileAction) getGeneratingAction(fObjectArtifact); // Only the module map of f itself itself and the direct dependencies are needed. assertThat(getNonSystemModuleMaps(fObjectAction.getInputs())) .containsExactly( getGenfilesArtifact("y.cppmap", "//nomodule:y"), getGenfilesArtifact("z.cppmap", "//nomodule:z"), getGenfilesArtifact("a.cppmap", "//nomodule:a"), getGenfilesArtifact("f.cppmap", "//nomodule:f"), getGenfilesArtifact("e.cppmap", "//nomodule:e")); getConfiguredTarget("//nomodule:c"); Artifact cObjectArtifact = getBinArtifact("_objs/c/nomodule/c.pic.o", "//nomodule:c"); CppCompileAction cObjectAction = (CppCompileAction) getGeneratingAction(cObjectArtifact); assertThat(getNonSystemModuleMaps(cObjectAction.getInputs())) .containsExactly( getGenfilesArtifact("y.cppmap", "//nomodule:y"), getGenfilesArtifact("z.cppmap", "//nomodule:z"), getGenfilesArtifact("a.cppmap", "//nomodule:a"), getGenfilesArtifact("b.cppmap", "//module:b"), getGenfilesArtifact("c.cppmap", "//nomodule:e")); assertThat(getHeaderModuleFlags(cObjectAction.getCompilerOptions())) .containsExactly("b.pic.pcm"); getConfiguredTarget("//nomodule:d"); Artifact dObjectArtifact = getBinArtifact("_objs/d/nomodule/d.pic.o", "//nomodule:d"); CppCompileAction dObjectAction = (CppCompileAction) getGeneratingAction(dObjectArtifact); assertThat(getNonSystemModuleMaps(dObjectAction.getInputs())) .containsExactly( getGenfilesArtifact("y.cppmap", "//nomodule:y"), getGenfilesArtifact("z.cppmap", "//nomodule:z"), getGenfilesArtifact("a.cppmap", "//nomodule:a"), getGenfilesArtifact("b.cppmap", "//module:b"), getGenfilesArtifact("c.cppmap", "//nomodule:c"), getGenfilesArtifact("d.cppmap", "//nomodule:d")); assertThat(getHeaderModuleFlags(dObjectAction.getCompilerOptions())) .containsExactly("b.pic.pcm"); }
@Test public void testCompileHeaderModules() throws Exception { AnalysisMock.get() .ccSupport() .setupCrosstool( mockToolsConfig, "" + "feature { name: 'header_modules' }" + "feature { name: 'module_maps' }"); useConfiguration(); scratch.file( "module/BUILD", "package(features = ['header_modules'])", "cc_library(", " name = 'a',", " srcs = ['a.h', 'a.cc'],", " deps = ['b']", ")", "cc_library(", " name = 'b',", " srcs = ['b.h'],", " textual_hdrs = ['t.h'],", ")"); getConfiguredTarget("//module:b"); Artifact bModuleArtifact = getBinArtifact("_objs/b/module/b.pic.pcm", "//module:b"); CppCompileAction bModuleAction = (CppCompileAction) getGeneratingAction(bModuleArtifact); assertThat(bModuleAction.getIncludeScannerSources()) .containsExactly(getSourceArtifact("module/b.h"), getSourceArtifact("module/t.h")); assertThat(bModuleAction.getInputs()) .contains(getGenfilesArtifactWithNoOwner("module/b.cppmap")); getConfiguredTarget("//module:a"); Artifact aObjectArtifact = getBinArtifact("_objs/a/module/a.pic.o", "//module:a"); CppCompileAction aObjectAction = (CppCompileAction) getGeneratingAction(aObjectArtifact); assertThat(aObjectAction.getIncludeScannerSources()) .containsExactly( getSourceArtifact("module/a.cc"), getSourceArtifact("module/b.h"), getSourceArtifact("module/t.h")); assertThat(aObjectAction.getInputs()) .contains(getBinArtifact("_objs/b/module/b.pic.pcm", "//module:b")); assertThat(aObjectAction.getInputs()) .contains(getGenfilesArtifactWithNoOwner("module/b.cppmap")); assertNoEvents(); }
private void createSourceAction( String outputName, CcCompilationOutputs.Builder result, AnalysisEnvironment env, Artifact sourceArtifact, CppCompileActionBuilder builder, ArtifactCategory outputCategory, boolean addObject, boolean enableCoverage, boolean generateDwo, boolean generateDotd, Map<String, String> sourceSpecificBuildVariables) { PathFragment ccRelativeName = semantics.getEffectiveSourcePath(sourceArtifact); if (cppConfiguration.isLipoOptimization()) { // TODO(bazel-team): we shouldn't be needing this, merging context with the binary // is a superset of necessary information. LipoContextProvider lipoProvider = Preconditions.checkNotNull(CppHelper.getLipoContextProvider(ruleContext), outputName); builder.setContext( CppCompilationContext.mergeForLipo(lipoProvider.getLipoContext(), context)); } boolean generatePicAction = getGeneratePicActions(); // If we always need pic for everything, then don't bother to create a no-pic action. boolean generateNoPicAction = getGenerateNoPicActions(); Preconditions.checkState(generatePicAction || generateNoPicAction); if (fake) { boolean usePic = !generateNoPicAction; createFakeSourceAction( outputName, result, env, builder, outputCategory, addObject, ccRelativeName, sourceArtifact.getExecPath(), usePic, generateDotd); } else { // Create PIC compile actions (same as non-PIC, but use -fPIC and // generate .pic.o, .pic.d, .pic.gcno instead of .o, .d, .gcno.) if (generatePicAction) { String picOutputBase = CppHelper.getCompileArtifactName(ruleContext, ArtifactCategory.PIC_FILE, outputName); CppCompileActionBuilder picBuilder = copyAsPicBuilder(builder, picOutputBase, outputCategory, generateDotd); String gcnoFileName = CppHelper.getCompileArtifactName( ruleContext, ArtifactCategory.COVERAGE_DATA_FILE, picOutputBase); Artifact gcnoFile = enableCoverage ? CppHelper.getCompileOutputArtifact(ruleContext, gcnoFileName) : null; Artifact dwoFile = generateDwo ? getDwoFile(picBuilder.getOutputFile()) : null; setupCompileBuildVariables( picBuilder, /*usePic=*/ true, ccRelativeName, sourceArtifact.getExecPath(), gcnoFile, dwoFile, sourceSpecificBuildVariables); if (maySaveTemps) { result.addTemps( createTempsActions( sourceArtifact, outputName, picBuilder, /*usePic=*/ true, /*generateDotd=*/ generateDotd, ccRelativeName)); } picBuilder.setGcnoFile(gcnoFile); picBuilder.setDwoFile(dwoFile); semantics.finalizeCompileActionBuilder(ruleContext, picBuilder); CppCompileAction picAction = picBuilder.build(); env.registerAction(picAction); if (addObject) { result.addPicObjectFile(picAction.getOutputFile()); if (featureConfiguration.isEnabled(CppRuleClasses.THIN_LTO) && CppFileTypes.LTO_SOURCE.matches(sourceArtifact.getFilename())) { result.addLTOBitcodeFile(picAction.getOutputFile()); } } if (dwoFile != null) { // Host targets don't produce .dwo files. result.addPicDwoFile(dwoFile); } if (cppConfiguration.isLipoContextCollector() && !generateNoPicAction) { result.addLipoScannable(picAction); } } if (generateNoPicAction) { Artifact noPicOutputFile = CppHelper.getCompileOutputArtifact( ruleContext, CppHelper.getCompileArtifactName(ruleContext, outputCategory, outputName)); builder.setOutputs(outputCategory, outputName, generateDotd); String gcnoFileName = CppHelper.getCompileArtifactName( ruleContext, ArtifactCategory.COVERAGE_DATA_FILE, outputName); // Create non-PIC compile actions Artifact gcnoFile = !cppConfiguration.isLipoOptimization() && enableCoverage ? CppHelper.getCompileOutputArtifact(ruleContext, gcnoFileName) : null; Artifact noPicDwoFile = generateDwo ? getDwoFile(noPicOutputFile) : null; setupCompileBuildVariables( builder, /*usePic=*/ false, ccRelativeName, sourceArtifact.getExecPath(), gcnoFile, noPicDwoFile, sourceSpecificBuildVariables); if (maySaveTemps) { result.addTemps( createTempsActions( sourceArtifact, outputName, builder, /*usePic=*/ false, /*generateDotd*/ generateDotd, ccRelativeName)); } builder.setGcnoFile(gcnoFile); builder.setDwoFile(noPicDwoFile); semantics.finalizeCompileActionBuilder(ruleContext, builder); CppCompileAction compileAction = builder.build(); env.registerAction(compileAction); Artifact objectFile = compileAction.getOutputFile(); if (addObject) { result.addObjectFile(objectFile); if (featureConfiguration.isEnabled(CppRuleClasses.THIN_LTO) && CppFileTypes.LTO_SOURCE.matches(sourceArtifact.getFilename())) { result.addLTOBitcodeFile(objectFile); } } if (noPicDwoFile != null) { // Host targets don't produce .dwo files. result.addDwoFile(noPicDwoFile); } if (cppConfiguration.isLipoContextCollector()) { result.addLipoScannable(compileAction); } } } }
@Test public void testCompileHeaderModulesTransitively() throws Exception { AnalysisMock.get() .ccSupport() .setupCrosstool(mockToolsConfig, MockCcSupport.HEADER_MODULES_FEATURE_CONFIGURATION); useConfiguration(); setupPackagesForModuleTests(/*useHeaderModules=*/ false); // The //nomodule:f target only depends on non-module targets, thus it should be module-free. getConfiguredTarget("//nomodule:f"); assertThat(getGeneratingAction(getBinArtifact("_objs/f/nomodule/f.pic.pcm", "//nomodule:f"))) .isNull(); Artifact fObjectArtifact = getBinArtifact("_objs/f/nomodule/f.pic.o", "//nomodule:f"); CppCompileAction fObjectAction = (CppCompileAction) getGeneratingAction(fObjectArtifact); // Only the module map of f itself itself and the direct dependencies are needed. assertThat(getNonSystemModuleMaps(fObjectAction.getInputs())) .containsExactly( getGenfilesArtifact("f.cppmap", "//nomodule:f"), getGenfilesArtifact("e.cppmap", "//nomodule:e")); assertThat(getHeaderModules(fObjectAction.getInputs())).isEmpty(); assertThat(fObjectAction.getIncludeScannerSources()) .containsExactly(getSourceArtifact("nomodule/f.cc")); assertThat(getHeaderModuleFlags(fObjectAction.getCompilerOptions())).isEmpty(); // The //nomodule:c target will get the header module for //module:b, which is a direct // dependency. getConfiguredTarget("//nomodule:c"); assertThat(getGeneratingAction(getBinArtifact("_objs/c/nomodule/c.pic.pcm", "//nomodule:c"))) .isNull(); Artifact cObjectArtifact = getBinArtifact("_objs/c/nomodule/c.pic.o", "//nomodule:c"); CppCompileAction cObjectAction = (CppCompileAction) getGeneratingAction(cObjectArtifact); assertThat(getNonSystemModuleMaps(cObjectAction.getInputs())) .containsExactly( getGenfilesArtifact("b.cppmap", "//module:b"), getGenfilesArtifact("c.cppmap", "//nomodule:e")); assertThat(getHeaderModules(cObjectAction.getInputs())) .containsExactly(getBinArtifact("_objs/b/module/b.pic.pcm", "//module:b")); // All headers of transitive dependencies that are built as modules are needed as entry points // for include scanning. assertThat(cObjectAction.getIncludeScannerSources()) .containsExactly(getSourceArtifact("nomodule/c.cc"), getSourceArtifact("module/b.h")); assertThat(cObjectAction.getMainIncludeScannerSource()) .isEqualTo(getSourceArtifact("nomodule/c.cc")); assertThat(getHeaderModuleFlags(cObjectAction.getCompilerOptions())).isEmpty(); // The //nomodule:d target depends on //module:b via one indirection (//nomodule:c). getConfiguredTarget("//nomodule:d"); assertThat(getGeneratingAction(getBinArtifact("_objs/d/nomodule/d.pic.pcm", "//nomodule:d"))) .isNull(); Artifact dObjectArtifact = getBinArtifact("_objs/d/nomodule/d.pic.o", "//nomodule:d"); CppCompileAction dObjectAction = (CppCompileAction) getGeneratingAction(dObjectArtifact); // Module map 'c.cppmap' is needed because it is a direct dependency. assertThat(getNonSystemModuleMaps(dObjectAction.getInputs())) .containsExactly( getGenfilesArtifact("c.cppmap", "//nomodule:c"), getGenfilesArtifact("d.cppmap", "//nomodule:d")); assertThat(getHeaderModules(dObjectAction.getInputs())) .containsExactly(getBinArtifact("_objs/b/module/b.pic.pcm", "//module:b")); // All headers of transitive dependencies that are built as modules are needed as entry points // for include scanning. assertThat(dObjectAction.getIncludeScannerSources()) .containsExactly(getSourceArtifact("module/b.h"), getSourceArtifact("nomodule/d.cc")); assertThat(getHeaderModuleFlags(dObjectAction.getCompilerOptions())).isEmpty(); // The //module:j target depends on //module:g via //nomodule:h and on //module:b via // both //module:g and //nomodule:c. getConfiguredTarget("//module:j"); Artifact jObjectArtifact = getBinArtifact("_objs/j/module/j.pic.o", "//module:j"); CppCompileAction jObjectAction = (CppCompileAction) getGeneratingAction(jObjectArtifact); assertThat(getHeaderModules(jObjectAction.getInputs())) .containsExactly( getBinArtifact("_objs/b/module/b.pic.pcm", "//module:b"), getBinArtifact("_objs/g/module/g.pic.pcm", "//module:g")); assertThat(jObjectAction.getIncludeScannerSources()) .containsExactly( getSourceArtifact("module/j.cc"), getSourceArtifact("module/b.h"), getSourceArtifact("module/g.h")); assertThat(jObjectAction.getMainIncludeScannerSource()) .isEqualTo(getSourceArtifact("module/j.cc")); assertThat(getHeaderModuleFlags(jObjectAction.getCompilerOptions())) .containsExactly("b.pic.pcm", "g.pic.pcm"); }