diff options
author | Rumou Duan <rduan@google.com> | 2017-02-10 17:24:03 +0000 |
---|---|---|
committer | Kristina Chodorow <kchodorow@google.com> | 2017-02-10 18:19:31 +0000 |
commit | 5490757be5e527df82eee5094a0f59c86a5de766 (patch) | |
tree | 6d75800e0348de7e3472dd37de75d467a65fb468 /src/main/java/com/google/devtools/build/lib/rules | |
parent | 762576e5e7a3ee0da39dbb24134cb8530cbb911e (diff) |
Introduce CppCompileActionTemplate, which expands into a list of CppCompileActions that to be executed at execution time.
--
PiperOrigin-RevId: 147163077
MOS_MIGRATED_REVID=147163077
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/rules')
13 files changed, 590 insertions, 220 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationOutputs.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationOutputs.java index f601913dc2..f70a4ed28b 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationOutputs.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationOutputs.java @@ -200,7 +200,10 @@ public class CcCompilationOutputs { * Adds an .o file. */ public Builder addObjectFile(Artifact artifact) { - Preconditions.checkArgument(Link.OBJECT_FILETYPES.matches(artifact.getFilename())); + // We skip file extension checks for TreeArtifacts because they represent directory artifacts + // without a file extension. + Preconditions.checkArgument( + artifact.isTreeArtifact() || Link.OBJECT_FILETYPES.matches(artifact.getFilename())); objectFiles.add(artifact); return this; } diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java index 355d01b00b..9d5295764e 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java @@ -451,13 +451,16 @@ public final class CcLibraryHelper { * file type also to compilationUnitSources. */ private void addHeader(Artifact header, Label label) { - boolean isHeader = CppFileTypes.CPP_HEADER.matches(header.getExecPath()); + // We assume TreeArtifacts passed in are directories containing proper headers. + boolean isHeader = + CppFileTypes.CPP_HEADER.matches(header.getExecPath()) || header.isTreeArtifact(); boolean isTextualInclude = CppFileTypes.CPP_TEXTUAL_INCLUDE.matches(header.getExecPath()); publicHeaders.add(header); if (isTextualInclude || !isHeader || !shouldProcessHeaders()) { return; } - compilationUnitSources.add(CppSource.create(header, label, ImmutableMap.<String, String>of())); + compilationUnitSources.add( + CppSource.create(header, label, ImmutableMap.<String, String>of(), CppSource.Type.HEADER)); } /** Adds a header to {@code publicHeaders}, but not to this target's module map. */ @@ -476,14 +479,26 @@ public final class CcLibraryHelper { Preconditions.checkNotNull(featureConfiguration); boolean isHeader = CppFileTypes.CPP_HEADER.matches(source.getExecPath()); boolean isTextualInclude = CppFileTypes.CPP_TEXTUAL_INCLUDE.matches(source.getExecPath()); - boolean isCompiledSource = sourceCategory.getSourceTypes().matches(source.getExecPathString()); + // We assume TreeArtifacts passed in are directories containing proper sources for compilation. + boolean isCompiledSource = + sourceCategory.getSourceTypes().matches(source.getExecPathString()) + || source.isTreeArtifact(); if (isHeader || isTextualInclude) { privateHeaders.add(source); } if (isTextualInclude || !isCompiledSource || (isHeader && !shouldProcessHeaders())) { return; } - compilationUnitSources.add(CppSource.create(source, label, buildVariables)); + boolean isClifInputProto = CppFileTypes.CLIF_INPUT_PROTO.matches(source.getExecPathString()); + CppSource.Type type; + if (isHeader) { + type = CppSource.Type.HEADER; + } else if (isClifInputProto) { + type = CppSource.Type.CLIF_INPUT_PROTO; + } else { + type = CppSource.Type.SOURCE; + } + compilationUnitSources.add(CppSource.create(source, label, buildVariables, type)); } private boolean shouldProcessHeaders() { diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainFeatures.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainFeatures.java index f9295c684a..3d03ece32d 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainFeatures.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainFeatures.java @@ -1407,6 +1407,13 @@ public class CcToolchainFeatures implements Serializable { private final Map<String, VariableValue> variablesMap = new LinkedHashMap<>(); private final Map<String, String> stringVariablesMap = new LinkedHashMap<>(); + public Builder() {}; + + public Builder(Variables variables) { + variablesMap.putAll(variables.variablesMap); + stringVariablesMap.putAll(variables.stringVariablesMap); + } + /** Add a variable that expands {@code name} to {@code value}. */ public Builder addStringVariable(String name, String value) { Preconditions.checkArgument( @@ -1419,6 +1426,14 @@ public class CcToolchainFeatures implements Serializable { return this; } + /** Overrides a variable to expands {@code name} to {@code value} instead. */ + public Builder overrideStringVariable(String name, String value) { + Preconditions.checkNotNull( + value, "Cannot set null as a value for variable '%s'", name); + stringVariablesMap.put(name, value); + return this; + } + /** * Add a sequence variable that expands {@code name} to {@code values}. * diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileAction.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileAction.java index 6d73265772..c51edff2f9 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileAction.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileAction.java @@ -36,7 +36,6 @@ import com.google.devtools.build.lib.actions.Executor; import com.google.devtools.build.lib.actions.ResourceSet; import com.google.devtools.build.lib.actions.extra.CppCompileInfo; import com.google.devtools.build.lib.actions.extra.ExtraActionInfo; -import com.google.devtools.build.lib.analysis.RuleContext; import com.google.devtools.build.lib.analysis.config.PerLabelOptions; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.collect.CollectionUtils; @@ -236,6 +235,7 @@ public class CppCompileAction extends AbstractAction * Creates a new action to compile C/C++ source files. * * @param owner the owner of the action, usually the configured target that emitted it + * @param allInputs the list of all action inputs. * @param features TODO(bazel-team): Add parameter description. * @param featureConfiguration TODO(bazel-team): Add parameter description. * @param variables TODO(bazel-team): Add parameter description. @@ -266,14 +266,15 @@ public class CppCompileAction extends AbstractAction * @param executionRequirements out-of-band hints to be passed to the execution backend to signal * platform requirements * @param environment TODO(bazel-team): Add parameter description + * @param builtinIncludeFiles List of include files that may be included even if they are not + * mentioned in the source file or any of the headers included by it * @param actionName a string giving the name of this action for the purpose of toolchain * evaluation - * @param ruleContext The rule-context that produced this action * @param cppSemantics C++ compilation semantics - * @param ccToolchain C++ toolchain provider */ protected CppCompileAction( ActionOwner owner, + NestedSet<Artifact> allInputs, // TODO(bazel-team): Eventually we will remove 'features'; all functionality in 'features' // will be provided by 'featureConfiguration'. ImmutableList<String> features, @@ -306,18 +307,11 @@ public class CppCompileAction extends AbstractAction ImmutableMap<String, String> executionInfo, ImmutableMap<String, String> environment, String actionName, - RuleContext ruleContext, - CppSemantics cppSemantics, - CcToolchainProvider ccToolchain) { + Iterable<Artifact> builtinIncludeFiles, + CppSemantics cppSemantics) { super( owner, - createInputs( - ruleContext, - ccToolchain, - mandatoryInputs, - context.getTransitiveCompilationPrerequisites(), - optionalSourceFile, - lipoScannables), + allInputs, CollectionUtils.asListWithoutNulls( outputFile, (dotdFile == null ? null : dotdFile.artifact()), gcnoFile, dwoFile)); this.localShellEnvironment = localShellEnvironment; @@ -351,81 +345,12 @@ public class CppCompileAction extends AbstractAction // artifact and will definitely exist prior to this action execution. this.mandatoryInputs = mandatoryInputs; this.prunableInputs = prunableInputs; - this.builtinIncludeFiles = ccToolchain.getBuiltinIncludeFiles(); + this.builtinIncludeFiles = ImmutableList.copyOf(builtinIncludeFiles); this.cppSemantics = cppSemantics; - if (cppSemantics.needsIncludeValidation()) { - verifyIncludePaths(ruleContext); - } this.additionalIncludeScannables = ImmutableList.copyOf(additionalIncludeScannables); } /** - * Verifies that the include paths of this action are within the limits of the execution root. - */ - private void verifyIncludePaths(RuleContext ruleContext) { - if (ruleContext == null) { - return; - } - - Iterable<PathFragment> ignoredDirs = getValidationIgnoredDirs(); - - // We currently do not check the output of: - // - getQuoteIncludeDirs(): those only come from includes attributes, and are checked in - // CcCommon.getIncludeDirsFromIncludesAttribute(). - // - getBuiltinIncludeDirs(): while in practice this doesn't happen, bazel can be configured - // to use an absolute system root, in which case the builtin include dirs might be absolute. - for (PathFragment include : Iterables.concat(getIncludeDirs(), getSystemIncludeDirs())) { - - // Ignore headers from built-in include directories. - if (FileSystemUtils.startsWithAny(include, ignoredDirs)) { - continue; - } - - // One starting ../ is okay for getting to a sibling repository. - if (include.startsWith(new PathFragment(Label.EXTERNAL_PATH_PREFIX))) { - include = include.relativeTo(Label.EXTERNAL_PATH_PREFIX); - } - - if (include.isAbsolute() - || !PathFragment.EMPTY_FRAGMENT.getRelative(include).normalize().isNormalized()) { - ruleContext.ruleError( - "The include path '" + include + "' references a path outside of the execution root."); - } - } - } - - private static NestedSet<Artifact> createInputs( - RuleContext ruleContext, - CcToolchainProvider ccToolchain, - NestedSet<Artifact> mandatoryInputs, - Set<Artifact> prerequisites, - Artifact optionalSourceFile, - Iterable<IncludeScannable> lipoScannables) { - NestedSetBuilder<Artifact> builder = NestedSetBuilder.stableOrder(); - if (optionalSourceFile != null) { - builder.add(optionalSourceFile); - } - builder.addAll(prerequisites); - builder.addAll(ccToolchain.getBuiltinIncludeFiles()); - builder.addTransitive(mandatoryInputs); - if (lipoScannables != null && lipoScannables.iterator().hasNext()) { - // We need to add "legal generated scanner files" coming through LIPO scannables here. These - // usually contain pre-grepped source files, i.e. files just containing the #include lines - // extracted from generated files. With LIPO, some of these files can be accessed, even though - // there is no direct dependency on them. Adding the artifacts as inputs to this compile - // action ensures that the action generating them is actually executed. - for (IncludeScannable lipoScannable : lipoScannables) { - for (Artifact value : lipoScannable.getLegalGeneratedScannerFileMap().values()) { - if (value != null) { - builder.add(value); - } - } - } - } - return builder.build(); - } - - /** * Whether we should do "include scanning". Note that this does *not* mean whether we should parse * the .d files to determine which include files were used during compilation. Instead, this means * whether we should a) run the pre-execution include scanner (see {@code IncludeScanningContext}) @@ -959,7 +884,7 @@ public class CppCompileAction extends AbstractAction errors.assertProblemFree(this, getSourceFile()); } - private Iterable<PathFragment> getValidationIgnoredDirs() { + Iterable<PathFragment> getValidationIgnoredDirs() { List<PathFragment> cxxSystemIncludeDirs = cppConfiguration.getBuiltInIncludeDirectories(); return Iterables.concat( cxxSystemIncludeDirs, context.getSystemIncludeDirs()); @@ -1383,7 +1308,7 @@ public class CppCompileAction extends AbstractAction CcToolchainFeatures.Variables variables, String actionName) { this.sourceFile = Preconditions.checkNotNull(sourceFile); - this.dotdFile = CppFileTypes.mustProduceDotdFile(sourceFile.getPath().toString()) + this.dotdFile = CppFileTypes.mustProduceDotdFile(sourceFile) ? Preconditions.checkNotNull(dotdFile) : null; this.copts = Preconditions.checkNotNull(copts); this.coptsFilter = coptsFilter; diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileActionBuilder.java index ee606bc14b..39e7ff95b3 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileActionBuilder.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileActionBuilder.java @@ -22,7 +22,6 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import com.google.devtools.build.lib.actions.ActionOwner; import com.google.devtools.build.lib.actions.Artifact; -import com.google.devtools.build.lib.analysis.AnalysisEnvironment; import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode; import com.google.devtools.build.lib.analysis.RuleContext; import com.google.devtools.build.lib.analysis.config.BuildConfiguration; @@ -34,12 +33,14 @@ import com.google.devtools.build.lib.rules.cpp.CppCompileAction.DotdFile; import com.google.devtools.build.lib.rules.cpp.CppCompileAction.SpecialInputsHandler; import com.google.devtools.build.lib.util.FileType; import com.google.devtools.build.lib.util.Preconditions; +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.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.UUID; import java.util.regex.Pattern; @@ -53,7 +54,7 @@ public class CppCompileActionBuilder { private final List<String> features = new ArrayList<>(); private CcToolchainFeatures.FeatureConfiguration featureConfiguration; private CcToolchainFeatures.Variables variables; - private final Artifact sourceFile; + private Artifact sourceFile; private final Label sourceLabel; private final NestedSetBuilder<Artifact> mandatoryInputsBuilder; private Artifact optionalSourceFile; @@ -62,12 +63,10 @@ public class CppCompileActionBuilder { private PathFragment tempOutputFile; private DotdFile dotdFile; private Artifact gcnoFile; - private final BuildConfiguration configuration; private CppCompilationContext context = CppCompilationContext.EMPTY; private final List<String> copts = new ArrayList<>(); private final List<String> pluginOpts = new ArrayList<>(); private final List<Pattern> nocopts = new ArrayList<>(); - private AnalysisEnvironment analysisEnvironment; private ImmutableList<PathFragment> extraSystemIncludePrefixes = ImmutableList.of(); private boolean usePic; private boolean allowUsingHeaderModules; @@ -78,34 +77,50 @@ public class CppCompileActionBuilder { private ImmutableMap<Artifact, IncludeScannable> lipoScannableMap; private final ImmutableList.Builder<Artifact> additionalIncludeFiles = new ImmutableList.Builder<>(); - private RuleContext ruleContext = null; private Boolean shouldScanIncludes; private Map<String, String> executionInfo = new LinkedHashMap<>(); private Map<String, String> environment = new LinkedHashMap<>(); private CppSemantics cppSemantics; private CcToolchainProvider ccToolchain; + private final ImmutableMap<String, String> localShellEnvironment; + private final boolean codeCoverageEnabled; // New fields need to be added to the copy constructor. /** * Creates a builder from a rule. This also uses the configuration and * artifact factory from the rule. */ - public CppCompileActionBuilder(RuleContext ruleContext, Artifact sourceFile, Label sourceLabel, + public CppCompileActionBuilder(RuleContext ruleContext, Label sourceLabel, CcToolchainProvider ccToolchain) { - this.owner = ruleContext.getActionOwner(); - this.actionContext = CppCompileActionContext.class; - this.cppConfiguration = ruleContext.getFragment(CppConfiguration.class); - this.analysisEnvironment = ruleContext.getAnalysisEnvironment(); - this.sourceFile = sourceFile; + this( + ruleContext.getActionOwner(), + sourceLabel, + ruleContext.getFragment(CppConfiguration.class), + ruleContext.getConfiguration(), + getLipoScannableMap(ruleContext), + ruleContext.getFeatures(), + ccToolchain); + } + + private CppCompileActionBuilder( + ActionOwner actionOwner, + Label sourceLabel, + CppConfiguration cppConfiguration, + BuildConfiguration configuration, + Map<Artifact, IncludeScannable> lipoScannableMap, + Set<String> features, + CcToolchainProvider ccToolchain) { + this.owner = actionOwner; this.sourceLabel = sourceLabel; - this.configuration = ruleContext.getConfiguration(); + this.cppConfiguration = cppConfiguration; + this.lipoScannableMap = ImmutableMap.copyOf(lipoScannableMap); + this.features.addAll(features); this.mandatoryInputsBuilder = NestedSetBuilder.stableOrder(); - this.lipoScannableMap = getLipoScannableMap(ruleContext); - this.ruleContext = ruleContext; this.allowUsingHeaderModules = true; + this.localShellEnvironment = configuration.getLocalShellEnvironment(); + this.codeCoverageEnabled = configuration.isCodeCoverageEnabled(); + this.actionContext = CppCompileActionContext.class; this.ccToolchain = ccToolchain; - - features.addAll(ruleContext.getFeatures()); } private static ImmutableMap<Artifact, IncludeScannable> getLipoScannableMap( @@ -115,7 +130,7 @@ public class CppCompileActionBuilder { // contain headers, will still create CppCompileActions without providing a // lipo_context_collector. || ruleContext.attributes().getAttributeDefinition(":lipo_context_collector") == null) { - return null; + return ImmutableMap.<Artifact, IncludeScannable>of(); } LipoContextProvider provider = ruleContext.getPrerequisite( ":lipo_context_collector", Mode.DONT_CHECK, LipoContextProvider.class); @@ -129,6 +144,7 @@ public class CppCompileActionBuilder { this.owner = other.owner; this.features.addAll(other.features); this.featureConfiguration = other.featureConfiguration; + this.variables = other.variables; this.sourceFile = other.sourceFile; this.sourceLabel = other.sourceLabel; this.mandatoryInputsBuilder = NestedSetBuilder.<Artifact>stableOrder() @@ -139,12 +155,10 @@ public class CppCompileActionBuilder { this.tempOutputFile = other.tempOutputFile; this.dotdFile = other.dotdFile; this.gcnoFile = other.gcnoFile; - this.configuration = other.configuration; this.context = other.context; this.copts.addAll(other.copts); this.pluginOpts.addAll(other.pluginOpts); this.nocopts.addAll(other.nocopts); - this.analysisEnvironment = other.analysisEnvironment; this.extraSystemIncludePrefixes = ImmutableList.copyOf(other.extraSystemIncludePrefixes); this.specialInputsHandler = other.specialInputsHandler; this.actionClassId = other.actionClassId; @@ -153,10 +167,11 @@ public class CppCompileActionBuilder { this.usePic = other.usePic; this.allowUsingHeaderModules = other.allowUsingHeaderModules; this.lipoScannableMap = other.lipoScannableMap; - this.ruleContext = other.ruleContext; this.shouldScanIncludes = other.shouldScanIncludes; this.executionInfo = new LinkedHashMap<>(other.executionInfo); this.environment = new LinkedHashMap<>(other.environment); + this.localShellEnvironment = other.localShellEnvironment; + this.codeCoverageEnabled = other.codeCoverageEnabled; this.cppSemantics = other.cppSemantics; this.ccToolchain = other.ccToolchain; } @@ -165,6 +180,11 @@ public class CppCompileActionBuilder { return tempOutputFile; } + public CppCompileActionBuilder setSourceFile(Artifact sourceFile) { + this.sourceFile = sourceFile; + return this; + } + public Artifact getSourceFile() { return sourceFile; } @@ -198,16 +218,21 @@ public class CppCompileActionBuilder { } private Iterable<IncludeScannable> getLipoScannables(NestedSet<Artifact> realMandatoryInputs) { - return lipoScannableMap == null ? ImmutableList.<IncludeScannable>of() : Iterables.filter( - Iterables.transform( - Iterables.filter( - FileType.filter( - realMandatoryInputs, - CppFileTypes.C_SOURCE, CppFileTypes.CPP_SOURCE, - CppFileTypes.ASSEMBLER_WITH_C_PREPROCESSOR), - Predicates.not(Predicates.equalTo(getSourceFile()))), - Functions.forMap(lipoScannableMap, null)), - Predicates.notNull()); + boolean fake = tempOutputFile != null; + + return lipoScannableMap == null || fake + ? ImmutableList.<IncludeScannable>of() + : Iterables.filter( + Iterables.transform( + Iterables.filter( + FileType.filter( + realMandatoryInputs, + CppFileTypes.C_SOURCE, + CppFileTypes.CPP_SOURCE, + CppFileTypes.ASSEMBLER_WITH_C_PREPROCESSOR), + Predicates.not(Predicates.equalTo(getSourceFile()))), + Functions.forMap(lipoScannableMap, null)), + Predicates.notNull()); } private String getActionName() { @@ -248,7 +273,23 @@ public class CppCompileActionBuilder { } /** - * Builds the Action as configured and returns the to be generated Artifact. + * Builds the action and performs some validations on the action. + * + * <p>This method may be called multiple times to create multiple compile + * actions (usually after calling some setters to modify the generated + * action). + */ + public CppCompileAction buildAndValidate(RuleContext ruleContext) { + CppCompileAction action = build(); + if (cppSemantics.needsIncludeValidation()) { + verifyActionIncludePaths(action, ruleContext); + } + return action; + } + + /** + * Builds the Action as configured without validations. Users may want to call + * {@link #buildAndValidate} instead. * * <p>This method may be called multiple times to create multiple compile * actions (usually after calling some setters to modify the generated @@ -262,19 +303,6 @@ public class CppCompileActionBuilder { allowUsingHeaderModules && featureConfiguration.isEnabled(CppRuleClasses.USE_HEADER_MODULES); - boolean fake = tempOutputFile != null; - // Configuration can be null in tests. - NestedSetBuilder<Artifact> realMandatoryInputsBuilder = NestedSetBuilder.compileOrder(); - realMandatoryInputsBuilder.addTransitive(mandatoryInputsBuilder.build()); - boolean shouldPruneModules = - cppConfiguration.getPruneCppModules() && shouldScanIncludes && useHeaderModules; - if (useHeaderModules && !shouldPruneModules) { - realMandatoryInputsBuilder.addTransitive(context.getTransitiveModules(usePic)); - } - realMandatoryInputsBuilder.addTransitive(context.getAdditionalInputs()); - - realMandatoryInputsBuilder.add(sourceFile); - // If the crosstool uses action_configs to configure cc compilation, collect execution info // from there, otherwise, use no execution info. // TODO(b/27903698): Assert that the crosstool has an action_config for this action. @@ -285,7 +313,8 @@ public class CppCompileActionBuilder { } } - NestedSet<Artifact> realMandatoryInputs = realMandatoryInputsBuilder.build(); + NestedSet<Artifact> realMandatoryInputs = buildMandatoryInputs(); + NestedSet<Artifact> allInputs = buildAllInputs(); NestedSetBuilder<Artifact> prunableInputBuilder = NestedSetBuilder.stableOrder(); prunableInputBuilder.addTransitive(context.getDeclaredIncludeSrcs()); @@ -294,15 +323,17 @@ public class CppCompileActionBuilder { NestedSet<Artifact> prunableInputs = prunableInputBuilder.build(); // Copying the collections is needed to make the builder reusable. + boolean fake = tempOutputFile != null; if (fake) { return new FakeCppCompileAction( owner, + allInputs, ImmutableList.copyOf(features), featureConfiguration, variables, sourceFile, shouldScanIncludes, - shouldPruneModules, + shouldPruneModules(), usePic, useHeaderModules, sourceLabel, @@ -311,25 +342,27 @@ public class CppCompileActionBuilder { outputFile, tempOutputFile, dotdFile, - configuration, + localShellEnvironment, + codeCoverageEnabled, cppConfiguration, context, actionContext, ImmutableList.copyOf(copts), getNocoptPredicate(nocopts), - ruleContext, + getLipoScannables(realMandatoryInputs), + ccToolchain.getBuiltinIncludeFiles(), cppSemantics, - ccToolchain, ImmutableMap.copyOf(executionInfo)); } else { return new CppCompileAction( owner, + allInputs, ImmutableList.copyOf(features), featureConfiguration, variables, sourceFile, shouldScanIncludes, - shouldPruneModules, + shouldPruneModules(), usePic, useHeaderModules, sourceLabel, @@ -340,8 +373,8 @@ public class CppCompileActionBuilder { gcnoFile, dwoFile, optionalSourceFile, - configuration.getLocalShellEnvironment(), - configuration.isCodeCoverageEnabled(), + localShellEnvironment, + codeCoverageEnabled, cppConfiguration, context, actionContext, @@ -354,9 +387,84 @@ public class CppCompileActionBuilder { ImmutableMap.copyOf(executionInfo), ImmutableMap.copyOf(environment), getActionName(), - ruleContext, - cppSemantics, - ccToolchain); + ccToolchain.getBuiltinIncludeFiles(), + cppSemantics); + } + } + + /** + * Returns the list of mandatory inputs for the {@link CppCompileAction} as configured. + */ + NestedSet<Artifact> buildMandatoryInputs() { + NestedSetBuilder<Artifact> realMandatoryInputsBuilder = NestedSetBuilder.compileOrder(); + realMandatoryInputsBuilder.addTransitive(mandatoryInputsBuilder.build()); + if (useHeaderModules() && !shouldPruneModules()) { + realMandatoryInputsBuilder.addTransitive(context.getTransitiveModules(usePic)); + } + realMandatoryInputsBuilder.addTransitive(context.getAdditionalInputs()); + realMandatoryInputsBuilder.add(Preconditions.checkNotNull(sourceFile)); + return realMandatoryInputsBuilder.build(); + } + + /** + * Returns the list of all inputs for the {@link CppCompileAction} as configured. + */ + NestedSet<Artifact> buildAllInputs() { + NestedSet<Artifact> mandatoryInputs = buildMandatoryInputs(); + NestedSetBuilder<Artifact> builder = NestedSetBuilder.stableOrder(); + if (optionalSourceFile != null) { + builder.add(optionalSourceFile); + } + builder.addAll(context.getTransitiveCompilationPrerequisites()); + builder.addAll(ccToolchain.getBuiltinIncludeFiles()); + builder.addTransitive(mandatoryInputs); + Iterable<IncludeScannable> lipoScannables = getLipoScannables(mandatoryInputs); + // We need to add "legal generated scanner files" coming through LIPO scannables here. These + // usually contain pre-grepped source files, i.e. files just containing the #include lines + // extracted from generated files. With LIPO, some of these files can be accessed, even though + // there is no direct dependency on them. Adding the artifacts as inputs to this compile + // action ensures that the action generating them is actually executed. + for (IncludeScannable lipoScannable : lipoScannables) { + for (Artifact value : lipoScannable.getLegalGeneratedScannerFileMap().values()) { + if (value != null) { + builder.add(value); + } + } + } + return builder.build(); + } + + private boolean useHeaderModules() { + return allowUsingHeaderModules + && featureConfiguration.isEnabled(CppRuleClasses.USE_HEADER_MODULES); + } + + private boolean shouldPruneModules() { + return cppConfiguration.getPruneCppModules() && shouldScanIncludes && useHeaderModules(); + } + + private static void verifyActionIncludePaths(CppCompileAction action, RuleContext ruleContext) { + Iterable<PathFragment> ignoredDirs = action.getValidationIgnoredDirs(); + // We currently do not check the output of: + // - getQuoteIncludeDirs(): those only come from includes attributes, and are checked in + // CcCommon.getIncludeDirsFromIncludesAttribute(). + // - getBuiltinIncludeDirs(): while in practice this doesn't happen, bazel can be configured + // to use an absolute system root, in which case the builtin include dirs might be absolute. + for (PathFragment include : + Iterables.concat(action.getIncludeDirs(), action.getSystemIncludeDirs())) { + // Ignore headers from built-in include directories. + if (FileSystemUtils.startsWithAny(include, ignoredDirs)) { + continue; + } + // One starting ../ is okay for getting to a sibling repository. + if (include.startsWith(new PathFragment(Label.EXTERNAL_PATH_PREFIX))) { + include = include.relativeTo(Label.EXTERNAL_PATH_PREFIX); + } + if (include.isAbsolute() + || !PathFragment.EMPTY_FRAGMENT.getRelative(include).normalize().isNormalized()) { + ruleContext.ruleError( + "The include path '" + include + "' references a path outside of the execution root."); + } } } @@ -377,6 +485,13 @@ public class CppCompileActionBuilder { return this; } + /** + * Returns the build variables to be used for the action. + */ + CcToolchainFeatures.Variables getVariables() { + return variables; + } + public CppCompileActionBuilder addEnvironment(Map<String, String> environment) { this.environment.putAll(environment); return this; @@ -435,22 +550,24 @@ public class CppCompileActionBuilder { return this; } - public CppCompileActionBuilder setOutputsForTesting(Artifact outputFile, Artifact dotdFile) { + public CppCompileActionBuilder setOutputs(Artifact outputFile, Artifact dotdFile) { this.outputFile = outputFile; this.dotdFile = dotdFile == null ? null : new DotdFile(dotdFile); return this; } public CppCompileActionBuilder setOutputs( - ArtifactCategory outputCategory, String outputName, boolean generateDotd) { + RuleContext ruleContext, ArtifactCategory outputCategory, String outputName, + boolean generateDotd) { this.outputFile = CppHelper.getCompileOutputArtifact( ruleContext, CppHelper.getArtifactNameForCategory(ruleContext, ccToolchain, outputCategory, outputName)); if (generateDotd) { String dotdFileName = CppHelper.getDotdFileName(ruleContext, ccToolchain, outputCategory, outputName); - if (configuration.getFragment(CppConfiguration.class).getInmemoryDotdFiles()) { + if (cppConfiguration.getInmemoryDotdFiles()) { // Just set the path, no artifact is constructed + BuildConfiguration configuration = ruleContext.getConfiguration(); dotdFile = new DotdFile( configuration.getBinDirectory(ruleContext.getRule().getRepository()).getExecPath() .getRelative(CppHelper.getObjDirectory(ruleContext.getLabel())) diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileActionTemplate.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileActionTemplate.java new file mode 100644 index 0000000000..21abea8474 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileActionTemplate.java @@ -0,0 +1,200 @@ +// Copyright 2017 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.lib.rules.cpp; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.devtools.build.lib.actions.ActionAnalysisMetadata; +import com.google.devtools.build.lib.actions.ActionAnalysisMetadata.MiddlemanType; +import com.google.devtools.build.lib.actions.ActionInputHelper; +import com.google.devtools.build.lib.actions.ActionOwner; +import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.actions.Artifact.TreeFileArtifact; +import com.google.devtools.build.lib.actions.ArtifactOwner; +import com.google.devtools.build.lib.analysis.actions.ActionTemplate; +import com.google.devtools.build.lib.collect.nestedset.NestedSet; +import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; +import com.google.devtools.build.lib.vfs.FileSystemUtils; +import com.google.devtools.build.lib.vfs.PathFragment; + +/** + * An {@link ActionTemplate} that expands into {@link CppCompileAction}s at execution time. + */ +public final class CppCompileActionTemplate implements ActionTemplate<CppCompileAction> { + private final CppCompileActionBuilder cppCompileActionBuilder; + private final Artifact sourceTreeArtifact; + private final Artifact outputTreeArtifact; + private final CppConfiguration cppConfiguration; + private final Iterable<ArtifactCategory> categories; + private final ActionOwner actionOwner; + private final NestedSet<Artifact> mandatoryInputs; + private final NestedSet<Artifact> allInputs; + + /** + * Creates an CppCompileActionTemplate. + * @param sourceTreeArtifact the TreeArtifact that contains source files to compile. + * @param outputTreeArtifact the TreeArtifact that contains compilation outputs. + * @param cppCompileActionBuilder An almost completely configured {@link CppCompileActionBuilder} + * without the input and output files set. It is used as a template to instantiate expanded + * {CppCompileAction}s. + * @param cppConfiguration configuration for cpp. + * @param categories A list of {@link ArtifactCategory} used to calculate output file name from + * a source file name. + * @param actionOwner the owner of this {@link ActionTemplate}. + */ + CppCompileActionTemplate( + Artifact sourceTreeArtifact, + Artifact outputTreeArtifact, + CppCompileActionBuilder cppCompileActionBuilder, + CppConfiguration cppConfiguration, + Iterable<ArtifactCategory> categories, + ActionOwner actionOwner) { + this.cppCompileActionBuilder = cppCompileActionBuilder; + this.sourceTreeArtifact = sourceTreeArtifact; + this.outputTreeArtifact = outputTreeArtifact; + this.cppConfiguration = cppConfiguration; + this.categories = categories; + this.actionOwner = actionOwner; + this.mandatoryInputs = cppCompileActionBuilder.buildMandatoryInputs(); + this.allInputs = cppCompileActionBuilder.buildAllInputs(); + } + + @Override + public Iterable<CppCompileAction> generateActionForInputArtifacts( + Iterable<TreeFileArtifact> inputTreeFileArtifacts, ArtifactOwner artifactOwner) { + ImmutableList.Builder<CppCompileAction> expandedActions = new ImmutableList.Builder<>(); + for (TreeFileArtifact inputTreeFileArtifact : inputTreeFileArtifacts) { + String outputName = outputTreeFileArtifactName(inputTreeFileArtifact); + TreeFileArtifact outputTreeFileArtifact = ActionInputHelper.treeFileArtifact( + outputTreeArtifact, + new PathFragment(outputName), + artifactOwner); + + expandedActions.add(createAction(inputTreeFileArtifact, outputTreeFileArtifact)); + } + + return expandedActions.build(); + } + + private CppCompileAction createAction( + Artifact sourceTreeFileArtifact, Artifact outputTreeFileArtifact) { + CppCompileActionBuilder builder = new CppCompileActionBuilder(cppCompileActionBuilder); + builder.setSourceFile(sourceTreeFileArtifact); + builder.setOutputs(outputTreeFileArtifact, null); + + CcToolchainFeatures.Variables.Builder buildVariables = + new CcToolchainFeatures.Variables.Builder(builder.getVariables()); + buildVariables.overrideStringVariable( + "source_file", sourceTreeFileArtifact.getExecPathString()); + buildVariables.overrideStringVariable( + "output_file", outputTreeFileArtifact.getExecPathString()); + buildVariables.overrideStringVariable( + "output_object_file", outputTreeFileArtifact.getExecPathString()); + + builder.setVariables(buildVariables.build()); + + return builder.build(); + } + + private String outputTreeFileArtifactName(TreeFileArtifact inputTreeFileArtifact) { + String outputName = FileSystemUtils.removeExtension( + inputTreeFileArtifact.getParentRelativePath().getPathString()); + for (ArtifactCategory category : categories) { + outputName = cppConfiguration.getFeatures().getArtifactNameForCategory(category, outputName); + } + return outputName; + } + + @Override + public Artifact getInputTreeArtifact() { + return sourceTreeArtifact; + } + + @Override + public Artifact getOutputTreeArtifact() { + return outputTreeArtifact; + } + + @Override + public ActionOwner getOwner() { + return actionOwner; + } + + @Override + public final String getMnemonic() { + return "CppCompileActionTemplate"; + } + + @Override + public Iterable<Artifact> getMandatoryInputs() { + return NestedSetBuilder.<Artifact>compileOrder() + .add(sourceTreeArtifact) + .addTransitive(mandatoryInputs) + .build(); + } + + @Override + public ImmutableSet<Artifact> getMandatoryOutputs() { + return ImmutableSet.<Artifact>of(); + } + + @Override + public Iterable<Artifact> getTools() { + return ImmutableList.<Artifact>of(); + } + + @Override + public Iterable<Artifact> getInputs() { + return NestedSetBuilder.<Artifact>stableOrder() + .add(sourceTreeArtifact) + .addTransitive(allInputs) + .build(); + } + + @Override + public ImmutableSet<Artifact> getOutputs() { + return ImmutableSet.of(outputTreeArtifact); + } + + @Override + public Iterable<String> getClientEnvironmentVariables() { + return ImmutableList.<String>of(); + } + + @Override + public Artifact getPrimaryInput() { + return sourceTreeArtifact; + } + + @Override + public Artifact getPrimaryOutput() { + return outputTreeArtifact; + } + + @Override + public boolean shouldReportPathPrefixConflict(ActionAnalysisMetadata action) { + return this != action; + } + + @Override + public MiddlemanType getActionType() { + return MiddlemanType.NORMAL; + } + + @Override + public String prettyPrint() { + return String.format( + "CppCompileActionTemplate compiling " + sourceTreeArtifact.getExecPathString()); + } +} diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppFileTypes.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppFileTypes.java index 2ad342dd67..dc174850db 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppFileTypes.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppFileTypes.java @@ -183,10 +183,16 @@ public final class CppFileTypes { } }; - public static final boolean mustProduceDotdFile(String source) { - return !ASSEMBLER.matches(source) - && !PIC_ASSEMBLER.matches(source) - && !CLIF_INPUT_PROTO.matches(source); + public static final boolean mustProduceDotdFile(Artifact source) { + // Sources from TreeArtifacts and TreeFileArtifacts will not generate dotd file. + if (source.isTreeArtifact() || source.hasParent()) { + return false; + } + + String fileName = source.getFilename(); + return !ASSEMBLER.matches(fileName) + && !PIC_ASSEMBLER.matches(fileName) + && !CLIF_INPUT_PROTO.matches(fileName); } } 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 e4b19dcb2b..5228588d91 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 @@ -584,9 +584,19 @@ public class CppHelper { ruleContext.getConfiguration().getBinDirectory(ruleContext.getRule().getRepository())); } - static String getArtifactNameForCategory( - RuleContext ruleContext, CcToolchainProvider toolchain, ArtifactCategory category, - String outputName) { + /** + * Returns the corresponding compiled TreeArtifact given the source TreeArtifact. + */ + public static Artifact getCompileOutputTreeArtifact( + RuleContext ruleContext, Artifact sourceTreeArtifact) { + PathFragment objectDir = getObjDirectory(ruleContext.getLabel()); + PathFragment rootRelativePath = sourceTreeArtifact.getRootRelativePath(); + return ruleContext.getTreeArtifact( + objectDir.getRelative(rootRelativePath), sourceTreeArtifact.getRoot()); + } + + static String getArtifactNameForCategory(RuleContext ruleContext, CcToolchainProvider toolchain, + ArtifactCategory category, String outputName) { return toolchain.getFeatures().getArtifactNameForCategory(category, outputName); } diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java index b22e989734..ffe579062a 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java @@ -954,8 +954,11 @@ public class CppLinkActionBuilder { } private void addObjectFile(LinkerInput input) { + // We skip file extension checks for TreeArtifacts because they represent directory artifacts + // without a file extension. String name = input.getArtifact().getFilename(); - Preconditions.checkArgument(Link.OBJECT_FILETYPES.matches(name), name); + Preconditions.checkArgument( + input.getArtifact().isTreeArtifact() || Link.OBJECT_FILETYPES.matches(name), name); this.objectFiles.add(input); } 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 index 1e186294aa..7960baca9d 100644 --- 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 @@ -144,9 +144,10 @@ public final class CppModel { * units, including module files or headers to be parsed or preprocessed. */ public CppModel addCompilationUnitSources( - Iterable<Artifact> sourceFiles, Label sourceLabel, Map<String, String> buildVariables) { + Iterable<Artifact> sourceFiles, Label sourceLabel, Map<String, String> buildVariables, + CppSource.Type type) { for (Artifact sourceFile : sourceFiles) { - this.sourceFiles.add(CppSource.create(sourceFile, sourceLabel, buildVariables)); + this.sourceFiles.add(CppSource.create(sourceFile, sourceLabel, buildVariables, type)); } return this; } @@ -380,7 +381,7 @@ public final class CppModel { buildVariables.addStringVariable("output_object_file", realOutputFilePath); } - DotdFile dotdFile = CppFileTypes.mustProduceDotdFile(sourceFile.getPath().toString()) + DotdFile dotdFile = CppFileTypes.mustProduceDotdFile(sourceFile) ? Preconditions.checkNotNull(builder.getDotdFile()) : null; // Set dependency_file to enable <object>.d file generation. if (dotdFile != null) { @@ -485,33 +486,61 @@ public final class CppModel { CppCompileActionBuilder builder = initializeCompileAction(sourceArtifact, sourceLabel); builder.setSemantics(semantics); - - if (CppFileTypes.CPP_HEADER.matches(source.getSource().getExecPath())) { - createHeaderAction(outputName, result, env, builder, - CppFileTypes.mustProduceDotdFile(sourceArtifact.getFilename())); - } else if (CppFileTypes.CLIF_INPUT_PROTO.matches(source.getSource().getExecPath())) { - createClifMatchAction(outputName, result, env, builder); + + if (!sourceArtifact.isTreeArtifact()) { + switch (source.getType()) { + case HEADER: + createHeaderAction(outputName, result, env, builder, + CppFileTypes.mustProduceDotdFile(sourceArtifact)); + break; + case CLIF_INPUT_PROTO: + createClifMatchAction(outputName, result, env, builder); + break; + default: + boolean bitcodeOutput = + featureConfiguration.isEnabled(CppRuleClasses.THIN_LTO) + && CppFileTypes.LTO_SOURCE.matches(sourceArtifact.getFilename()); + createSourceAction( + outputName, + result, + env, + sourceArtifact, + builder, + 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. + /*generateDwo=*/ cppConfiguration.useFission() && !bitcodeOutput, + CppFileTypes.mustProduceDotdFile(sourceArtifact), + source.getBuildVariables(), /*addHeaderTokenFile=*/ + false); + break; + } } else { - boolean bitcodeOutput = - featureConfiguration.isEnabled(CppRuleClasses.THIN_LTO) - && CppFileTypes.LTO_SOURCE.matches(sourceArtifact.getFilename()); - createSourceAction( - outputName, - result, - env, - sourceArtifact, - builder, - 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. - /*generateDwo=*/ cppConfiguration.useFission() && !bitcodeOutput, - CppFileTypes.mustProduceDotdFile(sourceArtifact.getFilename()), - source.getBuildVariables(), /*addHeaderTokenFile=*/ - false); + switch (source.getType()) { + case HEADER: + Artifact headerTokenFile = + createCompileActionTemplate( + env, + source, + builder, + ImmutableList.of( + ArtifactCategory.GENERATED_HEADER, ArtifactCategory.PROCESSED_HEADER)); + result.addHeaderTokenFile(headerTokenFile); + break; + case SOURCE: + Artifact objectFile = + createCompileActionTemplate( + env, source, builder, ImmutableList.of(ArtifactCategory.OBJECT_FILE)); + result.addObjectFile(objectFile); + break; + default: + throw new IllegalStateException( + "Encountered invalid source types when creating CppCompileActionTemplates"); + } } } @@ -525,7 +554,7 @@ public final class CppModel { ruleContext, ccToolchain, ArtifactCategory.GENERATED_HEADER, outputName); builder - .setOutputs(ArtifactCategory.PROCESSED_HEADER, outputNameBase, generateDotd) + .setOutputs(ruleContext, ArtifactCategory.PROCESSED_HEADER, outputNameBase, generateDotd) // If we generate pic actions, we prefer the header actions to use the pic artifacts. .setPicMode(this.getGeneratePicActions()); setupCompileBuildVariables( @@ -538,7 +567,7 @@ public final class CppModel { builder.getContext().getCppModuleMap(), ImmutableMap.<String, String>of()); semantics.finalizeCompileActionBuilder(ruleContext, builder); - CppCompileAction compileAction = builder.build(); + CppCompileAction compileAction = builder.buildAndValidate(ruleContext); env.registerAction(compileAction); Artifact tokenFile = compileAction.getOutputFile(); result.addHeaderTokenFile(tokenFile); @@ -568,7 +597,7 @@ public final class CppModel { /*addObject=*/ false, /*enableCoverage=*/ false, /*generateDwo=*/ false, - CppFileTypes.mustProduceDotdFile(moduleMapArtifact.getFilename()), + CppFileTypes.mustProduceDotdFile(moduleMapArtifact), ImmutableMap.<String, String>of(), /*addHeaderTokenFile=*/ addHeaderTokenFiles); } @@ -576,7 +605,7 @@ public final class CppModel { private void createClifMatchAction( String outputName, Builder result, AnalysisEnvironment env, CppCompileActionBuilder builder) { builder - .setOutputs(ArtifactCategory.CLIF_OUTPUT_PROTO, outputName, false) + .setOutputs(ruleContext, ArtifactCategory.CLIF_OUTPUT_PROTO, outputName, false) .setPicMode(false) // The additional headers in a clif action are both mandatory inputs and // need to be include-scanned. @@ -592,7 +621,7 @@ public final class CppModel { builder.getContext().getCppModuleMap(), /*sourceSpecificBuildVariables=*/ ImmutableMap.<String, String>of()); semantics.finalizeCompileActionBuilder(ruleContext, builder); - CppCompileAction compileAction = builder.build(); + CppCompileAction compileAction = builder.buildAndValidate(ruleContext); env.registerAction(compileAction); Artifact tokenFile = compileAction.getOutputFile(); result.addHeaderTokenFile(tokenFile); @@ -663,7 +692,7 @@ public final class CppModel { picBuilder.setDwoFile(dwoFile); semantics.finalizeCompileActionBuilder(ruleContext, picBuilder); - CppCompileAction picAction = picBuilder.build(); + CppCompileAction picAction = picBuilder.buildAndValidate(ruleContext); env.registerAction(picAction); if (addHeaderTokenFiles) { result.addHeaderTokenFile(picAction.getOutputFile()); @@ -690,7 +719,7 @@ public final class CppModel { ruleContext, CppHelper.getArtifactNameForCategory( ruleContext, ccToolchain, outputCategory, outputName)); - builder.setOutputs(outputCategory, outputName, generateDotd); + builder.setOutputs(ruleContext, outputCategory, outputName, generateDotd); String gcnoFileName = CppHelper.getArtifactNameForCategory(ruleContext, ccToolchain, ArtifactCategory.COVERAGE_DATA_FILE, outputName); @@ -727,7 +756,7 @@ public final class CppModel { builder.setDwoFile(noPicDwoFile); semantics.finalizeCompileActionBuilder(ruleContext, builder); - CppCompileAction compileAction = builder.build(); + CppCompileAction compileAction = builder.buildAndValidate(ruleContext); env.registerAction(compileAction); Artifact objectFile = compileAction.getOutputFile(); if (addHeaderTokenFiles) { @@ -751,6 +780,35 @@ public final class CppModel { } } + private Artifact createCompileActionTemplate(AnalysisEnvironment env, + CppSource source, CppCompileActionBuilder builder, + Iterable<ArtifactCategory> outputCategories) { + Artifact sourceArtifact = source.getSource(); + Artifact outputFiles = CppHelper.getCompileOutputTreeArtifact(ruleContext, sourceArtifact); + // TODO(rduan): Dotd file output is not supported yet. + builder.setOutputs(outputFiles, null); + setupCompileBuildVariables( + builder, + /* usePic=*/ false, + /*ccRelativeName=*/ null, + /*autoFdoImportPath=*/ null, + /*gcnoFile=*/ null, + /*dwoFile=*/ null, + builder.getContext().getCppModuleMap(), + source.getBuildVariables()); + semantics.finalizeCompileActionBuilder(ruleContext, builder); + CppCompileActionTemplate actionTemplate = new CppCompileActionTemplate( + sourceArtifact, + outputFiles, + builder, + cppConfiguration, + outputCategories, + ruleContext.getActionOwner()); + env.registerAction(actionTemplate); + + return outputFiles; + } + String getOutputNameBaseWith(String base, boolean usePic) { return usePic ? CppHelper.getArtifactNameForCategory( @@ -771,7 +829,7 @@ public final class CppModel { .getPathString(); builder .setPicMode(usePic) - .setOutputs(outputCategory, outputNameBase, generateDotd) + .setOutputs(ruleContext, outputCategory, outputNameBase, generateDotd) .setTempOutputFile(new PathFragment(tempOutputName)); setupCompileBuildVariables( @@ -784,7 +842,7 @@ public final class CppModel { builder.getContext().getCppModuleMap(), ImmutableMap.<String, String>of()); semantics.finalizeCompileActionBuilder(ruleContext, builder); - CppCompileAction action = builder.build(); + CppCompileAction action = builder.buildAndValidate(ruleContext); env.registerAction(action); if (addObject) { if (usePic) { @@ -818,7 +876,6 @@ public final class CppModel { maybePicName = CppHelper.getArtifactNameForCategory( ruleContext, ccToolchain, ArtifactCategory.PIC_FILE, maybePicName); } - String linkedName = CppHelper.getArtifactNameForCategory( ruleContext, ccToolchain, linkTargetType.getLinkerOutput(), maybePicName); PathFragment artifactFragment = new PathFragment(ruleContext.getLabel().getName()) @@ -923,7 +980,6 @@ public final class CppModel { // 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(true)) @@ -1062,9 +1118,8 @@ public final class CppModel { * inputs, output and dotd file names, compilation context and copts. */ private CppCompileActionBuilder createCompileActionBuilder(Artifact source, Label label) { - CppCompileActionBuilder builder = new CppCompileActionBuilder( - ruleContext, source, label, ccToolchain); - + CppCompileActionBuilder builder = new CppCompileActionBuilder(ruleContext, label, ccToolchain); + builder.setSourceFile(source); builder.setContext(context).addCopts(copts); builder.addEnvironment(ccToolchain.getEnvironment()); return builder; @@ -1080,7 +1135,7 @@ public final class CppModel { CppCompileActionBuilder picBuilder = new CppCompileActionBuilder(builder); picBuilder .setPicMode(true) - .setOutputs(outputCategory, outputName, generateDotd); + .setOutputs(ruleContext, outputCategory, outputName, generateDotd); return picBuilder; } @@ -1109,7 +1164,7 @@ public final class CppModel { String outputArtifactNameBase = getOutputNameBaseWith(outputName, usePic); CppCompileActionBuilder dBuilder = new CppCompileActionBuilder(builder); - dBuilder.setOutputs(category, outputArtifactNameBase, generateDotd); + dBuilder.setOutputs(ruleContext, category, outputArtifactNameBase, generateDotd); setupCompileBuildVariables( dBuilder, usePic, @@ -1120,11 +1175,12 @@ public final class CppModel { builder.getContext().getCppModuleMap(), ImmutableMap.<String, String>of()); semantics.finalizeCompileActionBuilder(ruleContext, dBuilder); - CppCompileAction dAction = dBuilder.build(); + CppCompileAction dAction = dBuilder.buildAndValidate(ruleContext); ruleContext.registerAction(dAction); CppCompileActionBuilder sdBuilder = new CppCompileActionBuilder(builder); - sdBuilder.setOutputs(ArtifactCategory.GENERATED_ASSEMBLY, outputArtifactNameBase, generateDotd); + sdBuilder.setOutputs( + ruleContext, ArtifactCategory.GENERATED_ASSEMBLY, outputArtifactNameBase, generateDotd); setupCompileBuildVariables( sdBuilder, usePic, @@ -1135,7 +1191,7 @@ public final class CppModel { builder.getContext().getCppModuleMap(), ImmutableMap.<String, String>of()); semantics.finalizeCompileActionBuilder(ruleContext, sdBuilder); - CppCompileAction sdAction = sdBuilder.build(); + CppCompileAction sdAction = sdBuilder.buildAndValidate(ruleContext); ruleContext.registerAction(sdAction); return ImmutableList.of( diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppSource.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppSource.java index 17ec8d0372..bc6ff4b6ac 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppSource.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppSource.java @@ -22,7 +22,17 @@ import java.util.Map; /** A source file that is an input to a c++ compilation. */ @AutoValue -abstract class CppSource { +public abstract class CppSource { + + /** + * Types of sources. + */ + public enum Type { + SOURCE, + HEADER, + CLIF_INPUT_PROTO, + } + /** * Creates a {@code CppSource}. * @@ -30,9 +40,11 @@ abstract class CppSource { * @param label the label from which this source arises in the build graph * @param buildVariables build variables that should be used specifically in the compilation * of this source + * @param type type of the source file. */ - static CppSource create(Artifact source, Label label, Map<String, String> buildVariables) { - return new AutoValue_CppSource(source, label, buildVariables); + static CppSource create(Artifact source, Label label, Map<String, String> buildVariables, + Type type) { + return new AutoValue_CppSource(source, label, buildVariables, type); } /** @@ -49,4 +61,9 @@ abstract class CppSource { * Returns build variables to be used specifically in the compilation of this source. */ abstract Map<String, String> getBuildVariables(); + + /** + * Returns the type of this source. + */ + abstract Type getType(); } diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/FakeCppCompileAction.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/FakeCppCompileAction.java index dc42ddd235..cf57fd67d3 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/FakeCppCompileAction.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/FakeCppCompileAction.java @@ -29,8 +29,6 @@ import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.actions.ExecException; import com.google.devtools.build.lib.actions.Executor; import com.google.devtools.build.lib.actions.ResourceSet; -import com.google.devtools.build.lib.analysis.RuleContext; -import com.google.devtools.build.lib.analysis.config.BuildConfiguration; 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; @@ -61,6 +59,7 @@ public class FakeCppCompileAction extends CppCompileAction { FakeCppCompileAction( ActionOwner owner, + NestedSet<Artifact> allInputs, ImmutableList<String> features, FeatureConfiguration featureConfiguration, CcToolchainFeatures.Variables variables, @@ -75,18 +74,20 @@ public class FakeCppCompileAction extends CppCompileAction { Artifact outputFile, PathFragment tempOutputFile, DotdFile dotdFile, - BuildConfiguration configuration, + ImmutableMap<String, String> localShellEnvironment, + boolean codeCoverageEnabled, CppConfiguration cppConfiguration, CppCompilationContext context, Class<? extends CppCompileActionContext> actionContext, ImmutableList<String> copts, Predicate<String> nocopts, - RuleContext ruleContext, + Iterable<IncludeScannable> lipoScannables, + Iterable<Artifact> builtinIncludeFiles, CppSemantics cppSemantics, - CcToolchainProvider ccToolchain, ImmutableMap<String, String> executionInfo) { super( owner, + allInputs, features, featureConfiguration, variables, @@ -103,8 +104,8 @@ public class FakeCppCompileAction extends CppCompileAction { null, null, null, - configuration.getLocalShellEnvironment(), - configuration.isCodeCoverageEnabled(), + localShellEnvironment, + codeCoverageEnabled, cppConfiguration, // We only allow inclusion of header files explicitly declared in // "srcs", so we only use declaredIncludeSrcs, not declaredIncludeDirs. @@ -118,15 +119,14 @@ public class FakeCppCompileAction extends CppCompileAction { copts, nocopts, VOID_SPECIAL_INPUTS_HANDLER, - ImmutableList.<IncludeScannable>of(), + lipoScannables, ImmutableList.<Artifact>of(), GUID, executionInfo, ImmutableMap.<String, String>of(), CppCompileAction.CPP_COMPILE, - ruleContext, - cppSemantics, - ccToolchain); + builtinIncludeFiles, + cppSemantics); this.tempOutputFile = Preconditions.checkNotNull(tempOutputFile); } diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkerInputs.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkerInputs.java index d4346a39e1..bb65c34002 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkerInputs.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkerInputs.java @@ -47,7 +47,10 @@ public abstract class LinkerInputs { break; case OBJECT_FILE: - Preconditions.checkState(Link.OBJECT_FILETYPES.matches(basename)); + // We skip file extension checks for TreeArtifacts because they represent directory + // artifacts without a file extension. + Preconditions.checkState( + artifact.isTreeArtifact() || Link.OBJECT_FILETYPES.matches(basename)); break; default: |