aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build
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
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')
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java1
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java15
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationHelper.java1153
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkingHelper.java428
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchain.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CompileCommandLine.java5
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java7
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkstampCompileHelper.java29
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CppModel.java1699
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoAspect.java2
11 files changed, 1512 insertions, 1831 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java
index 727db97d60..49a3264140 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java
@@ -259,7 +259,6 @@ public abstract class CcBinary implements RuleConfiguredTargetFactory {
ruleContext.getConfiguration())
.fromCommon(common)
.addDeps(ImmutableList.of(CppHelper.mallocForTarget(ruleContext)))
- .setFake(fake)
.enableInterfaceSharedObjects();
linkingHelper.setStaticLinkType(LinkTargetType.STATIC_LIBRARY);
ccLinkingOutputs =
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java
index e9ae312128..69c3f6061d 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java
@@ -70,6 +70,21 @@ import javax.annotation.Nullable;
*/
public final class CcCommon {
+ /** Name of the build variable for the sysroot path variable name. */
+ public static final String SYSROOT_VARIABLE_NAME = "sysroot";
+
+ /** Name of the build variable for the path to the input file being processed. */
+ public static final String INPUT_FILE_VARIABLE_NAME = "input_file";
+
+ /**
+ * Name of the build variable for includes that compiler needs to include into sources to be
+ * compiled.
+ */
+ public static final String INCLUDES_VARIABLE_NAME = "includes";
+
+ /** Name of the build variable for stripopts for the strip action. */
+ public static final String STRIPOPTS_VARIABLE_NAME = "stripopts";
+
private static final String NO_COPTS_ATTRIBUTE = "nocopts";
/**
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());
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java
index d07dd05769..660eff3045 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java
@@ -202,7 +202,7 @@ public abstract class CcLibrary implements RuleConfiguredTargetFactory {
+ "Did you mean to use 'linkstatic=1' instead?");
}
- linkingHelper.setCreateDynamicLibrary(createDynamicLibrary);
+ linkingHelper.setShouldCreateDynamicLibrary(createDynamicLibrary);
linkingHelper.setDynamicLibrary(soImplArtifact);
// If the reason we're not creating a dynamic library is that the toolchain
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkingHelper.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkingHelper.java
index 77dc80f562..0d96ff1b27 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkingHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkingHelper.java
@@ -14,6 +14,7 @@
package com.google.devtools.build.lib.rules.cpp;
+import static com.google.devtools.build.lib.packages.BuildType.LABEL;
import static java.util.stream.Collectors.joining;
import com.google.common.base.Preconditions;
@@ -23,6 +24,8 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import com.google.common.collect.Streams;
import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.FailAction;
+import com.google.devtools.build.lib.analysis.AnalysisEnvironment;
import com.google.devtools.build.lib.analysis.AnalysisUtils;
import com.google.devtools.build.lib.analysis.FileProvider;
import com.google.devtools.build.lib.analysis.LanguageDependentFragment;
@@ -38,13 +41,17 @@ 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.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
-import com.google.devtools.build.lib.rules.cpp.CcCommon.CoptsFilter;
+import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.ExpansionException;
import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration;
import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables.VariablesExtension;
+import com.google.devtools.build.lib.rules.cpp.Link.LinkStaticness;
import com.google.devtools.build.lib.rules.cpp.Link.LinkTargetType;
+import com.google.devtools.build.lib.rules.cpp.Link.Picness;
import com.google.devtools.build.lib.rules.cpp.Link.Staticness;
import com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink;
import com.google.devtools.build.lib.syntax.Type;
+import com.google.devtools.build.lib.vfs.FileSystemUtils;
+import com.google.devtools.build.lib.vfs.PathFragment;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -54,7 +61,7 @@ import javax.annotation.Nullable;
/**
* A class to create C/C++ link 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 CppLinkActionBuilder.
*
* <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
@@ -133,17 +140,18 @@ public final class CcLinkingHelper {
private final RuleContext ruleContext;
private final CppSemantics semantics;
private final BuildConfiguration configuration;
+ private final CppConfiguration cppConfiguration;
private final List<Artifact> nonCodeLinkerInputs = new ArrayList<>();
private final List<String> linkopts = new ArrayList<>();
private final List<TransitiveInfoCollection> deps = new ArrayList<>();
private final NestedSetBuilder<Artifact> linkstamps = NestedSetBuilder.stableOrder();
private final List<Artifact> linkActionInputs = new ArrayList<>();
+ private CppCompilationContext cppCompilationContext;
@Nullable private Artifact dynamicLibrary;
private LinkTargetType linkType = LinkTargetType.STATIC_LIBRARY;
private boolean neverlink;
- private boolean fake;
private final List<LibraryToLink> staticLibraries = new ArrayList<>();
private final List<LibraryToLink> picStaticLibraries = new ArrayList<>();
@@ -155,8 +163,8 @@ public final class CcLinkingHelper {
private boolean emitCcNativeLibrariesProvider;
private boolean emitCcSpecificLinkParamsProvider;
private boolean emitInterfaceSharedObjects;
- private boolean createDynamicLibrary = true;
- private boolean createStaticLibraries = true;
+ private boolean shouldCreateDynamicLibrary = true;
+ private boolean shouldCreateStaticLibraries = true;
private final List<VariablesExtension> variablesExtensions = new ArrayList<>();
private final FeatureConfiguration featureConfiguration;
@@ -187,6 +195,8 @@ public final class CcLinkingHelper {
this.ccToolchain = Preconditions.checkNotNull(ccToolchain);
this.fdoSupport = Preconditions.checkNotNull(fdoSupport);
this.configuration = Preconditions.checkNotNull(configuration);
+ this.cppConfiguration =
+ Preconditions.checkNotNull(ruleContext.getFragment(CppConfiguration.class));
}
/** Sets fields that overlap for cc_library and cc_binary rules. */
@@ -338,17 +348,6 @@ public final class CcLinkingHelper {
return this;
}
- /**
- * Marks the resulting code as fake, i.e., the code will not actually be compiled or linked, but
- * instead, the compile command is written to a file and added to the runfiles. This is currently
- * used for non-compilation tests. Unfortunately, the design is problematic, so please don't add
- * any further uses.
- */
- public CcLinkingHelper setFake(boolean fake) {
- this.fake = fake;
- return this;
- }
-
/*
* Adds a suffix for paths of linked artifacts. Normally their paths are derived solely from rule
* labels. In the case of multiple callers (e.g., aspects) acting on a single rule, they may
@@ -403,14 +402,16 @@ public final class CcLinkingHelper {
* generate a dynamic library. Note that the selection between dynamic or static linking is
* performed at the binary rule level.
*/
- public CcLinkingHelper setCreateDynamicLibrary(boolean emitDynamicLibrary) {
- this.createDynamicLibrary = emitDynamicLibrary;
+ public CcLinkingHelper setShouldCreateDynamicLibrary(boolean emitDynamicLibrary) {
+ this.shouldCreateDynamicLibrary = emitDynamicLibrary;
return this;
}
- /** When createStaticLibraries is true, there are no actions created for static libraries. */
- public CcLinkingHelper setCreateStaticLibraries(boolean emitStaticLibraries) {
- this.createStaticLibraries = emitStaticLibraries;
+ /**
+ * When shouldCreateStaticLibraries is true, there are no actions created for static libraries.
+ */
+ public CcLinkingHelper setShouldCreateStaticLibraries(boolean emitStaticLibraries) {
+ this.shouldCreateStaticLibraries = emitStaticLibraries;
return this;
}
@@ -438,8 +439,7 @@ public final class CcLinkingHelper {
}
}
- CppModel model = initializeCppModel();
- model.setContext(cppCompilationContext);
+ this.cppCompilationContext = cppCompilationContext;
// Create link actions (only if there are object files or if explicitly requested).
CcLinkingOutputs ccLinkingOutputs = CcLinkingOutputs.EMPTY;
@@ -452,7 +452,7 @@ public final class CcLinkingHelper {
// generate any link actions, effectively disabling header checking in some cases.
if (linkType.staticness() == Staticness.STATIC) {
// TODO(bazel-team): This can't create the link action for a cc_binary yet.
- ccLinkingOutputs = model.createCcLinkActions(ccOutputs, nonCodeLinkerInputs);
+ ccLinkingOutputs = createCcLinkActions(ccOutputs, nonCodeLinkerInputs);
}
}
CcLinkingOutputs originalLinkingOutputs = ccLinkingOutputs;
@@ -606,34 +606,6 @@ public final class CcLinkingHelper {
outputGroups.put(DYNAMIC_LIBRARY_OUTPUT_GROUP_NAME, dynamicLibrary.build());
}
- /** Creates the C/C++ compilation action creator. */
- private CppModel initializeCppModel() {
- // TODO(plf): Split CppModel into compilation and linking and stop passing last two arguments.
- return new CppModel(
- ruleContext,
- semantics,
- ccToolchain,
- fdoSupport,
- configuration,
- ImmutableList.of(),
- CoptsFilter.alwaysPasses())
- .setLinkTargetType(linkType)
- .setNeverLink(neverlink)
- .addLinkActionInputs(linkActionInputs)
- .setFake(fake)
- .setAllowInterfaceSharedObjects(emitInterfaceSharedObjects)
- .setCreateDynamicLibrary(createDynamicLibrary)
- .setCreateStaticLibraries(createStaticLibraries)
- // 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)
- .setDynamicLibrary(dynamicLibrary)
- .addLinkopts(linkopts)
- .setFeatureConfiguration(featureConfiguration)
- .addVariablesExtension(variablesExtensions)
- .setLinkedArtifactNameSuffix(linkedArtifactNameSuffix);
- }
-
private Runfiles collectCppRunfiles(
CcLinkingOutputs ccLinkingOutputs, boolean linkingStatically) {
Runfiles.Builder builder =
@@ -703,4 +675,356 @@ public final class CcLinkingHelper {
? CcExecutionDynamicLibrariesProvider.EMPTY
: new CcExecutionDynamicLibrariesProvider(builder.build());
}
+
+ /**
+ * Constructs the C++ linker actions. It generally generates two actions, one for a static library
+ * and one for a dynamic library. If PIC is required for shared libraries, but not for binaries,
+ * it additionally creates a third action to generate a PIC static library. If PIC is required for
+ * shared libraries and binaries, then only PIC actions are registered.
+ *
+ * <p>For dynamic libraries, this method can additionally create an interface shared library that
+ * can be used for linking, but doesn't contain any executable code. This increases the number of
+ * cache hits for link actions. Call {@link #enableInterfaceSharedObjects()} to enable this
+ * behavior.
+ *
+ * @throws RuleErrorException
+ */
+ private CcLinkingOutputs createCcLinkActions(
+ CcCompilationOutputs ccOutputs, Iterable<Artifact> nonCodeLinkerInputs)
+ throws RuleErrorException, InterruptedException {
+ // For now only handle static links. Note that the dynamic library link below ignores linkType.
+ // TODO(bazel-team): Either support non-static links or move this check to setStaticLinkType().
+ Preconditions.checkState(
+ linkType.staticness() == Staticness.STATIC, "can only handle static links");
+
+ CcLinkingOutputs.Builder result = new CcLinkingOutputs.Builder();
+ if (cppConfiguration.isLipoContextCollector()) {
+ // Don't try to create LIPO link actions in collector mode,
+ // because it needs some data that's not available at this point.
+ return result.build();
+ }
+ AnalysisEnvironment env = ruleContext.getAnalysisEnvironment();
+ boolean usePicForBinaries = CppHelper.usePic(ruleContext, ccToolchain, /* forBinary= */ true);
+ boolean usePicForSharedLibs =
+ CppHelper.usePic(ruleContext, ccToolchain, /* forBinary= */ false);
+
+ PathFragment labelName = PathFragment.create(ruleContext.getLabel().getName());
+ String libraryIdentifier =
+ ruleContext
+ .getPackageDirectory()
+ .getRelative(labelName.replaceName("lib" + labelName.getBaseName()))
+ .getPathString();
+
+ if (shouldCreateStaticLibraries) {
+ createStaticLibraries(
+ result,
+ env,
+ usePicForBinaries,
+ usePicForSharedLibs,
+ libraryIdentifier,
+ ccOutputs,
+ nonCodeLinkerInputs);
+ }
+
+ if (shouldCreateDynamicLibrary) {
+ createDynamicLibrary(result, env, usePicForSharedLibs, libraryIdentifier, ccOutputs);
+ }
+
+ return result.build();
+ }
+
+ private void createStaticLibraries(
+ CcLinkingOutputs.Builder result,
+ AnalysisEnvironment env,
+ boolean usePicForBinaries,
+ boolean usePicForSharedLibs,
+ String libraryIdentifier,
+ CcCompilationOutputs ccOutputs,
+ Iterable<Artifact> nonCodeLinkerInputs)
+ throws RuleErrorException, InterruptedException {
+ // Create static library (.a). The linkType only reflects whether the library is alwayslink or
+ // not. The PIC-ness is determined by whether we need to use PIC or not. There are three cases
+ // for (usePicForSharedLibs usePicForBinaries):
+ //
+ // (1) (false false) -> no pic code
+ // (2) (true false) -> shared libraries as pic, but not binaries
+ // (3) (true true) -> both shared libraries and binaries as pic
+ //
+ // In case (3), we always need PIC, so only create one static library containing the PIC
+ // object
+ // files. The name therefore does not match the content.
+ //
+ // Presumably, it is done this way because the .a file is an implicit output of every
+ // cc_library
+ // rule, so we can't use ".pic.a" that in the always-PIC case.
+
+ // If the crosstool is configured to select an output artifact, we use that selection.
+ // Otherwise, we use linux defaults.
+ Artifact linkedArtifact = getLinkedArtifact(linkType);
+
+ CppLinkAction maybePicAction =
+ newLinkActionBuilder(linkedArtifact)
+ .addObjectFiles(ccOutputs.getObjectFiles(usePicForBinaries))
+ .addNonCodeInputs(nonCodeLinkerInputs)
+ .addLtoBitcodeFiles(ccOutputs.getLtoBitcodeFiles())
+ .setLinkType(linkType)
+ .setLinkStaticness(LinkStaticness.FULLY_STATIC)
+ .addActionInputs(linkActionInputs)
+ .setLibraryIdentifier(libraryIdentifier)
+ .addVariablesExtensions(variablesExtensions)
+ .build();
+ env.registerAction(maybePicAction);
+ if (usePicForBinaries) {
+ result.addPicStaticLibrary(maybePicAction.getOutputLibrary());
+ } else {
+ result.addStaticLibrary(maybePicAction.getOutputLibrary());
+ // Create a second static library (.pic.a). Only in case (2) do we need both PIC and non-PIC
+ // static libraries. In that case, the first static library contains the non-PIC code, and
+ // this
+ // one contains the PIC code, so the names match the content.
+ if (usePicForSharedLibs) {
+ LinkTargetType picLinkType =
+ (linkType == LinkTargetType.ALWAYS_LINK_STATIC_LIBRARY)
+ ? LinkTargetType.ALWAYS_LINK_PIC_STATIC_LIBRARY
+ : LinkTargetType.PIC_STATIC_LIBRARY;
+
+ // If the crosstool is configured to select an output artifact, we use that selection.
+ // Otherwise, we use linux defaults.
+ Artifact picArtifact = getLinkedArtifact(picLinkType);
+ CppLinkAction picAction =
+ newLinkActionBuilder(picArtifact)
+ .addObjectFiles(ccOutputs.getObjectFiles(/* usePic= */ true))
+ .addLtoBitcodeFiles(ccOutputs.getLtoBitcodeFiles())
+ .setLinkType(picLinkType)
+ .setLinkStaticness(LinkStaticness.FULLY_STATIC)
+ .addActionInputs(linkActionInputs)
+ .setLibraryIdentifier(libraryIdentifier)
+ .addVariablesExtensions(variablesExtensions)
+ .build();
+ env.registerAction(picAction);
+ result.addPicStaticLibrary(picAction.getOutputLibrary());
+ }
+ }
+ }
+
+ private void createDynamicLibrary(
+ CcLinkingOutputs.Builder result,
+ AnalysisEnvironment env,
+ boolean usePicForSharedLibs,
+ String libraryIdentifier,
+ CcCompilationOutputs ccOutputs)
+ throws RuleErrorException, InterruptedException {
+ // Create dynamic library.
+ Artifact soImpl;
+ String mainLibraryIdentifier;
+ if (dynamicLibrary == null) {
+ // If the crosstool is configured to select an output artifact, we use that selection.
+ // Otherwise, we use linux defaults.
+ soImpl = getLinkedArtifact(LinkTargetType.DYNAMIC_LIBRARY);
+ mainLibraryIdentifier = libraryIdentifier;
+ } else {
+ // This branch is only used for vestigial Google-internal rules where the name of the output
+ // file is explicitly specified in the BUILD file and as such, is platform-dependent. Thus,
+ // we just hardcode some reasonable logic to compute the library identifier and hope that this
+ // will eventually go away.
+ soImpl = dynamicLibrary;
+ mainLibraryIdentifier =
+ FileSystemUtils.removeExtension(soImpl.getRootRelativePath().getPathString());
+ }
+
+ List<String> sonameLinkopts = ImmutableList.of();
+ Artifact soInterface = null;
+ if (CppHelper.useInterfaceSharedObjects(cppConfiguration, ccToolchain)
+ && emitInterfaceSharedObjects) {
+ soInterface =
+ CppHelper.getLinuxLinkedArtifact(
+ ruleContext,
+ configuration,
+ LinkTargetType.INTERFACE_DYNAMIC_LIBRARY,
+ linkedArtifactNameSuffix);
+ // TODO(b/28946988): Remove this hard-coded flag.
+ if (!featureConfiguration.isEnabled(CppRuleClasses.TARGETS_WINDOWS)) {
+ sonameLinkopts =
+ ImmutableList.of(
+ "-Wl,-soname="
+ + SolibSymlinkAction.getDynamicLibrarySoname(
+ soImpl.getRootRelativePath(), /* preserveName= */ false));
+ }
+ }
+
+ CppLinkActionBuilder dynamicLinkActionBuilder =
+ newLinkActionBuilder(soImpl)
+ .setInterfaceOutput(soInterface)
+ .addObjectFiles(ccOutputs.getObjectFiles(usePicForSharedLibs))
+ .addNonCodeInputs(ccOutputs.getHeaderTokenFiles())
+ .addLtoBitcodeFiles(ccOutputs.getLtoBitcodeFiles())
+ .setLinkType(LinkTargetType.DYNAMIC_LIBRARY)
+ .setLinkStaticness(LinkStaticness.DYNAMIC)
+ .addActionInputs(linkActionInputs)
+ .setLibraryIdentifier(mainLibraryIdentifier)
+ .addLinkopts(linkopts)
+ .addLinkopts(sonameLinkopts)
+ .setRuntimeInputs(
+ ArtifactCategory.DYNAMIC_LIBRARY,
+ ccToolchain.getDynamicRuntimeLinkMiddleman(),
+ ccToolchain.getDynamicRuntimeLinkInputs())
+ .addVariablesExtensions(variablesExtensions);
+
+ if (featureConfiguration.isEnabled(CppRuleClasses.TARGETS_WINDOWS)) {
+ // On Windows, we cannot build a shared library with symbols unresolved, so here we
+ // dynamically
+ // link to all it's dependencies.
+ CcLinkParams.Builder ccLinkParamsBuilder =
+ CcLinkParams.builder(/* linkingStatically= */ false, /* linkShared= */ true);
+ ccLinkParamsBuilder.addCcLibrary(ruleContext);
+ dynamicLinkActionBuilder.addLinkParams(ccLinkParamsBuilder.build(), ruleContext);
+
+ // If windows_export_all_symbols feature is enabled, bazel parses object files to generate
+ // DEF file and use it to export symbols. The generated DEF file won't be used if a custom
+ // DEF file is specified by win_def_file attribute.
+ if (CppHelper.shouldUseGeneratedDefFile(ruleContext, featureConfiguration)) {
+ Artifact generatedDefFile =
+ CppHelper.createDefFileActions(
+ ruleContext,
+ ruleContext.getPrerequisiteArtifact("$def_parser", Mode.HOST),
+ ccOutputs.getObjectFiles(false),
+ SolibSymlinkAction.getDynamicLibrarySoname(soImpl.getRootRelativePath(), true));
+ dynamicLinkActionBuilder.setDefFile(generatedDefFile);
+ }
+
+ // If user specifies a custom DEF file, then we use this one instead of the generated one.
+ Artifact customDefFile = null;
+ if (ruleContext.isAttrDefined("win_def_file", LABEL)) {
+ customDefFile = ruleContext.getPrerequisiteArtifact("win_def_file", Mode.TARGET);
+ }
+ if (customDefFile != null) {
+ dynamicLinkActionBuilder.setDefFile(customDefFile);
+ }
+ }
+
+ if (!ccOutputs.getLtoBitcodeFiles().isEmpty()
+ && featureConfiguration.isEnabled(CppRuleClasses.THIN_LTO)) {
+ dynamicLinkActionBuilder.setLtoIndexing(true);
+ dynamicLinkActionBuilder.setUsePicForLtoBackendActions(usePicForSharedLibs);
+ CppLinkAction indexAction = dynamicLinkActionBuilder.build();
+ if (indexAction != null) {
+ env.registerAction(indexAction);
+ }
+
+ dynamicLinkActionBuilder.setLtoIndexing(false);
+ }
+
+ CppLinkAction dynamicLinkAction = dynamicLinkActionBuilder.build();
+ env.registerAction(dynamicLinkAction);
+
+ LibraryToLink dynamicLibrary = dynamicLinkAction.getOutputLibrary();
+ LibraryToLink interfaceLibrary = dynamicLinkAction.getInterfaceOutputLibrary();
+
+ // If shared library has neverlink=1, then leave it untouched. Otherwise,
+ // create a mangled symlink for it and from now on reference it through
+ // mangled name only.
+ //
+ // When COPY_DYNAMIC_LIBRARIES_TO_BINARY is enabled, we don't need to create the special
+ // solibDir, instead we use the original interface library and dynamic library.
+ if (neverlink
+ || featureConfiguration.isEnabled(CppRuleClasses.COPY_DYNAMIC_LIBRARIES_TO_BINARY)) {
+ result.addDynamicLibrary(interfaceLibrary == null ? dynamicLibrary : interfaceLibrary);
+ result.addExecutionDynamicLibrary(dynamicLibrary);
+ } else {
+ Artifact implLibraryLinkArtifact =
+ SolibSymlinkAction.getDynamicLibrarySymlink(
+ ruleContext,
+ ccToolchain.getSolibDirectory(),
+ dynamicLibrary.getArtifact(),
+ /* preserveName= */ false,
+ /* prefixConsumer= */ false,
+ ruleContext.getConfiguration());
+ LibraryToLink implLibraryLink =
+ LinkerInputs.solibLibraryToLink(
+ implLibraryLinkArtifact, dynamicLibrary.getArtifact(), libraryIdentifier);
+ result.addExecutionDynamicLibrary(implLibraryLink);
+
+ LibraryToLink libraryLink;
+ if (interfaceLibrary == null) {
+ libraryLink = implLibraryLink;
+ } else {
+ Artifact libraryLinkArtifact =
+ SolibSymlinkAction.getDynamicLibrarySymlink(
+ ruleContext,
+ ccToolchain.getSolibDirectory(),
+ interfaceLibrary.getArtifact(),
+ /* preserveName= */ false,
+ /* prefixConsumer= */ false,
+ ruleContext.getConfiguration());
+ libraryLink =
+ LinkerInputs.solibLibraryToLink(
+ libraryLinkArtifact, interfaceLibrary.getArtifact(), libraryIdentifier);
+ }
+ result.addDynamicLibrary(libraryLink);
+ }
+ }
+
+ private CppLinkActionBuilder newLinkActionBuilder(Artifact outputArtifact) {
+ return new CppLinkActionBuilder(
+ ruleContext, outputArtifact, ccToolchain, fdoSupport, featureConfiguration, semantics)
+ .setCrosstoolInputs(ccToolchain.getLink())
+ .addNonCodeInputs(cppCompilationContext.getTransitiveCompilationPrerequisites());
+ }
+
+ /**
+ * Returns the linked artifact resulting from a linking of the given type. Consults the feature
+ * configuration to obtain an action_config that provides the artifact. If the feature
+ * configuration provides no artifact, uses a default.
+ *
+ * <p>We cannot assume that the feature configuration contains an action_config for the link
+ * action, because the linux link action depends on hardcoded values in
+ * LinkCommandLine.getRawLinkArgv(), which are applied on the condition that an action_config is
+ * not present. TODO(b/30393154): Assert that the given link action has an action_config.
+ *
+ * @throws RuleErrorException
+ */
+ private Artifact getLinkedArtifact(LinkTargetType linkTargetType) throws RuleErrorException {
+ Artifact result = null;
+ Artifact linuxDefault =
+ CppHelper.getLinuxLinkedArtifact(
+ ruleContext, configuration, linkTargetType, linkedArtifactNameSuffix);
+
+ try {
+ String maybePicName = ruleContext.getLabel().getName() + linkedArtifactNameSuffix;
+ if (linkTargetType.picness() == Picness.PIC) {
+ maybePicName =
+ CppHelper.getArtifactNameForCategory(
+ ruleContext, ccToolchain, ArtifactCategory.PIC_FILE, maybePicName);
+ }
+ String linkedName =
+ CppHelper.getArtifactNameForCategory(
+ ruleContext, ccToolchain, linkTargetType.getLinkerOutput(), maybePicName);
+ PathFragment artifactFragment =
+ PathFragment.create(ruleContext.getLabel().getName())
+ .getParentDirectory()
+ .getRelative(linkedName);
+
+ result =
+ ruleContext.getPackageRelativeArtifact(
+ artifactFragment,
+ configuration.getBinDirectory(ruleContext.getRule().getRepository()));
+ } catch (ExpansionException e) {
+ ruleContext.throwWithRuleError(e.getMessage());
+ }
+
+ // If the linked artifact is not the linux default, then a FailAction is generated for the
+ // linux default to satisfy the requirement of the implicit output.
+ // TODO(b/30132703): Remove the implicit outputs of cc_library.
+ if (!result.equals(linuxDefault)) {
+ ruleContext.registerAction(
+ new FailAction(
+ ruleContext.getActionOwner(),
+ ImmutableList.of(linuxDefault),
+ String.format(
+ "the given toolchain supports creation of %s instead of %s",
+ linuxDefault.getExecPathString(), result.getExecPathString())));
+ }
+
+ return result;
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchain.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchain.java
index f52a13c4a6..885f031fac 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchain.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchain.java
@@ -792,7 +792,7 @@ public class CcToolchain implements RuleConfiguredTargetFactory {
PathFragment sysroot = calculateSysroot(ruleContext, defaultSysroot);
if (sysroot != null) {
- variables.addStringVariable(CppModel.SYSROOT_VARIABLE_NAME, sysroot.getPathString());
+ variables.addStringVariable(CcCommon.SYSROOT_VARIABLE_NAME, sysroot.getPathString());
}
addBuildVariables(ruleContext, variables);
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CompileCommandLine.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CompileCommandLine.java
index 37960deb86..76d9e47223 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CompileCommandLine.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CompileCommandLine.java
@@ -153,8 +153,9 @@ public final class CompileCommandLine {
* explicit attribute, not using platform-dependent garbage bag that copts is).
*/
public ImmutableList<String> getCopts() {
- if (variables.isAvailable(CppModel.USER_COMPILE_FLAGS_VARIABLE_NAME)) {
- return Variables.toStringList(variables, CppModel.USER_COMPILE_FLAGS_VARIABLE_NAME);
+ if (variables.isAvailable(CcCompilationHelper.USER_COMPILE_FLAGS_VARIABLE_NAME)) {
+ return Variables.toStringList(
+ variables, CcCompilationHelper.USER_COMPILE_FLAGS_VARIABLE_NAME);
} else {
return ImmutableList.of();
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java
index 126fda003d..3d0b2c0666 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java
@@ -945,10 +945,11 @@ public class CppHelper {
featureConfiguration.getToolForAction(CppCompileAction.STRIP_ACTION_NAME));
Variables variables =
new Variables.Builder(toolchain.getBuildVariables())
- .addStringVariable(CppModel.OUTPUT_FILE_VARIABLE_NAME, output.getExecPathString())
+ .addStringVariable(
+ CcCompilationHelper.OUTPUT_FILE_VARIABLE_NAME, output.getExecPathString())
.addStringSequenceVariable(
- CppModel.STRIPOPTS_VARIABLE_NAME, cppConfiguration.getStripOpts())
- .addStringVariable(CppModel.INPUT_FILE_VARIABLE_NAME, input.getExecPathString())
+ CcCommon.STRIPOPTS_VARIABLE_NAME, cppConfiguration.getStripOpts())
+ .addStringVariable(CcCommon.INPUT_FILE_VARIABLE_NAME, input.getExecPathString())
.build();
ImmutableList<String> commandLine =
ImmutableList.copyOf(
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkstampCompileHelper.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkstampCompileHelper.java
index dad73d3227..49be968256 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkstampCompileHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkstampCompileHelper.java
@@ -138,39 +138,42 @@ public class CppLinkstampCompileHelper {
Variables.Builder variables = new Variables.Builder(ccToolchainProvider.getBuildVariables());
// We need to force inclusion of build_info headers
variables.addStringSequenceVariable(
- CppModel.INCLUDES_VARIABLE_NAME,
+ CcCommon.INCLUDES_VARIABLE_NAME,
buildInfoHeaderArtifacts
.stream()
.map(Artifact::getExecPathString)
.collect(ImmutableList.toImmutableList()));
// Input/Output files.
- variables.addStringVariable(CppModel.SOURCE_FILE_VARIABLE_NAME, sourceFile.getExecPathString());
- variables.addStringVariable(CppModel.OUTPUT_FILE_VARIABLE_NAME, outputFile.getExecPathString());
variables.addStringVariable(
- CppModel.OUTPUT_OBJECT_FILE_VARIABLE_NAME, outputFile.getExecPathString());
+ CcCompilationHelper.SOURCE_FILE_VARIABLE_NAME, sourceFile.getExecPathString());
+ variables.addStringVariable(
+ CcCompilationHelper.OUTPUT_FILE_VARIABLE_NAME, outputFile.getExecPathString());
+ variables.addStringVariable(
+ CcCompilationHelper.OUTPUT_OBJECT_FILE_VARIABLE_NAME, outputFile.getExecPathString());
// Include directories for (normal includes with ".", empty quote- and system- includes).
variables.addStringSequenceVariable(
- CppModel.INCLUDE_PATHS_VARIABLE_NAME, ImmutableList.of("."));
+ CcCompilationHelper.INCLUDE_PATHS_VARIABLE_NAME, ImmutableList.of("."));
variables.addStringSequenceVariable(
- CppModel.QUOTE_INCLUDE_PATHS_VARIABLE_NAME, ImmutableList.of());
+ CcCompilationHelper.QUOTE_INCLUDE_PATHS_VARIABLE_NAME, ImmutableList.of());
variables.addStringSequenceVariable(
- CppModel.SYSTEM_INCLUDE_PATHS_VARIABLE_NAME, ImmutableList.of());
+ CcCompilationHelper.SYSTEM_INCLUDE_PATHS_VARIABLE_NAME, ImmutableList.of());
// Legacy flags coming from fields such as compiler_flag
variables.addLazyStringSequenceVariable(
- CppModel.LEGACY_COMPILE_FLAGS_VARIABLE_NAME,
- CppModel.getLegacyCompileFlagsSupplier(
+ CcCompilationHelper.LEGACY_COMPILE_FLAGS_VARIABLE_NAME,
+ CcCompilationHelper.getLegacyCompileFlagsSupplier(
cppConfiguration,
ccToolchainProvider,
sourceFile.getExecPathString(),
ImmutableSet.of()));
// Unfilterable flags coming from unfiltered_cxx_flag fields
variables.addLazyStringSequenceVariable(
- CppModel.UNFILTERED_COMPILE_FLAGS_VARIABLE_NAME,
- CppModel.getUnfilteredCompileFlagsSupplier(ccToolchainProvider, ImmutableSet.of()));
+ CcCompilationHelper.UNFILTERED_COMPILE_FLAGS_VARIABLE_NAME,
+ CcCompilationHelper.getUnfilteredCompileFlagsSupplier(
+ ccToolchainProvider, ImmutableSet.of()));
// Collect all preprocessor defines, and in each replace ${LABEL} by labelReplacements, and
// ${OUTPUT_PATH} with outputPathReplacement.
variables.addStringSequenceVariable(
- CppModel.PREPROCESSOR_DEFINES_VARIABLE_NAME,
+ CcCompilationHelper.PREPROCESSOR_DEFINES_VARIABLE_NAME,
computeAllLinkstampDefines(
labelReplacement,
outputReplacement,
@@ -180,7 +183,7 @@ public class CppLinkstampCompileHelper {
codeCoverageEnabled));
// For dynamic libraries, produce position independent code.
if (needsPic) {
- variables.addStringVariable(CppModel.PIC_VARIABLE_NAME, "");
+ variables.addStringVariable(CcCompilationHelper.PIC_VARIABLE_NAME, "");
}
return variables.build();
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppModel.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppModel.java
deleted file mode 100644
index 34c625b5b9..0000000000
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppModel.java
+++ /dev/null
@@ -1,1699 +0,0 @@
-// Copyright 2014 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.devtools.build.lib.packages.BuildType.LABEL;
-
-import com.google.common.base.Preconditions;
-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.actions.FailAction;
-import com.google.devtools.build.lib.analysis.AnalysisEnvironment;
-import com.google.devtools.build.lib.analysis.RuleContext;
-import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
-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.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.ExpansionException;
-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.Link.LinkStaticness;
-import com.google.devtools.build.lib.rules.cpp.Link.LinkTargetType;
-import com.google.devtools.build.lib.rules.cpp.Link.Picness;
-import com.google.devtools.build.lib.rules.cpp.Link.Staticness;
-import com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink;
-import com.google.devtools.build.lib.util.FileType;
-import com.google.devtools.build.lib.vfs.FileSystemUtils;
-import com.google.devtools.build.lib.vfs.PathFragment;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Representation of a C/C++ compilation. Its purpose is to share the code that creates compilation
- * actions between all classes that need to do so. It follows the builder pattern - load up the
- * necessary settings and then call {@link #createCcCompileActions}.
- *
- * <p>This class is not thread-safe, and it should only be used once for each set of source files,
- * i.e. calling {@link #createCcCompileActions} will throw an Exception if called twice.
- */
-public final class CppModel {
-
- /** 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 input file being processed. */
- public static final String INPUT_FILE_VARIABLE_NAME = "input_file";
-
- /** Name of the build variable for the path to the compilation output file. */
- public static final String OUTPUT_FILE_VARIABLE_NAME = "output_file";
-
- /**
- * Name of the build variable for the path to the compilation output file in case of assembly
- * source.
- */
- public static final String OUTPUT_ASSEMBLY_FILE_VARIABLE_NAME = "output_assembly_file";
-
- /**
- * 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 module file name. */
- public static final String MODULE_NAME_VARIABLE_NAME = "module_name";
-
- /** Name of the build variable for the module map file name. */
- public static final String MODULE_MAP_FILE_VARIABLE_NAME = "module_map_file";
-
- /** Name of the build variable for the dependent module map file name. */
- public static final String DEPENDENT_MODULE_MAP_FILES_VARIABLE_NAME =
- "dependent_module_map_files";
-
- /** Name of the build variable for the collection of module files. */
- public static final String MODULE_FILES_VARIABLE_NAME = "module_files";
-
- /**
- * Name of the build variable for includes that compiler needs to include into sources to be
- * compiled.
- */
- public static final String INCLUDES_VARIABLE_NAME = "includes";
-
- /**
- * 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 dependency file path */
- public static final String DEPENDENCY_FILE_VARIABLE_NAME = "dependency_file";
-
- /** 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 gcov coverage file path. */
- public static final String GCOV_GCNO_FILE_VARIABLE_NAME = "gcov_gcno_file";
-
- /** Name of the build variable for the per object debug info file. */
- public 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. */
- public static final String LTO_INDEXING_BITCODE_FILE_VARIABLE_NAME = "lto_indexing_bitcode_file";
-
- /** Name of the build variable for stripopts for the strip action. */
- public static final String STRIPOPTS_VARIABLE_NAME = "stripopts";
-
- /**
- * 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 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 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 sysroot path variable name. */
- public static final String SYSROOT_VARIABLE_NAME = "sysroot";
-
- private static final String PIC_CONFIGURATION_ERROR =
- "PIC compilation is requested but the toolchain does not support it";
-
- private final CppSemantics semantics;
- private final RuleContext ruleContext;
- private final BuildConfiguration configuration;
- private final CppConfiguration cppConfiguration;
-
- // compile model
- private CppCompilationContext context;
- private final Set<CppSource> sourceFiles = new LinkedHashSet<>();
- private final List<Artifact> compilationMandatoryInputs = new ArrayList<>();
- private final List<Artifact> additionalIncludeScanningRoots = new ArrayList<>();
- private final ImmutableList<String> copts;
- private final CoptsFilter coptsFilter;
- private boolean fake;
- private boolean maySaveTemps;
- private CcCompilationOutputs compilationOutputs;
-
- // link model
- private final List<String> linkopts = new ArrayList<>();
- private LinkTargetType linkType = LinkTargetType.STATIC_LIBRARY;
- private boolean neverLink;
- private final List<Artifact> linkActionInputs = new ArrayList<>();
- private boolean allowInterfaceSharedObjects;
- private boolean createDynamicLibrary = true;
- private boolean createStaticLibraries = true;
- private Artifact soImplArtifact;
- private FeatureConfiguration featureConfiguration;
- private List<VariablesExtension> variablesExtensions = new ArrayList<>();
- private final CcToolchainProvider ccToolchain;
- private final FdoSupportProvider fdoSupport;
- private String linkedArtifactNameSuffix = "";
- private final ImmutableSet<String> features;
- private boolean generateNoPic = true;
-
- public CppModel(
- RuleContext ruleContext,
- CppSemantics semantics,
- CcToolchainProvider ccToolchain,
- FdoSupportProvider fdoSupport,
- ImmutableList<String> copts) {
- this(
- ruleContext,
- semantics,
- ccToolchain,
- fdoSupport,
- ruleContext.getConfiguration(),
- copts,
- CoptsFilter.alwaysPasses());
- }
-
- public CppModel(
- RuleContext ruleContext,
- CppSemantics semantics,
- CcToolchainProvider ccToolchain,
- FdoSupportProvider fdoSupport,
- ImmutableList<String> copts,
- CoptsFilter coptsFilter) {
- this(
- ruleContext,
- semantics,
- ccToolchain,
- fdoSupport,
- ruleContext.getConfiguration(),
- copts,
- coptsFilter);
- }
-
- public CppModel(
- RuleContext ruleContext,
- CppSemantics semantics,
- CcToolchainProvider ccToolchain,
- FdoSupportProvider fdoSupport,
- BuildConfiguration configuration,
- ImmutableList<String> copts,
- CoptsFilter coptsFilter) {
- this.ruleContext = Preconditions.checkNotNull(ruleContext);
- this.semantics = semantics;
- this.ccToolchain = Preconditions.checkNotNull(ccToolchain);
- this.fdoSupport = Preconditions.checkNotNull(fdoSupport);
- this.configuration = configuration;
- this.copts = copts;
- this.coptsFilter = Preconditions.checkNotNull(coptsFilter);
- cppConfiguration = ruleContext.getFragment(CppConfiguration.class);
- features = ruleContext.getFeatures();
- }
-
- 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);
- }
-
- /**
- * If the cpp compilation is a fake, then it creates only a single compile action without PIC.
- * Defaults to false.
- */
- public CppModel setFake(boolean fake) {
- this.fake = fake;
- return this;
- }
-
- /**
- * Whether to create actions for temps. This defaults to false.
- */
- public CppModel setSaveTemps(boolean maySaveTemps) {
- this.maySaveTemps = maySaveTemps;
- return this;
- }
-
- /**
- * Sets the compilation context, i.e. include directories and allowed header files inclusions.
- */
- public CppModel setContext(CppCompilationContext context) {
- this.context = context;
- return this;
- }
-
- /**
- * Adds a single source file to be compiled. Note that this should only be called for primary
- * compilation units, including module files or headers to be parsed or preprocessed.
- */
- public CppModel addCompilationUnitSources(
- Iterable<Artifact> sourceFiles, Label sourceLabel, CppSource.Type type) {
- for (Artifact sourceFile : sourceFiles) {
- this.sourceFiles.add(CppSource.create(sourceFile, sourceLabel, type));
- }
- return this;
- }
-
- /**
- * Adds all the source files. Note that this should only be called for primary compilation units,
- * including module files or headers to be parsed or preprocessed.
- */
- public CppModel addCompilationUnitSources(Set<CppSource> sources) {
- this.sourceFiles.addAll(sources);
- return this;
- }
-
- /** Adds compilation mandatory inputs. */
- public CppModel addCompilationMandatoryInputs(Collection<Artifact> compilationMandatoryInputs) {
- this.compilationMandatoryInputs.addAll(compilationMandatoryInputs);
- return this;
- }
-
- /** Adds additional includes to be scanned. */
- public CppModel addAdditionalIncludeScanningRoots(
- Collection<Artifact> additionalIncludeScanningRoots) {
- this.additionalIncludeScanningRoots.addAll(additionalIncludeScanningRoots);
- return this;
- }
-
- /**
- * Adds the given linkopts to the optional dynamic library link command.
- */
- public CppModel addLinkopts(Collection<String> linkopts) {
- this.linkopts.addAll(linkopts);
- return this;
- }
-
- /**
- * Adds the given variablesExensions for templating the crosstool.
- *
- * <p>In general, we prefer the build variables (especially those that derive strictly from
- * the configuration) be learned by inspecting the CcToolchain, as passed to the rule in the
- * CcToolchainProvider. However, for build variables that must be injected into the rule
- * implementation (ex. build variables learned from the BUILD file), should be added using the
- * VariablesExtension abstraction. This allows the injection to construct non-trivial build
- * variables (lists, ect.).
- */
- public CppModel addVariablesExtension(Collection<VariablesExtension> variablesExtensions) {
- this.variablesExtensions.addAll(variablesExtensions);
- return this;
- }
-
- /**
- * Sets the link type used for the link actions. Note that only static links are supported at this
- * time.
- */
- public CppModel setLinkTargetType(LinkTargetType linkType) {
- this.linkType = linkType;
- return this;
- }
-
- public CppModel setNeverLink(boolean neverLink) {
- this.neverLink = neverLink;
- return this;
- }
-
- /**
- * Adds an artifact to the inputs of any link actions created by this CppModel.
- */
- public CppModel addLinkActionInputs(Collection<Artifact> inputs) {
- this.linkActionInputs.addAll(inputs);
- return this;
- }
-
- /**
- * Whether to allow interface dynamic libraries. Note that setting this to true only has an effect
- * if the configuration allows it. Defaults to false.
- */
- public CppModel setAllowInterfaceSharedObjects(boolean allowInterfaceSharedObjects) {
- // TODO(bazel-team): Set the default to true, and require explicit action to disable it.
- this.allowInterfaceSharedObjects = allowInterfaceSharedObjects;
- return this;
- }
-
- public CppModel setCreateDynamicLibrary(boolean createDynamicLibrary) {
- this.createDynamicLibrary = createDynamicLibrary;
- return this;
- }
-
- public CppModel setCreateStaticLibraries(boolean createStaticLibraries) {
- this.createStaticLibraries = createStaticLibraries;
- return this;
- }
-
- public CppModel setDynamicLibrary(Artifact soImplFilename) {
- this.soImplArtifact = soImplFilename;
- return this;
- }
-
- /** Sets the feature configuration to be used for C/C++ actions. */
- public CppModel setFeatureConfiguration(FeatureConfiguration featureConfiguration) {
- this.featureConfiguration = featureConfiguration;
- return this;
- }
-
- /*
- * Adds a suffix for paths of linked artifacts. Normally their paths are derived solely from rule
- * labels. In the case of multiple callers (e.g., aspects) acting on a single rule, they may
- * generate the same linked artifact and therefore lead to artifact conflicts. This method
- * provides a way to avoid this artifact conflict by allowing different callers acting on the same
- * rule to provide a suffix that will be used to scope their own linked artifacts.
- */
- public CppModel setLinkedArtifactNameSuffix(String suffix) {
- this.linkedArtifactNameSuffix = suffix;
- return this;
- }
-
- /** no-PIC actions won't be generated. */
- public CppModel setGenerateNoPic(boolean generateNoPic) {
- this.generateNoPic = generateNoPic;
- return this;
- }
-
- /**
- * @returns whether we want to provide header modules for the current target.
- */
- private boolean shouldProvideHeaderModules() {
- return featureConfiguration.isEnabled(CppRuleClasses.HEADER_MODULES)
- && !cppConfiguration.isLipoContextCollector();
- }
-
- /**
- * @return the non-pic header module artifact for the current target.
- */
- public 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.
- */
- public Artifact getPicHeaderModule(Artifact moduleMapArtifact) {
- PathFragment objectDir = CppHelper.getObjDirectory(ruleContext.getLabel());
- PathFragment outputName = objectDir.getRelative(moduleMapArtifact.getRootRelativePath());
- return ruleContext.getRelatedArtifact(outputName, ".pic.pcm");
- }
-
- /** @return whether this target needs to generate pic actions. */
- private boolean getGeneratePicActions() {
- return featureConfiguration.isEnabled(CppRuleClasses.PIC)
- && CppHelper.usePic(ruleContext, ccToolchain, false);
- }
-
- /** @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 a pic header module.
- */
- public boolean getGeneratesPicHeaderModule() {
- return shouldProvideHeaderModules() && !fake && getGeneratePicActions();
- }
-
- /**
- * @return whether this target needs to generate a non-pic header module.
- */
- public boolean getGeneratesNoPicHeaderModule() {
- return shouldProvideHeaderModules() && !fake && getGenerateNoPicActions();
- }
-
- /**
- * 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;
- }
-
- /** 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();
- }
-
- /**
- * 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);
- }
-
- /**
- * 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();
- };
- }
-
- 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);
- }
-
- 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());
- }
-
- /** Returns true if Dotd file should be generated. */
- private boolean isGenerateDotdFile(Artifact sourceArtifact) {
- return CppFileTypes.headerDiscoveryRequired(sourceArtifact)
- && !featureConfiguration.isEnabled(CppRuleClasses.PARSE_SHOWINCLUDES);
- }
-
- /**
- * 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 CcCompilationOutputs createCcCompileActions() throws RuleErrorException {
- CcCompilationOutputs.Builder result = new CcCompilationOutputs.Builder();
- Preconditions.checkNotNull(context);
- AnalysisEnvironment env = ruleContext.getAnalysisEnvironment();
-
- if (shouldProvideHeaderModules()) {
- Label moduleMapLabel = Label.parseAbsoluteUnchecked(context.getCppModuleMap().getName());
- Collection<Artifact> modules = createModuleAction(result, context.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 (context.getVerificationModuleMap() != null) {
- Collection<Artifact> modules = createModuleAction(result, context.getVerificationModuleMap());
- for (Artifact module : modules) {
- result.addHeaderTokenFile(module);
- }
- }
-
- for (CppSource source : sourceFiles) {
- 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,
- context.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");
- }
- }
- }
-
- compilationOutputs = result.build();
- return compilationOutputs;
- }
-
- 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 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);
- }
- }
-
- 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(),
- context));
- }
- 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);
-
- if (maySaveTemps) {
- 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);
-
- if (maySaveTemps) {
- 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();
- }
-
- 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;
- }
-
- 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 the linked artifact resulting from a linking of the given type. Consults the feature
- * configuration to obtain an action_config that provides the artifact. If the feature
- * configuration provides no artifact, uses a default.
- *
- * <p>We cannot assume that the feature configuration contains an action_config for the link
- * action, because the linux link action depends on hardcoded values in
- * LinkCommandLine.getRawLinkArgv(), which are applied on the condition that an action_config is
- * not present.
- * TODO(b/30393154): Assert that the given link action has an action_config.
- *
- * @throws RuleErrorException
- */
- private Artifact getLinkedArtifact(LinkTargetType linkTargetType) throws RuleErrorException {
- Artifact result = null;
- Artifact linuxDefault =
- CppHelper.getLinuxLinkedArtifact(
- ruleContext, configuration, linkTargetType, linkedArtifactNameSuffix);
-
- try {
- String maybePicName = ruleContext.getLabel().getName() + linkedArtifactNameSuffix;
- if (linkTargetType.picness() == Picness.PIC) {
- maybePicName = CppHelper.getArtifactNameForCategory(
- ruleContext, ccToolchain, ArtifactCategory.PIC_FILE, maybePicName);
- }
- String linkedName = CppHelper.getArtifactNameForCategory(
- ruleContext, ccToolchain, linkTargetType.getLinkerOutput(), maybePicName);
- PathFragment artifactFragment = PathFragment.create(ruleContext.getLabel().getName())
- .getParentDirectory().getRelative(linkedName);
-
- result = ruleContext.getPackageRelativeArtifact(
- artifactFragment, configuration.getBinDirectory(ruleContext.getRule().getRepository()));
- } catch (ExpansionException e) {
- ruleContext.throwWithRuleError(e.getMessage());
- }
-
- // If the linked artifact is not the linux default, then a FailAction is generated for the
- // linux default to satisfy the requirement of the implicit output.
- // TODO(b/30132703): Remove the implicit outputs of cc_library.
- if (!result.equals(linuxDefault)) {
- ruleContext.registerAction(
- new FailAction(
- ruleContext.getActionOwner(),
- ImmutableList.of(linuxDefault),
- String.format(
- "the given toolchain supports creation of %s instead of %s",
- linuxDefault.getExecPathString(), result.getExecPathString())));
- }
-
- return result;
- }
-
- /**
- * Constructs the C++ linker actions. It generally generates two actions, one for a static library
- * and one for a dynamic library. If PIC is required for shared libraries, but not for binaries,
- * it additionally creates a third action to generate a PIC static library.
- *
- * <p>For dynamic libraries, this method can additionally create an interface shared library that
- * can be used for linking, but doesn't contain any executable code. This increases the number of
- * cache hits for link actions. Call {@link #setAllowInterfaceSharedObjects(boolean)} to enable
- * this behavior.
- *
- * @throws RuleErrorException
- */
- public CcLinkingOutputs createCcLinkActions(
- CcCompilationOutputs ccOutputs, Iterable<Artifact> nonCodeLinkerInputs)
- throws RuleErrorException, InterruptedException {
- // For now only handle static links. Note that the dynamic library link below ignores linkType.
- // TODO(bazel-team): Either support non-static links or move this check to setStaticLinkType().
- Preconditions.checkState(
- linkType.staticness() == Staticness.STATIC, "can only handle static links");
-
- CcLinkingOutputs.Builder result = new CcLinkingOutputs.Builder();
- if (cppConfiguration.isLipoContextCollector()) {
- // Don't try to create LIPO link actions in collector mode,
- // because it needs some data that's not available at this point.
- return result.build();
- }
- AnalysisEnvironment env = ruleContext.getAnalysisEnvironment();
- boolean usePicForBinaries = CppHelper.usePic(ruleContext, ccToolchain, /* forBinary= */ true);
- boolean usePicForSharedLibs =
- CppHelper.usePic(ruleContext, ccToolchain, /* forBinary= */ false);
-
- PathFragment labelName = PathFragment.create(ruleContext.getLabel().getName());
- String libraryIdentifier =
- ruleContext
- .getPackageDirectory()
- .getRelative(labelName.replaceName("lib" + labelName.getBaseName()))
- .getPathString();
-
- if (createStaticLibraries) {
- createStaticLibraries(
- result,
- env,
- usePicForBinaries,
- usePicForSharedLibs,
- libraryIdentifier,
- ccOutputs,
- nonCodeLinkerInputs);
- }
-
- if (createDynamicLibrary) {
- createDynamicLibrary(result, env, usePicForSharedLibs, libraryIdentifier, ccOutputs);
- }
-
- return result.build();
- }
-
- private void createStaticLibraries(
- CcLinkingOutputs.Builder result,
- AnalysisEnvironment env,
- boolean usePicForBinaries,
- boolean usePicForSharedLibs,
- String libraryIdentifier,
- CcCompilationOutputs ccOutputs,
- Iterable<Artifact> nonCodeLinkerInputs)
- throws RuleErrorException, InterruptedException {
- // Create static library (.a). The linkType only reflects whether the library is alwayslink or
- // not. The PIC-ness is determined by whether we need to use PIC or not. There are three cases
- // for (usePicForSharedLibs usePicForBinaries):
- //
- // (1) (false false) -> no pic code
- // (2) (true false) -> shared libraries as pic, but not binaries
- // (3) (true true) -> both shared libraries and binaries as pic
- //
- // In case (3), we always need PIC, so only create one static library containing the PIC
- // object
- // files. The name therefore does not match the content.
- //
- // Presumably, it is done this way because the .a file is an implicit output of every
- // cc_library
- // rule, so we can't use ".pic.a" that in the always-PIC case.
-
- // If the crosstool is configured to select an output artifact, we use that selection.
- // Otherwise, we use linux defaults.
- Artifact linkedArtifact = getLinkedArtifact(linkType);
-
- CppLinkAction maybePicAction =
- newLinkActionBuilder(linkedArtifact)
- .addObjectFiles(ccOutputs.getObjectFiles(usePicForBinaries))
- .addNonCodeInputs(nonCodeLinkerInputs)
- .addLtoBitcodeFiles(ccOutputs.getLtoBitcodeFiles())
- .setLinkType(linkType)
- .setLinkStaticness(LinkStaticness.FULLY_STATIC)
- .addActionInputs(linkActionInputs)
- .setLibraryIdentifier(libraryIdentifier)
- .addVariablesExtensions(variablesExtensions)
- .build();
- env.registerAction(maybePicAction);
- if (usePicForBinaries) {
- result.addPicStaticLibrary(maybePicAction.getOutputLibrary());
- } else {
- result.addStaticLibrary(maybePicAction.getOutputLibrary());
- // Create a second static library (.pic.a). Only in case (2) do we need both PIC and non-PIC
- // static libraries. In that case, the first static library contains the non-PIC code, and
- // this
- // one contains the PIC code, so the names match the content.
- if (usePicForSharedLibs) {
- LinkTargetType picLinkType =
- (linkType == LinkTargetType.ALWAYS_LINK_STATIC_LIBRARY)
- ? LinkTargetType.ALWAYS_LINK_PIC_STATIC_LIBRARY
- : LinkTargetType.PIC_STATIC_LIBRARY;
-
- // If the crosstool is configured to select an output artifact, we use that selection.
- // Otherwise, we use linux defaults.
- Artifact picArtifact = getLinkedArtifact(picLinkType);
- CppLinkAction picAction =
- newLinkActionBuilder(picArtifact)
- .addObjectFiles(ccOutputs.getObjectFiles(/* usePic= */ true))
- .addLtoBitcodeFiles(ccOutputs.getLtoBitcodeFiles())
- .setLinkType(picLinkType)
- .setLinkStaticness(LinkStaticness.FULLY_STATIC)
- .addActionInputs(linkActionInputs)
- .setLibraryIdentifier(libraryIdentifier)
- .addVariablesExtensions(variablesExtensions)
- .build();
- env.registerAction(picAction);
- result.addPicStaticLibrary(picAction.getOutputLibrary());
- }
- }
- }
-
- private void createDynamicLibrary(
- CcLinkingOutputs.Builder result,
- AnalysisEnvironment env,
- boolean usePicForSharedLibs,
- String libraryIdentifier,
- CcCompilationOutputs ccOutputs)
- throws RuleErrorException, InterruptedException {
- // Create dynamic library.
- Artifact soImpl;
- String mainLibraryIdentifier;
- if (soImplArtifact == null) {
- // If the crosstool is configured to select an output artifact, we use that selection.
- // Otherwise, we use linux defaults.
- soImpl = getLinkedArtifact(LinkTargetType.DYNAMIC_LIBRARY);
- mainLibraryIdentifier = libraryIdentifier;
- } else {
- // This branch is only used for vestigial Google-internal rules where the name of the output
- // file is explicitly specified in the BUILD file and as such, is platform-dependent. Thus,
- // we just hardcode some reasonable logic to compute the library identifier and hope that this
- // will eventually go away.
- soImpl = soImplArtifact;
- mainLibraryIdentifier = FileSystemUtils.removeExtension(
- soImpl.getRootRelativePath().getPathString());
-
- }
-
- List<String> sonameLinkopts = ImmutableList.of();
- Artifact soInterface = null;
- if (CppHelper.useInterfaceSharedObjects(cppConfiguration, ccToolchain)
- && allowInterfaceSharedObjects) {
- soInterface =
- CppHelper.getLinuxLinkedArtifact(
- ruleContext,
- configuration,
- LinkTargetType.INTERFACE_DYNAMIC_LIBRARY,
- linkedArtifactNameSuffix);
- // TODO(b/28946988): Remove this hard-coded flag.
- if (!featureConfiguration.isEnabled(CppRuleClasses.TARGETS_WINDOWS)) {
- sonameLinkopts =
- ImmutableList.of(
- "-Wl,-soname="
- + SolibSymlinkAction.getDynamicLibrarySoname(
- soImpl.getRootRelativePath(), /* preserveName= */ false));
- }
- }
-
- CppLinkActionBuilder dynamicLinkActionBuilder =
- newLinkActionBuilder(soImpl)
- .setInterfaceOutput(soInterface)
- .addObjectFiles(ccOutputs.getObjectFiles(usePicForSharedLibs))
- .addNonCodeInputs(ccOutputs.getHeaderTokenFiles())
- .addLtoBitcodeFiles(ccOutputs.getLtoBitcodeFiles())
- .setLinkType(LinkTargetType.DYNAMIC_LIBRARY)
- .setLinkStaticness(LinkStaticness.DYNAMIC)
- .addActionInputs(linkActionInputs)
- .setLibraryIdentifier(mainLibraryIdentifier)
- .addLinkopts(linkopts)
- .addLinkopts(sonameLinkopts)
- .setRuntimeInputs(
- ArtifactCategory.DYNAMIC_LIBRARY,
- ccToolchain.getDynamicRuntimeLinkMiddleman(),
- ccToolchain.getDynamicRuntimeLinkInputs())
- .addVariablesExtensions(variablesExtensions);
-
- if (featureConfiguration.isEnabled(CppRuleClasses.TARGETS_WINDOWS)) {
- // On Windows, we cannot build a shared library with symbols unresolved, so here we
- // dynamically
- // link to all it's dependencies.
- CcLinkParams.Builder ccLinkParamsBuilder =
- CcLinkParams.builder(/* linkingStatically= */ false, /* linkShared= */ true);
- ccLinkParamsBuilder.addCcLibrary(ruleContext);
- dynamicLinkActionBuilder.addLinkParams(ccLinkParamsBuilder.build(), ruleContext);
-
- // If windows_export_all_symbols feature is enabled, bazel parses object files to generate
- // DEF file and use it to export symbols. The generated DEF file won't be used if a custom
- // DEF file is specified by win_def_file attribute.
- if (CppHelper.shouldUseGeneratedDefFile(ruleContext, featureConfiguration)) {
- Artifact generatedDefFile =
- CppHelper.createDefFileActions(
- ruleContext,
- ruleContext.getPrerequisiteArtifact("$def_parser", Mode.HOST),
- ccOutputs.getObjectFiles(false),
- SolibSymlinkAction.getDynamicLibrarySoname(soImpl.getRootRelativePath(), true));
- dynamicLinkActionBuilder.setDefFile(generatedDefFile);
- }
-
- // If user specifies a custom DEF file, then we use this one instead of the generated one.
- Artifact customDefFile = null;
- if (ruleContext.isAttrDefined("win_def_file", LABEL)) {
- customDefFile = ruleContext.getPrerequisiteArtifact("win_def_file", Mode.TARGET);
- }
- if (customDefFile != null) {
- dynamicLinkActionBuilder.setDefFile(customDefFile);
- }
- }
-
- if (!ccOutputs.getLtoBitcodeFiles().isEmpty()
- && featureConfiguration.isEnabled(CppRuleClasses.THIN_LTO)) {
- dynamicLinkActionBuilder.setLtoIndexing(true);
- dynamicLinkActionBuilder.setUsePicForLtoBackendActions(usePicForSharedLibs);
- CppLinkAction indexAction = dynamicLinkActionBuilder.build();
- if (indexAction != null) {
- env.registerAction(indexAction);
- }
-
- dynamicLinkActionBuilder.setLtoIndexing(false);
- }
-
- CppLinkAction dynamicLinkAction = dynamicLinkActionBuilder.build();
- env.registerAction(dynamicLinkAction);
-
- LibraryToLink dynamicLibrary = dynamicLinkAction.getOutputLibrary();
- LibraryToLink interfaceLibrary = dynamicLinkAction.getInterfaceOutputLibrary();
-
- // If shared library has neverlink=1, then leave it untouched. Otherwise,
- // create a mangled symlink for it and from now on reference it through
- // mangled name only.
- //
- // When COPY_DYNAMIC_LIBRARIES_TO_BINARY is enabled, we don't need to create the special
- // solibDir, instead we use the original interface library and dynamic library.
- if (neverLink
- || featureConfiguration.isEnabled(CppRuleClasses.COPY_DYNAMIC_LIBRARIES_TO_BINARY)) {
- result.addDynamicLibrary(interfaceLibrary == null ? dynamicLibrary : interfaceLibrary);
- result.addExecutionDynamicLibrary(dynamicLibrary);
- } else {
- Artifact implLibraryLinkArtifact =
- SolibSymlinkAction.getDynamicLibrarySymlink(
- ruleContext,
- ccToolchain.getSolibDirectory(),
- dynamicLibrary.getArtifact(),
- /* preserveName= */ false,
- /* prefixConsumer= */ false,
- ruleContext.getConfiguration());
- LibraryToLink implLibraryLink =
- LinkerInputs.solibLibraryToLink(
- implLibraryLinkArtifact, dynamicLibrary.getArtifact(), libraryIdentifier);
- result.addExecutionDynamicLibrary(implLibraryLink);
-
- LibraryToLink libraryLink;
- if (interfaceLibrary == null) {
- libraryLink = implLibraryLink;
- } else {
- Artifact libraryLinkArtifact =
- SolibSymlinkAction.getDynamicLibrarySymlink(
- ruleContext,
- ccToolchain.getSolibDirectory(),
- interfaceLibrary.getArtifact(),
- /* preserveName= */ false,
- /* prefixConsumer= */ false,
- ruleContext.getConfiguration());
- libraryLink =
- LinkerInputs.solibLibraryToLink(
- libraryLinkArtifact, interfaceLibrary.getArtifact(), libraryIdentifier);
- }
- result.addDynamicLibrary(libraryLink);
- }
- }
-
-
- private CppLinkActionBuilder newLinkActionBuilder(Artifact outputArtifact) {
- return new CppLinkActionBuilder(
- ruleContext, outputArtifact, ccToolchain, fdoSupport, featureConfiguration, semantics)
- .setCrosstoolInputs(ccToolchain.getLink())
- .addNonCodeInputs(context.getTransitiveCompilationPrerequisites());
- }
-
- /**
- * 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(context);
- builder.addEnvironment(ccToolchain.getEnvironment());
- builder.setCoptsFilter(coptsFilter);
- return builder;
- }
-
- /**
- * 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;
- }
-
- /** 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());
- }
-
- /**
- * 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;
- }
-}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoAspect.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoAspect.java
index 2f4e7807e8..bce029f360 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoAspect.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoAspect.java
@@ -273,7 +273,7 @@ public abstract class CcProtoAspect extends NativeAspectClass implements Configu
// TODO(dougk): Configure output artifact with action_config
// once proto compile action is configurable from the crosstool.
if (!ccToolchain(ruleContext).supportsDynamicLinker()) {
- helper.setCreateDynamicLibrary(false);
+ helper.setShouldCreateDynamicLibrary(false);
}
return helper;
}