aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationHelper.java
diff options
context:
space:
mode:
authorGravatar plf <plf@google.com>2018-02-15 02:12:58 -0800
committerGravatar Copybara-Service <copybara-piper@google.com>2018-02-15 02:14:44 -0800
commitf58dc51a225139fabeb452eb4b88022558f29f55 (patch)
tree5e06cdb7a39059dac51cd678f151e0a56bd26e9e /src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationHelper.java
parent9d8ff35aac5006fb799584120166f8ecea1d391c (diff)
C++: Removes CppModel class
The logic is split between CcCompilationHelper and CcLinkingHelper. RELNOTES:none PiperOrigin-RevId: 185809915
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationHelper.java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationHelper.java1153
1 files changed, 1095 insertions, 58 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationHelper.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationHelper.java
index a7c1615d92..f9149ea2fd 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationHelper.java
@@ -20,10 +20,13 @@ import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicates;
+import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.Artifact.SpecialArtifact;
+import com.google.devtools.build.lib.analysis.AnalysisEnvironment;
import com.google.devtools.build.lib.analysis.AnalysisUtils;
import com.google.devtools.build.lib.analysis.LanguageDependentFragment;
import com.google.devtools.build.lib.analysis.OutputGroupInfo;
@@ -33,20 +36,27 @@ import com.google.devtools.build.lib.analysis.TransitiveInfoProviderMap;
import com.google.devtools.build.lib.analysis.TransitiveInfoProviderMapBuilder;
import com.google.devtools.build.lib.analysis.actions.SymlinkAction;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.analysis.config.PerLabelOptions;
import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode;
+import com.google.devtools.build.lib.analysis.test.InstrumentedFilesCollector;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.collect.nestedset.Order;
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
+import com.google.devtools.build.lib.packages.BuildType;
import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
import com.google.devtools.build.lib.rules.cpp.CcCommon.CoptsFilter;
import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration;
+import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables.StringSequenceBuilder;
import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables.VariablesExtension;
+import com.google.devtools.build.lib.rules.cpp.CppCompileAction.DotdFile;
import com.google.devtools.build.lib.rules.cpp.CppConfiguration.HeadersCheckingMode;
import com.google.devtools.build.lib.syntax.Type;
+import com.google.devtools.build.lib.util.FileType;
import com.google.devtools.build.lib.util.FileTypeSet;
import com.google.devtools.build.lib.util.Pair;
+import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.PathFragment;
import java.util.ArrayList;
import java.util.Arrays;
@@ -61,7 +71,7 @@ import javax.annotation.Nullable;
/**
* A class to create C/C++ compile actions in a way that is consistent with cc_library. Rules that
* generate source files and emulate cc_library on top of that should use this class instead of the
- * lower-level APIs in CppHelper and CppModel.
+ * lower-level APIs in CppHelper and CppCompileActionBuilder.
*
* <p>Rules that want to use this class are required to have implicit dependencies on the toolchain,
* the STL, the lipo context, and so on. Optionally, they can also have copts, and malloc
@@ -74,6 +84,97 @@ public final class CcCompilationHelper {
+ "hidden_header_tokens"
+ OutputGroupInfo.INTERNAL_SUFFIX;
+ private static final String PIC_CONFIGURATION_ERROR =
+ "PIC compilation is requested but the toolchain does not support it";
+ /** Name of the build variable for the path to the source file being compiled. */
+ public static final String SOURCE_FILE_VARIABLE_NAME = "source_file";
+
+ /** Name of the build variable for the path to the compilation output file. */
+ public static final String OUTPUT_FILE_VARIABLE_NAME = "output_file";
+
+ /**
+ * Build variable for all flags coming from copt rule attribute, and from --copt, --cxxopt, or
+ * --conlyopt options.
+ */
+ public static final String USER_COMPILE_FLAGS_VARIABLE_NAME = "user_compile_flags";
+
+ /**
+ * Build variable for all flags coming from legacy crosstool fields, such as compiler_flag,
+ * optional_compiler_flag, cxx_flag, optional_cxx_flag.
+ */
+ public static final String LEGACY_COMPILE_FLAGS_VARIABLE_NAME = "legacy_compile_flags";
+
+ /** Build variable for flags coming from unfiltered_cxx_flag CROSSTOOL fields. */
+ public static final String UNFILTERED_COMPILE_FLAGS_VARIABLE_NAME = "unfiltered_compile_flags";
+
+ /**
+ * Name of the build variable for the path to the compilation output file in case of preprocessed
+ * source.
+ */
+ public static final String OUTPUT_PREPROCESS_FILE_VARIABLE_NAME = "output_preprocess_file";
+
+ /** Name of the build variable for the path to the output file when output is an object file. */
+ public static final String OUTPUT_OBJECT_FILE_VARIABLE_NAME = "output_object_file";
+
+ /**
+ * Name of the build variable for the collection of include paths.
+ *
+ * @see CppCompilationContext#getIncludeDirs().
+ */
+ public static final String INCLUDE_PATHS_VARIABLE_NAME = "include_paths";
+
+ /**
+ * Name of the build variable for the collection of quote include paths.
+ *
+ * @see CppCompilationContext#getIncludeDirs().
+ */
+ public static final String QUOTE_INCLUDE_PATHS_VARIABLE_NAME = "quote_include_paths";
+
+ /**
+ * Name of the build variable for the collection of system include paths.
+ *
+ * @see CppCompilationContext#getIncludeDirs().
+ */
+ public static final String SYSTEM_INCLUDE_PATHS_VARIABLE_NAME = "system_include_paths";
+
+ /** Name of the build variable for the collection of macros defined for preprocessor. */
+ public static final String PREPROCESSOR_DEFINES_VARIABLE_NAME = "preprocessor_defines";
+
+ /** Name of the build variable present when the output is compiled as position independent. */
+ public static final String PIC_VARIABLE_NAME = "pic";
+
+ /**
+ * Name of the build variable for the path to the compilation output file in case of assembly
+ * source.
+ */
+ private static final String OUTPUT_ASSEMBLY_FILE_VARIABLE_NAME = "output_assembly_file";
+
+ /** Name of the build variable for the dependency file path */
+ private static final String DEPENDENCY_FILE_VARIABLE_NAME = "dependency_file";
+
+ /** Name of the build variable for the module file name. */
+ private static final String MODULE_NAME_VARIABLE_NAME = "module_name";
+
+ /** Name of the build variable for the module map file name. */
+ private static final String MODULE_MAP_FILE_VARIABLE_NAME = "module_map_file";
+
+ /** Name of the build variable for the dependent module map file name. */
+ private static final String DEPENDENT_MODULE_MAP_FILES_VARIABLE_NAME =
+ "dependent_module_map_files";
+
+ /** Name of the build variable for the collection of module files. */
+ private static final String MODULE_FILES_VARIABLE_NAME = "module_files";
+
+ /** Name of the build variable for the gcov coverage file path. */
+ private static final String GCOV_GCNO_FILE_VARIABLE_NAME = "gcov_gcno_file";
+
+ /** Name of the build variable for the per object debug info file. */
+ private static final String PER_OBJECT_DEBUG_INFO_FILE_VARIABLE_NAME =
+ "per_object_debug_info_file";
+
+ /** Name of the build variable for the LTO indexing bitcode file. */
+ private static final String LTO_INDEXING_BITCODE_FILE_VARIABLE_NAME = "lto_indexing_bitcode_file";
+
/**
* A group of source file types and action names for builds controlled by CcCompilationHelper.
* Determines what file types CcCompilationHelper considers sources and what action configs are
@@ -155,6 +256,7 @@ public final class CcCompilationHelper {
private final RuleContext ruleContext;
private final CppSemantics semantics;
private final BuildConfiguration configuration;
+ private final CppConfiguration cppConfiguration;
private final List<Artifact> publicHeaders = new ArrayList<>();
private final List<Artifact> nonModuleMapHeaders = new ArrayList<>();
@@ -190,11 +292,15 @@ public final class CcCompilationHelper {
private final FeatureConfiguration featureConfiguration;
private final CcToolchainProvider ccToolchain;
private final FdoSupportProvider fdoSupport;
+ private final ImmutableSet<String> features;
private boolean useDeps = true;
private boolean generateModuleMap = true;
private String purpose = null;
private boolean generateNoPic = true;
+ // TODO(plf): Pull out of class.
+ private CppCompilationContext cppCompilationContext;
+
/**
* Creates a CcCompilationHelper.
*
@@ -248,6 +354,9 @@ public final class CcCompilationHelper {
this.ccToolchain = Preconditions.checkNotNull(ccToolchain);
this.fdoSupport = Preconditions.checkNotNull(fdoSupport);
this.configuration = Preconditions.checkNotNull(configuration);
+ this.cppConfiguration =
+ Preconditions.checkNotNull(ruleContext.getFragment(CppConfiguration.class));
+ this.features = ruleContext.getFeatures();
}
/**
@@ -645,9 +754,7 @@ public final class CcCompilationHelper {
}
}
- CppModel model = initializeCppModel();
- CppCompilationContext cppCompilationContext = initializeCppCompilationContext(model);
- model.setContext(cppCompilationContext);
+ cppCompilationContext = initializeCppCompilationContext();
boolean compileHeaderModules = featureConfiguration.isEnabled(CppRuleClasses.HEADER_MODULES);
Preconditions.checkState(
@@ -655,7 +762,7 @@ public final class CcCompilationHelper {
"All cc rules must support module maps.");
// Create compile actions (both PIC and non-PIC).
- CcCompilationOutputs ccOutputs = model.createCcCompileActions();
+ CcCompilationOutputs ccOutputs = createCcCompileActions();
if (!objectFiles.isEmpty() || !picObjectFiles.isEmpty()) {
// Merge the pre-compiled object files into the compiler outputs.
ccOutputs =
@@ -703,22 +810,6 @@ public final class CcCompilationHelper {
return new CompilationInfo(providers.build(), outputGroups, ccOutputs, cppCompilationContext);
}
- /** Creates the C/C++ compilation action creator. */
- private CppModel initializeCppModel() {
- return new CppModel(
- ruleContext, semantics, ccToolchain, fdoSupport, configuration, copts, coptsFilter)
- .addCompilationUnitSources(compilationUnitSources)
- .addCompilationMandatoryInputs(compilationMandatoryInputs)
- .addAdditionalIncludeScanningRoots(additionalIncludeScanningRoots)
- .setFake(fake)
- .setGenerateNoPic(generateNoPic)
- // Note: this doesn't actually save the temps, it just makes the CppModel use the
- // configurations --save_temps setting to decide whether to actually save the temps.
- .setSaveTemps(true)
- .setFeatureConfiguration(featureConfiguration)
- .addVariablesExtension(variablesExtensions);
- }
-
@Immutable
private static class PublicHeaders {
private final ImmutableList<Artifact> headers;
@@ -853,17 +944,12 @@ public final class CcCompilationHelper {
.getRelative(ruleContext.getUniqueDirectory("_virtual_includes")));
}
- /** Creates context for cc compile action from generated inputs. */
- public CppCompilationContext initializeCppCompilationContext() {
- return initializeCppCompilationContext(initializeCppModel());
- }
-
/**
* Create context for cc compile action from generated inputs.
*
* <p>TODO(plf): Try to pull out CppCompilationContext building out of this class.
*/
- private CppCompilationContext initializeCppCompilationContext(CppModel model) {
+ public CppCompilationContext initializeCppCompilationContext() {
CppCompilationContext.Builder contextBuilder = new CppCompilationContext.Builder(ruleContext);
// Setup the include path; local include directories come before those inherited from deps or
@@ -959,11 +1045,11 @@ public final class CcCompilationHelper {
ruleContext.registerAction(
createModuleMapAction(cppModuleMap, publicHeaders, dependentModuleMaps, compiled));
}
- if (model.getGeneratesPicHeaderModule()) {
- contextBuilder.setPicHeaderModule(model.getPicHeaderModule(cppModuleMap.getArtifact()));
+ if (getGeneratesPicHeaderModule()) {
+ contextBuilder.setPicHeaderModule(getPicHeaderModule(cppModuleMap.getArtifact()));
}
- if (model.getGeneratesNoPicHeaderModule()) {
- contextBuilder.setHeaderModule(model.getHeaderModule(cppModuleMap.getArtifact()));
+ if (getGeneratesNoPicHeaderModule()) {
+ contextBuilder.setHeaderModule(getHeaderModule(cppModuleMap.getArtifact()));
}
if (!compiled
&& featureConfiguration.isEnabled(CppRuleClasses.PARSE_HEADERS)
@@ -986,6 +1072,83 @@ public final class CcCompilationHelper {
return contextBuilder.build();
}
+ /**
+ * Collects all preprocessed header files (*.h.processed) from dependencies and the current rule.
+ */
+ public static NestedSet<Artifact> collectHeaderTokens(
+ RuleContext ruleContext, CcCompilationOutputs ccCompilationOutputs) {
+ NestedSetBuilder<Artifact> headerTokens = NestedSetBuilder.stableOrder();
+ for (OutputGroupInfo dep :
+ ruleContext.getPrerequisites("deps", Mode.TARGET, OutputGroupInfo.SKYLARK_CONSTRUCTOR)) {
+ headerTokens.addTransitive(dep.getOutputGroup(CcCompilationHelper.HIDDEN_HEADER_TOKENS));
+ }
+ if (ruleContext.getFragment(CppConfiguration.class).processHeadersInDependencies()) {
+ headerTokens.addAll(ccCompilationOutputs.getHeaderTokenFiles());
+ }
+ return headerTokens.build();
+ }
+
+ public void registerAdditionalModuleMap(CppModuleMap cppModuleMap) {
+ this.additionalCppModuleMaps.add(Preconditions.checkNotNull(cppModuleMap));
+ }
+
+ /** Don't generate a module map for this target if a custom module map is provided. */
+ public CcCompilationHelper doNotGenerateModuleMap() {
+ generateModuleMap = false;
+ return this;
+ }
+
+ /**
+ * Sets the purpose for the context.
+ *
+ * @see CppCompilationContext.Builder#setPurpose
+ * @param purpose must be a string which is suitable for use as a filename. A single rule may have
+ * many middlemen with distinct purposes.
+ */
+ public CcCompilationHelper setPurpose(@Nullable String purpose) {
+ this.purpose = purpose;
+ return this;
+ }
+
+ /**
+ * Supplier that computes legacy_compile_flags lazily at the execution phase.
+ *
+ * <p>Dear friends of the lambda, this method exists to limit the scope of captured variables only
+ * to arguments (to prevent accidental capture of enclosing instance which could regress memory).
+ */
+ public static Supplier<ImmutableList<String>> getLegacyCompileFlagsSupplier(
+ CppConfiguration cppConfiguration,
+ CcToolchainProvider toolchain,
+ String sourceFilename,
+ ImmutableSet<String> features) {
+ return () -> {
+ ImmutableList.Builder<String> legacyCompileFlags = ImmutableList.builder();
+ legacyCompileFlags.addAll(
+ CppHelper.getCompilerOptions(cppConfiguration, toolchain, features));
+ if (CppFileTypes.C_SOURCE.matches(sourceFilename)) {
+ legacyCompileFlags.addAll(cppConfiguration.getCOptions());
+ }
+ if (CppFileTypes.CPP_SOURCE.matches(sourceFilename)
+ || CppFileTypes.CPP_HEADER.matches(sourceFilename)
+ || CppFileTypes.CPP_MODULE_MAP.matches(sourceFilename)
+ || CppFileTypes.CLIF_INPUT_PROTO.matches(sourceFilename)) {
+ legacyCompileFlags.addAll(CppHelper.getCxxOptions(cppConfiguration, toolchain, features));
+ }
+ return legacyCompileFlags.build();
+ };
+ }
+
+ /**
+ * Supplier that computes unfiltered_compile_flags lazily at the execution phase.
+ *
+ * <p>Dear friends of the lambda, this method exists to limit the scope of captured variables only
+ * to arguments (to prevent accidental capture of enclosing instance which could regress memory).
+ */
+ public static Supplier<ImmutableList<String>> getUnfilteredCompileFlagsSupplier(
+ CcToolchainProvider ccToolchain, ImmutableSet<String> features) {
+ return () -> ccToolchain.getUnfilteredCompilerOptions(features);
+ }
+
private UmbrellaHeaderAction createUmbrellaHeaderAction(
Artifact umbrellaHeader, PublicHeaders publicHeaders) {
return new UmbrellaHeaderAction(
@@ -1041,19 +1204,6 @@ public final class CcCompilationHelper {
return Iterables.filter(result, Predicates.<CppModuleMap>notNull());
}
- static NestedSet<Artifact> collectHeaderTokens(
- RuleContext ruleContext, CcCompilationOutputs ccCompilationOutputs) {
- NestedSetBuilder<Artifact> headerTokens = NestedSetBuilder.stableOrder();
- for (OutputGroupInfo dep :
- ruleContext.getPrerequisites("deps", Mode.TARGET, OutputGroupInfo.SKYLARK_CONSTRUCTOR)) {
- headerTokens.addTransitive(dep.getOutputGroup(CcCompilationHelper.HIDDEN_HEADER_TOKENS));
- }
- if (ruleContext.getFragment(CppConfiguration.class).processHeadersInDependencies()) {
- headerTokens.addAll(ccCompilationOutputs.getHeaderTokenFiles());
- }
- return headerTokens.build();
- }
-
private TransitiveLipoInfoProvider collectTransitiveLipoInfo(CcCompilationOutputs outputs) {
if (fdoSupport.getFdoSupport().getFdoRoot() == null) {
return TransitiveLipoInfoProvider.EMPTY;
@@ -1086,25 +1236,912 @@ public final class CcCompilationHelper {
: compilationOutputs.getTemps();
}
- public void registerAdditionalModuleMap(CppModuleMap cppModuleMap) {
- this.additionalCppModuleMaps.add(Preconditions.checkNotNull(cppModuleMap));
+ /** @return whether this target needs to generate a pic header module. */
+ private boolean getGeneratesPicHeaderModule() {
+ return shouldProvideHeaderModules() && !fake && getGeneratePicActions();
}
- /** Don't generate a module map for this target if a custom module map is provided. */
- public CcCompilationHelper doNotGenerateModuleMap() {
- generateModuleMap = false;
- return this;
+ /** @return whether this target needs to generate a non-pic header module. */
+ private boolean getGeneratesNoPicHeaderModule() {
+ return shouldProvideHeaderModules() && !fake && getGenerateNoPicActions();
+ }
+
+ /** @return whether we want to provide header modules for the current target. */
+ private boolean shouldProvideHeaderModules() {
+ return featureConfiguration.isEnabled(CppRuleClasses.HEADER_MODULES)
+ && !cppConfiguration.isLipoContextCollector();
+ }
+
+ /** @return whether this target needs to generate non-pic actions. */
+ private boolean getGenerateNoPicActions() {
+ if (!generateNoPic) {
+ return false;
+ }
+ boolean picFeatureEnabled = featureConfiguration.isEnabled(CppRuleClasses.PIC);
+ boolean usePicForBinaries = CppHelper.usePic(ruleContext, ccToolchain, true);
+ boolean usePicForNonBinaries = CppHelper.usePic(ruleContext, ccToolchain, false);
+
+ if (!usePicForNonBinaries) {
+ // This means you have to be prepared to use non-pic output for dynamic libraries.
+ return true;
+ }
+
+ // Either you're only making a dynamic library (onlySingleOutput) or pic should be used
+ // in all cases.
+ if (usePicForBinaries) {
+ if (picFeatureEnabled) {
+ return false;
+ }
+ ruleContext.ruleError(PIC_CONFIGURATION_ERROR);
+ }
+
+ return true;
+ }
+
+ /** @return whether this target needs to generate pic actions. */
+ private boolean getGeneratePicActions() {
+ return featureConfiguration.isEnabled(CppRuleClasses.PIC)
+ && CppHelper.usePic(ruleContext, ccToolchain, false);
+ }
+
+ /** @return the non-pic header module artifact for the current target. */
+ private Artifact getHeaderModule(Artifact moduleMapArtifact) {
+ PathFragment objectDir = CppHelper.getObjDirectory(ruleContext.getLabel());
+ PathFragment outputName = objectDir.getRelative(moduleMapArtifact.getRootRelativePath());
+ return ruleContext.getRelatedArtifact(outputName, ".pcm");
+ }
+
+ /** @return the pic header module artifact for the current target. */
+ private Artifact getPicHeaderModule(Artifact moduleMapArtifact) {
+ PathFragment objectDir = CppHelper.getObjDirectory(ruleContext.getLabel());
+ PathFragment outputName = objectDir.getRelative(moduleMapArtifact.getRootRelativePath());
+ return ruleContext.getRelatedArtifact(outputName, ".pic.pcm");
}
/**
- * Sets the purpose for the context.
- *
- * @see CppCompilationContext.Builder#setPurpose
- * @param purpose must be a string which is suitable for use as a filename. A single rule may have
- * many middlemen with distinct purposes.
+ * Constructs the C++ compiler actions. It generally creates one action for every specified source
+ * file. It takes into account LIPO, fake-ness, coverage, and PIC, in addition to using the
+ * settings specified on the current object. This method should only be called once.
*/
- public CcCompilationHelper setPurpose(@Nullable String purpose) {
- this.purpose = purpose;
- return this;
+ private CcCompilationOutputs createCcCompileActions() throws RuleErrorException {
+ CcCompilationOutputs.Builder result = new CcCompilationOutputs.Builder();
+ Preconditions.checkNotNull(cppCompilationContext);
+ AnalysisEnvironment env = ruleContext.getAnalysisEnvironment();
+
+ if (shouldProvideHeaderModules()) {
+ Label moduleMapLabel =
+ Label.parseAbsoluteUnchecked(cppCompilationContext.getCppModuleMap().getName());
+ Collection<Artifact> modules =
+ createModuleAction(result, cppCompilationContext.getCppModuleMap());
+ if (featureConfiguration.isEnabled(CppRuleClasses.HEADER_MODULE_CODEGEN)) {
+ for (Artifact module : modules) {
+ // TODO(djasper): Investigate whether we need to use a label separate from that of the
+ // module map. It is used for per-file-copts.
+ createModuleCodegenAction(result, moduleMapLabel, module);
+ }
+ }
+ } else if (cppCompilationContext.getVerificationModuleMap() != null) {
+ Collection<Artifact> modules =
+ createModuleAction(result, cppCompilationContext.getVerificationModuleMap());
+ for (Artifact module : modules) {
+ result.addHeaderTokenFile(module);
+ }
+ }
+
+ for (CppSource source : compilationUnitSources) {
+ Artifact sourceArtifact = source.getSource();
+ Label sourceLabel = source.getLabel();
+ String outputName =
+ FileSystemUtils.removeExtension(sourceArtifact.getRootRelativePath()).getPathString();
+ CppCompileActionBuilder builder = initializeCompileAction(sourceArtifact);
+
+ builder
+ .setSemantics(semantics)
+ .addMandatoryInputs(compilationMandatoryInputs)
+ .addAdditionalIncludeScanningRoots(additionalIncludeScanningRoots);
+
+ boolean bitcodeOutput =
+ featureConfiguration.isEnabled(CppRuleClasses.THIN_LTO)
+ && CppFileTypes.LTO_SOURCE.matches(sourceArtifact.getFilename());
+
+ if (!sourceArtifact.isTreeArtifact()) {
+ switch (source.getType()) {
+ case HEADER:
+ createHeaderAction(
+ sourceLabel, outputName, result, env, builder, isGenerateDotdFile(sourceArtifact));
+ break;
+ default:
+ createSourceAction(
+ sourceLabel,
+ outputName,
+ result,
+ env,
+ sourceArtifact,
+ builder,
+ // TODO(plf): Continue removing CLIF logic from C++. Follow up changes would include
+ // refactoring CppSource.Type and ArtifactCategory to be classes instead of enums
+ // that could be instantiated with arbitrary values.
+ source.getType() == CppSource.Type.CLIF_INPUT_PROTO
+ ? ArtifactCategory.CLIF_OUTPUT_PROTO
+ : ArtifactCategory.OBJECT_FILE,
+ cppCompilationContext.getCppModuleMap(),
+ /* addObject= */ true,
+ isCodeCoverageEnabled(),
+ // The source action does not generate dwo when it has bitcode
+ // output (since it isn't generating a native object with debug
+ // info). In that case the LtoBackendAction will generate the dwo.
+ CppHelper.shouldCreatePerObjectDebugInfo(
+ cppConfiguration, ccToolchain, featureConfiguration)
+ && !bitcodeOutput,
+ isGenerateDotdFile(sourceArtifact));
+ break;
+ }
+ } else {
+ switch (source.getType()) {
+ case HEADER:
+ Artifact headerTokenFile =
+ createCompileActionTemplate(
+ env,
+ source,
+ builder,
+ ImmutableList.of(
+ ArtifactCategory.GENERATED_HEADER, ArtifactCategory.PROCESSED_HEADER),
+ false);
+ result.addHeaderTokenFile(headerTokenFile);
+ break;
+ case SOURCE:
+ Artifact objectFile =
+ createCompileActionTemplate(
+ env, source, builder, ImmutableList.of(ArtifactCategory.OBJECT_FILE), false);
+ result.addObjectFile(objectFile);
+
+ if (getGeneratePicActions()) {
+ Artifact picObjectFile =
+ createCompileActionTemplate(
+ env,
+ source,
+ builder,
+ ImmutableList.of(ArtifactCategory.PIC_OBJECT_FILE),
+ true);
+ result.addPicObjectFile(picObjectFile);
+ }
+ break;
+ default:
+ throw new IllegalStateException(
+ "Encountered invalid source types when creating CppCompileActionTemplates");
+ }
+ }
+ }
+
+ return result.build();
+ }
+
+ private Artifact createCompileActionTemplate(
+ AnalysisEnvironment env,
+ CppSource source,
+ CppCompileActionBuilder builder,
+ Iterable<ArtifactCategory> outputCategories,
+ boolean usePic) {
+ SpecialArtifact sourceArtifact = (SpecialArtifact) source.getSource();
+ SpecialArtifact outputFiles =
+ CppHelper.getCompileOutputTreeArtifact(ruleContext, sourceArtifact, usePic);
+ // TODO(rduan): Dotd file output is not supported yet.
+ builder.setOutputs(outputFiles, /* dotdFile= */ null);
+ setupCompileBuildVariables(
+ builder,
+ source.getLabel(),
+ usePic,
+ /* ccRelativeName= */ null,
+ /* autoFdoImportPath= */ null,
+ /* gcnoFile= */ null,
+ /* dwoFile= */ null,
+ /* ltoIndexingFile= */ null,
+ builder.getContext().getCppModuleMap());
+ semantics.finalizeCompileActionBuilder(ruleContext, builder);
+ // Make sure this builder doesn't reference ruleContext outside of analysis phase.
+ CppCompileActionTemplate actionTemplate =
+ new CppCompileActionTemplate(
+ sourceArtifact,
+ outputFiles,
+ builder,
+ ccToolchain,
+ outputCategories,
+ ruleContext.getActionOwner());
+ env.registerAction(actionTemplate);
+
+ return outputFiles;
+ }
+
+ private void setupCompileBuildVariables(
+ CppCompileActionBuilder builder,
+ Label sourceLabel,
+ boolean usePic,
+ PathFragment ccRelativeName,
+ PathFragment autoFdoImportPath,
+ Artifact gcnoFile,
+ Artifact dwoFile,
+ Artifact ltoIndexingFile,
+ CppModuleMap cppModuleMap) {
+ CcToolchainFeatures.Variables.Builder buildVariables =
+ new CcToolchainFeatures.Variables.Builder(ccToolchain.getBuildVariables());
+
+ CppCompilationContext builderContext = builder.getContext();
+ Artifact sourceFile = builder.getSourceFile();
+ Artifact outputFile = builder.getOutputFile();
+ String realOutputFilePath;
+
+ buildVariables.addStringVariable(SOURCE_FILE_VARIABLE_NAME, sourceFile.getExecPathString());
+ buildVariables.addStringVariable(OUTPUT_FILE_VARIABLE_NAME, outputFile.getExecPathString());
+ buildVariables.addStringSequenceVariable(
+ USER_COMPILE_FLAGS_VARIABLE_NAME,
+ ImmutableList.<String>builder()
+ .addAll(copts)
+ .addAll(collectPerFileCopts(sourceFile, sourceLabel))
+ .build());
+
+ String sourceFilename = sourceFile.getExecPathString();
+ buildVariables.addLazyStringSequenceVariable(
+ LEGACY_COMPILE_FLAGS_VARIABLE_NAME,
+ getLegacyCompileFlagsSupplier(cppConfiguration, ccToolchain, sourceFilename, features));
+
+ if (!CppFileTypes.OBJC_SOURCE.matches(sourceFilename)
+ && !CppFileTypes.OBJCPP_SOURCE.matches(sourceFilename)) {
+ buildVariables.addLazyStringSequenceVariable(
+ UNFILTERED_COMPILE_FLAGS_VARIABLE_NAME,
+ getUnfilteredCompileFlagsSupplier(ccToolchain, features));
+ }
+
+ if (builder.getTempOutputFile() != null) {
+ realOutputFilePath = builder.getTempOutputFile().getPathString();
+ } else {
+ realOutputFilePath = builder.getOutputFile().getExecPathString();
+ }
+
+ if (FileType.contains(outputFile, CppFileTypes.ASSEMBLER, CppFileTypes.PIC_ASSEMBLER)) {
+ buildVariables.addStringVariable(OUTPUT_ASSEMBLY_FILE_VARIABLE_NAME, realOutputFilePath);
+ } else if (FileType.contains(
+ outputFile,
+ CppFileTypes.PREPROCESSED_C,
+ CppFileTypes.PREPROCESSED_CPP,
+ CppFileTypes.PIC_PREPROCESSED_C,
+ CppFileTypes.PIC_PREPROCESSED_CPP)) {
+ buildVariables.addStringVariable(OUTPUT_PREPROCESS_FILE_VARIABLE_NAME, realOutputFilePath);
+ } else {
+ buildVariables.addStringVariable(OUTPUT_OBJECT_FILE_VARIABLE_NAME, realOutputFilePath);
+ }
+
+ DotdFile dotdFile =
+ isGenerateDotdFile(sourceFile) ? Preconditions.checkNotNull(builder.getDotdFile()) : null;
+ // Set dependency_file to enable <object>.d file generation.
+ if (dotdFile != null) {
+ buildVariables.addStringVariable(
+ DEPENDENCY_FILE_VARIABLE_NAME, dotdFile.getSafeExecPath().getPathString());
+ }
+
+ if (featureConfiguration.isEnabled(CppRuleClasses.MODULE_MAPS) && cppModuleMap != null) {
+ // If the feature is enabled and cppModuleMap is null, we are about to fail during analysis
+ // in any case, but don't crash.
+ buildVariables.addStringVariable(MODULE_NAME_VARIABLE_NAME, cppModuleMap.getName());
+ buildVariables.addStringVariable(
+ MODULE_MAP_FILE_VARIABLE_NAME, cppModuleMap.getArtifact().getExecPathString());
+ StringSequenceBuilder sequence = new StringSequenceBuilder();
+ for (Artifact artifact : builderContext.getDirectModuleMaps()) {
+ sequence.addValue(artifact.getExecPathString());
+ }
+ buildVariables.addCustomBuiltVariable(DEPENDENT_MODULE_MAP_FILES_VARIABLE_NAME, sequence);
+ }
+ if (featureConfiguration.isEnabled(CppRuleClasses.USE_HEADER_MODULES)) {
+ // Module inputs will be set later when the action is executed.
+ buildVariables.addStringSequenceVariable(MODULE_FILES_VARIABLE_NAME, ImmutableSet.of());
+ }
+ if (featureConfiguration.isEnabled(CppRuleClasses.INCLUDE_PATHS)) {
+ buildVariables.addStringSequenceVariable(
+ INCLUDE_PATHS_VARIABLE_NAME, getSafePathStrings(builderContext.getIncludeDirs()));
+ buildVariables.addStringSequenceVariable(
+ QUOTE_INCLUDE_PATHS_VARIABLE_NAME,
+ getSafePathStrings(builderContext.getQuoteIncludeDirs()));
+ buildVariables.addStringSequenceVariable(
+ SYSTEM_INCLUDE_PATHS_VARIABLE_NAME,
+ getSafePathStrings(builderContext.getSystemIncludeDirs()));
+ }
+
+ if (featureConfiguration.isEnabled(CppRuleClasses.PREPROCESSOR_DEFINES)) {
+ String fdoBuildStamp = CppHelper.getFdoBuildStamp(ruleContext, fdoSupport.getFdoSupport());
+ ImmutableList<String> defines;
+ if (fdoBuildStamp != null) {
+ // Stamp FDO builds with FDO subtype string
+ defines =
+ ImmutableList.<String>builder()
+ .addAll(builderContext.getDefines())
+ .add(
+ CppConfiguration.FDO_STAMP_MACRO
+ + "=\""
+ + CppHelper.getFdoBuildStamp(ruleContext, fdoSupport.getFdoSupport())
+ + "\"")
+ .build();
+ } else {
+ defines = builderContext.getDefines();
+ }
+
+ buildVariables.addStringSequenceVariable(PREPROCESSOR_DEFINES_VARIABLE_NAME, defines);
+ }
+
+ if (usePic) {
+ if (!featureConfiguration.isEnabled(CppRuleClasses.PIC)) {
+ ruleContext.ruleError(PIC_CONFIGURATION_ERROR);
+ }
+ buildVariables.addStringVariable(PIC_VARIABLE_NAME, "");
+ }
+
+ if (ccRelativeName != null) {
+ fdoSupport
+ .getFdoSupport()
+ .configureCompilation(
+ builder,
+ buildVariables,
+ ruleContext,
+ ccRelativeName,
+ autoFdoImportPath,
+ usePic,
+ featureConfiguration,
+ fdoSupport);
+ }
+ if (gcnoFile != null) {
+ buildVariables.addStringVariable(GCOV_GCNO_FILE_VARIABLE_NAME, gcnoFile.getExecPathString());
+ }
+
+ if (dwoFile != null) {
+ buildVariables.addStringVariable(
+ PER_OBJECT_DEBUG_INFO_FILE_VARIABLE_NAME, dwoFile.getExecPathString());
+ }
+
+ if (ltoIndexingFile != null) {
+ buildVariables.addStringVariable(
+ LTO_INDEXING_BITCODE_FILE_VARIABLE_NAME, ltoIndexingFile.getExecPathString());
+ }
+
+ for (VariablesExtension extension : variablesExtensions) {
+ extension.addVariables(buildVariables);
+ }
+
+ CcToolchainFeatures.Variables variables = buildVariables.build();
+ builder.setVariables(variables);
+ }
+
+ /**
+ * Returns a {@code CppCompileActionBuilder} with the common fields for a C++ compile action being
+ * initialized.
+ */
+ private CppCompileActionBuilder initializeCompileAction(Artifact sourceArtifact) {
+ CppCompileActionBuilder builder = createCompileActionBuilder(sourceArtifact);
+ builder.setFeatureConfiguration(featureConfiguration);
+
+ return builder;
+ }
+
+ /**
+ * Creates a basic cpp compile action builder for source file. Configures options, crosstool
+ * inputs, output and dotd file names, compilation context and copts.
+ */
+ private CppCompileActionBuilder createCompileActionBuilder(Artifact source) {
+ CppCompileActionBuilder builder =
+ new CppCompileActionBuilder(ruleContext, ccToolchain, configuration);
+ builder.setSourceFile(source);
+ builder.setContext(cppCompilationContext);
+ builder.addEnvironment(ccToolchain.getEnvironment());
+ builder.setCoptsFilter(coptsFilter);
+ return builder;
+ }
+
+ private void createModuleCodegenAction(
+ CcCompilationOutputs.Builder result, Label sourceLabel, Artifact module)
+ throws RuleErrorException {
+ if (fake) {
+ // We can't currently foresee a situation where we'd want nocompile tests for module codegen.
+ // If we find one, support needs to be added here.
+ return;
+ }
+ String outputName = module.getRootRelativePath().getPathString();
+
+ // TODO(djasper): Make this less hacky after refactoring how the PIC/noPIC actions are created.
+ boolean pic = module.getFilename().contains(".pic.");
+
+ CppCompileActionBuilder builder = initializeCompileAction(module);
+ builder.setSemantics(semantics);
+ builder.setPicMode(pic);
+ builder.setOutputs(
+ ruleContext, ArtifactCategory.OBJECT_FILE, outputName, isGenerateDotdFile(module));
+ PathFragment ccRelativeName = module.getRootRelativePath();
+
+ String gcnoFileName =
+ CppHelper.getArtifactNameForCategory(
+ ruleContext, ccToolchain, ArtifactCategory.COVERAGE_DATA_FILE, outputName);
+ // TODO(djasper): This is now duplicated. Refactor the various create..Action functions.
+ Artifact gcnoFile =
+ isCodeCoverageEnabled() && !CppHelper.isLipoOptimization(cppConfiguration, ccToolchain)
+ ? CppHelper.getCompileOutputArtifact(ruleContext, gcnoFileName, configuration)
+ : null;
+
+ boolean generateDwo =
+ CppHelper.shouldCreatePerObjectDebugInfo(
+ cppConfiguration, ccToolchain, featureConfiguration);
+ Artifact dwoFile = generateDwo ? getDwoFile(builder.getOutputFile()) : null;
+ // TODO(tejohnson): Add support for ThinLTO if needed.
+ boolean bitcodeOutput =
+ featureConfiguration.isEnabled(CppRuleClasses.THIN_LTO)
+ && CppFileTypes.LTO_SOURCE.matches(module.getFilename());
+ Preconditions.checkState(!bitcodeOutput);
+
+ setupCompileBuildVariables(
+ builder,
+ sourceLabel,
+ /* usePic= */ pic,
+ ccRelativeName,
+ module.getExecPath(),
+ gcnoFile,
+ dwoFile,
+ /* ltoIndexingFile= */ null,
+ builder.getContext().getCppModuleMap());
+
+ builder.setGcnoFile(gcnoFile);
+ builder.setDwoFile(dwoFile);
+
+ semantics.finalizeCompileActionBuilder(ruleContext, builder);
+ CppCompileAction compileAction = builder.buildOrThrowRuleError(ruleContext);
+ AnalysisEnvironment env = ruleContext.getAnalysisEnvironment();
+ env.registerAction(compileAction);
+ Artifact objectFile = compileAction.getOutputFile();
+ if (pic) {
+ result.addPicObjectFile(objectFile);
+ } else {
+ result.addObjectFile(objectFile);
+ }
+ }
+
+ /** Returns true if Dotd file should be generated. */
+ private boolean isGenerateDotdFile(Artifact sourceArtifact) {
+ return CppFileTypes.headerDiscoveryRequired(sourceArtifact)
+ && !featureConfiguration.isEnabled(CppRuleClasses.PARSE_SHOWINCLUDES);
+ }
+
+ private void createHeaderAction(
+ Label sourceLabel,
+ String outputName,
+ CcCompilationOutputs.Builder result,
+ AnalysisEnvironment env,
+ CppCompileActionBuilder builder,
+ boolean generateDotd)
+ throws RuleErrorException {
+ String outputNameBase =
+ CppHelper.getArtifactNameForCategory(
+ ruleContext, ccToolchain, ArtifactCategory.GENERATED_HEADER, outputName);
+
+ builder
+ .setOutputs(ruleContext, ArtifactCategory.PROCESSED_HEADER, outputNameBase, generateDotd)
+ // If we generate pic actions, we prefer the header actions to use the pic artifacts.
+ .setPicMode(getGeneratePicActions());
+ setupCompileBuildVariables(
+ builder,
+ sourceLabel,
+ this.getGeneratePicActions(),
+ /* ccRelativeName= */ null,
+ /* autoFdoImportPath= */ null,
+ /* gcnoFile= */ null,
+ /* dwoFile= */ null,
+ /* ltoIndexingFile= */ null,
+ builder.getContext().getCppModuleMap());
+ semantics.finalizeCompileActionBuilder(ruleContext, builder);
+ CppCompileAction compileAction = builder.buildOrThrowRuleError(ruleContext);
+ env.registerAction(compileAction);
+ Artifact tokenFile = compileAction.getOutputFile();
+ result.addHeaderTokenFile(tokenFile);
+ }
+
+ private Collection<Artifact> createModuleAction(
+ CcCompilationOutputs.Builder result, CppModuleMap cppModuleMap) throws RuleErrorException {
+ AnalysisEnvironment env = ruleContext.getAnalysisEnvironment();
+ Artifact moduleMapArtifact = cppModuleMap.getArtifact();
+ CppCompileActionBuilder builder = initializeCompileAction(moduleMapArtifact);
+
+ builder.setSemantics(semantics);
+
+ // A header module compile action is just like a normal compile action, but:
+ // - the compiled source file is the module map
+ // - it creates a header module (.pcm file).
+ return createSourceAction(
+ Label.parseAbsoluteUnchecked(cppModuleMap.getName()),
+ FileSystemUtils.removeExtension(moduleMapArtifact.getRootRelativePath()).getPathString(),
+ result,
+ env,
+ moduleMapArtifact,
+ builder,
+ ArtifactCategory.CPP_MODULE,
+ cppModuleMap,
+ /* addObject= */ false,
+ /* enableCoverage= */ false,
+ /* generateDwo= */ false,
+ isGenerateDotdFile(moduleMapArtifact));
+ }
+
+ private Collection<Artifact> createSourceAction(
+ Label sourceLabel,
+ String outputName,
+ CcCompilationOutputs.Builder result,
+ AnalysisEnvironment env,
+ Artifact sourceArtifact,
+ CppCompileActionBuilder builder,
+ ArtifactCategory outputCategory,
+ CppModuleMap cppModuleMap,
+ boolean addObject,
+ boolean enableCoverage,
+ boolean generateDwo,
+ boolean generateDotd)
+ throws RuleErrorException {
+ ImmutableList.Builder<Artifact> directOutputs = new ImmutableList.Builder<>();
+ PathFragment ccRelativeName = sourceArtifact.getRootRelativePath();
+ if (CppHelper.isLipoOptimization(cppConfiguration, ccToolchain)) {
+ // 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(), cppCompilationContext));
+ }
+ boolean generatePicAction = getGeneratePicActions();
+ boolean generateNoPicAction = getGenerateNoPicActions();
+ Preconditions.checkState(generatePicAction || generateNoPicAction);
+ if (fake) {
+ boolean usePic = !generateNoPicAction;
+ createFakeSourceAction(
+ sourceLabel,
+ outputName,
+ result,
+ env,
+ builder,
+ outputCategory,
+ addObject,
+ ccRelativeName,
+ sourceArtifact.getExecPath(),
+ usePic,
+ generateDotd);
+ } else {
+ boolean bitcodeOutput =
+ featureConfiguration.isEnabled(CppRuleClasses.THIN_LTO)
+ && CppFileTypes.LTO_SOURCE.matches(sourceArtifact.getFilename());
+
+ // 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.getArtifactNameForCategory(
+ ruleContext, ccToolchain, ArtifactCategory.PIC_FILE, outputName);
+ CppCompileActionBuilder picBuilder =
+ copyAsPicBuilder(builder, picOutputBase, outputCategory, generateDotd);
+ String gcnoFileName =
+ CppHelper.getArtifactNameForCategory(
+ ruleContext, ccToolchain, ArtifactCategory.COVERAGE_DATA_FILE, picOutputBase);
+ Artifact gcnoFile =
+ enableCoverage
+ ? CppHelper.getCompileOutputArtifact(ruleContext, gcnoFileName, configuration)
+ : null;
+ Artifact dwoFile = generateDwo ? getDwoFile(picBuilder.getOutputFile()) : null;
+ Artifact ltoIndexingFile =
+ bitcodeOutput ? getLtoIndexingFile(picBuilder.getOutputFile()) : null;
+
+ setupCompileBuildVariables(
+ picBuilder,
+ sourceLabel,
+ /* usePic= */ true,
+ ccRelativeName,
+ sourceArtifact.getExecPath(),
+ gcnoFile,
+ dwoFile,
+ ltoIndexingFile,
+ cppModuleMap);
+
+ result.addTemps(
+ createTempsActions(
+ sourceArtifact,
+ sourceLabel,
+ outputName,
+ picBuilder,
+ /* usePic= */ true,
+ /* generateDotd= */ generateDotd,
+ ccRelativeName));
+
+ picBuilder.setGcnoFile(gcnoFile);
+ picBuilder.setDwoFile(dwoFile);
+ picBuilder.setLtoIndexingFile(ltoIndexingFile);
+
+ semantics.finalizeCompileActionBuilder(ruleContext, picBuilder);
+ CppCompileAction picAction = picBuilder.buildOrThrowRuleError(ruleContext);
+ env.registerAction(picAction);
+ directOutputs.add(picAction.getOutputFile());
+ if (addObject) {
+ result.addPicObjectFile(picAction.getOutputFile());
+
+ if (bitcodeOutput) {
+ result.addLtoBitcodeFile(picAction.getOutputFile(), ltoIndexingFile);
+ }
+ }
+ 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.getArtifactNameForCategory(
+ ruleContext, ccToolchain, outputCategory, outputName),
+ configuration);
+ builder.setOutputs(ruleContext, outputCategory, outputName, generateDotd);
+ String gcnoFileName =
+ CppHelper.getArtifactNameForCategory(
+ ruleContext, ccToolchain, ArtifactCategory.COVERAGE_DATA_FILE, outputName);
+
+ // Create non-PIC compile actions
+ Artifact gcnoFile =
+ !CppHelper.isLipoOptimization(cppConfiguration, ccToolchain) && enableCoverage
+ ? CppHelper.getCompileOutputArtifact(ruleContext, gcnoFileName, configuration)
+ : null;
+
+ Artifact noPicDwoFile = generateDwo ? getDwoFile(noPicOutputFile) : null;
+ Artifact ltoIndexingFile =
+ bitcodeOutput ? getLtoIndexingFile(builder.getOutputFile()) : null;
+
+ setupCompileBuildVariables(
+ builder,
+ sourceLabel,
+ /* usePic= */ false,
+ ccRelativeName,
+ sourceArtifact.getExecPath(),
+ gcnoFile,
+ noPicDwoFile,
+ ltoIndexingFile,
+ cppModuleMap);
+
+ result.addTemps(
+ createTempsActions(
+ sourceArtifact,
+ sourceLabel,
+ outputName,
+ builder,
+ /* usePic= */ false,
+ generateDotd,
+ ccRelativeName));
+
+ builder.setGcnoFile(gcnoFile);
+ builder.setDwoFile(noPicDwoFile);
+ builder.setLtoIndexingFile(ltoIndexingFile);
+
+ semantics.finalizeCompileActionBuilder(ruleContext, builder);
+ CppCompileAction compileAction = builder.buildOrThrowRuleError(ruleContext);
+ env.registerAction(compileAction);
+ Artifact objectFile = compileAction.getOutputFile();
+ directOutputs.add(objectFile);
+ if (addObject) {
+ result.addObjectFile(objectFile);
+ if (bitcodeOutput) {
+ result.addLtoBitcodeFile(objectFile, ltoIndexingFile);
+ }
+ }
+ if (noPicDwoFile != null) {
+ // Host targets don't produce .dwo files.
+ result.addDwoFile(noPicDwoFile);
+ }
+ if (cppConfiguration.isLipoContextCollector()) {
+ result.addLipoScannable(compileAction);
+ }
+ }
+ }
+ return directOutputs.build();
+ }
+
+ /**
+ * Creates cpp PIC compile action builder from the given builder by adding necessary copt and
+ * changing output and dotd file names.
+ */
+ private CppCompileActionBuilder copyAsPicBuilder(
+ CppCompileActionBuilder builder,
+ String outputName,
+ ArtifactCategory outputCategory,
+ boolean generateDotd)
+ throws RuleErrorException {
+ CppCompileActionBuilder picBuilder = new CppCompileActionBuilder(builder);
+ picBuilder.setPicMode(true).setOutputs(ruleContext, outputCategory, outputName, generateDotd);
+
+ return picBuilder;
+ }
+
+ String getOutputNameBaseWith(String base, boolean usePic) throws RuleErrorException {
+ return usePic
+ ? CppHelper.getArtifactNameForCategory(
+ ruleContext, ccToolchain, ArtifactCategory.PIC_FILE, base)
+ : base;
+ }
+
+ private void createFakeSourceAction(
+ Label sourceLabel,
+ String outputName,
+ CcCompilationOutputs.Builder result,
+ AnalysisEnvironment env,
+ CppCompileActionBuilder builder,
+ ArtifactCategory outputCategory,
+ boolean addObject,
+ PathFragment ccRelativeName,
+ PathFragment execPath,
+ boolean usePic,
+ boolean generateDotd)
+ throws RuleErrorException {
+ String outputNameBase = getOutputNameBaseWith(outputName, usePic);
+ String tempOutputName =
+ ruleContext
+ .getConfiguration()
+ .getBinFragment()
+ .getRelative(CppHelper.getObjDirectory(ruleContext.getLabel()))
+ .getRelative(
+ CppHelper.getArtifactNameForCategory(
+ ruleContext,
+ ccToolchain,
+ outputCategory,
+ getOutputNameBaseWith(outputName + ".temp", usePic)))
+ .getPathString();
+ builder
+ .setPicMode(usePic)
+ .setOutputs(ruleContext, outputCategory, outputNameBase, generateDotd)
+ .setTempOutputFile(PathFragment.create(tempOutputName));
+
+ setupCompileBuildVariables(
+ builder,
+ sourceLabel,
+ usePic,
+ ccRelativeName,
+ execPath,
+ /* gcnoFile= */ null,
+ /* dwoFile= */ null,
+ /* ltoIndexingFile= */ null,
+ builder.getContext().getCppModuleMap());
+ semantics.finalizeCompileActionBuilder(ruleContext, builder);
+ CppCompileAction action = builder.buildOrThrowRuleError(ruleContext);
+ env.registerAction(action);
+ if (addObject) {
+ if (usePic) {
+ result.addPicObjectFile(action.getOutputFile());
+ } else {
+ result.addObjectFile(action.getOutputFile());
+ }
+ }
+ }
+
+ /** Returns true iff code coverage is enabled for the given target. */
+ private boolean isCodeCoverageEnabled() {
+ if (configuration.isCodeCoverageEnabled()) {
+ // If rule is matched by the instrumentation filter, enable instrumentation
+ if (InstrumentedFilesCollector.shouldIncludeLocalSources(ruleContext)) {
+ return true;
+ }
+ // At this point the rule itself is not matched by the instrumentation filter. However, we
+ // might still want to instrument C++ rules if one of the targets listed in "deps" is
+ // instrumented and, therefore, can supply header files that we would want to collect code
+ // coverage for. For example, think about cc_test rule that tests functionality defined in a
+ // header file that is supplied by the cc_library.
+ //
+ // Note that we only check direct prerequisites and not the transitive closure. This is done
+ // for two reasons:
+ // a) It is a good practice to declare libraries which you directly rely on. Including headers
+ // from a library hidden deep inside the transitive closure makes build dependencies less
+ // readable and can lead to unexpected breakage.
+ // b) Traversing the transitive closure for each C++ compile action would require more complex
+ // implementation (with caching results of this method) to avoid O(N^2) slowdown.
+ if (ruleContext.getRule().isAttrDefined("deps", BuildType.LABEL_LIST)) {
+ for (TransitiveInfoCollection dep : ruleContext.getPrerequisites("deps", Mode.TARGET)) {
+ if (dep.getProvider(CppCompilationContext.class) != null
+ && InstrumentedFilesCollector.shouldIncludeLocalSources(configuration, dep)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ private ImmutableList<String> collectPerFileCopts(Artifact sourceFile, Label sourceLabel) {
+ return cppConfiguration
+ .getPerFileCopts()
+ .stream()
+ .filter(
+ perLabelOptions ->
+ (sourceLabel != null && perLabelOptions.isIncluded(sourceLabel))
+ || perLabelOptions.isIncluded(sourceFile))
+ .map(PerLabelOptions::getOptions)
+ .flatMap(options -> options.stream())
+ .collect(ImmutableList.toImmutableList());
+ }
+
+ /** Get the safe path strings for a list of paths to use in the build variables. */
+ private ImmutableSet<String> getSafePathStrings(Collection<PathFragment> paths) {
+ ImmutableSet.Builder<String> result = ImmutableSet.builder();
+ for (PathFragment path : paths) {
+ result.add(path.getSafePathString());
+ }
+ return result.build();
+ }
+
+ private Artifact getDwoFile(Artifact outputFile) {
+ return ruleContext.getRelatedArtifact(outputFile.getRootRelativePath(), ".dwo");
+ }
+
+ private Artifact getLtoIndexingFile(Artifact outputFile) {
+ String ext = Iterables.getOnlyElement(CppFileTypes.LTO_INDEXING_OBJECT_FILE.getExtensions());
+ return ruleContext.getRelatedArtifact(outputFile.getRootRelativePath(), ext);
+ }
+
+ /** Create the actions for "--save_temps". */
+ private ImmutableList<Artifact> createTempsActions(
+ Artifact source,
+ Label sourceLabel,
+ String outputName,
+ CppCompileActionBuilder builder,
+ boolean usePic,
+ boolean generateDotd,
+ PathFragment ccRelativeName)
+ throws RuleErrorException {
+ 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(ruleContext, category, outputArtifactNameBase, generateDotd);
+ setupCompileBuildVariables(
+ dBuilder,
+ sourceLabel,
+ usePic,
+ ccRelativeName,
+ source.getExecPath(),
+ /* gcnoFile= */ null,
+ /* dwoFile= */ null,
+ /* ltoIndexingFile= */ null,
+ builder.getContext().getCppModuleMap());
+ semantics.finalizeCompileActionBuilder(ruleContext, dBuilder);
+ CppCompileAction dAction = dBuilder.buildOrThrowRuleError(ruleContext);
+ ruleContext.registerAction(dAction);
+
+ CppCompileActionBuilder sdBuilder = new CppCompileActionBuilder(builder);
+ sdBuilder.setOutputs(
+ ruleContext, ArtifactCategory.GENERATED_ASSEMBLY, outputArtifactNameBase, generateDotd);
+ setupCompileBuildVariables(
+ sdBuilder,
+ sourceLabel,
+ usePic,
+ ccRelativeName,
+ source.getExecPath(),
+ /* gcnoFile= */ null,
+ /* dwoFile= */ null,
+ /* ltoIndexingFile= */ null,
+ builder.getContext().getCppModuleMap());
+ semantics.finalizeCompileActionBuilder(ruleContext, sdBuilder);
+ CppCompileAction sdAction = sdBuilder.buildOrThrowRuleError(ruleContext);
+ ruleContext.registerAction(sdAction);
+
+ return ImmutableList.of(dAction.getOutputFile(), sdAction.getOutputFile());
}
}