aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/rules/objc
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/rules/objc')
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java49
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/IntermediateArtifacts.java9
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCommandLineOptions.java10
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCompileAction.java325
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/ObjcConfiguration.java12
5 files changed, 377 insertions, 28 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java
index 7faa6a516d..77faa716d2 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationSupport.java
@@ -83,6 +83,7 @@ import com.google.devtools.build.lib.rules.apple.AppleConfiguration;
import com.google.devtools.build.lib.rules.apple.AppleToolchain;
import com.google.devtools.build.lib.rules.apple.Platform;
import com.google.devtools.build.lib.rules.apple.Platform.PlatformType;
+import com.google.devtools.build.lib.rules.cpp.CppCompileAction.DotdFile;
import com.google.devtools.build.lib.rules.cpp.CppModuleMap;
import com.google.devtools.build.lib.rules.cpp.CppModuleMapAction;
import com.google.devtools.build.lib.rules.objc.XcodeProvider.Builder;
@@ -655,19 +656,21 @@ public final class CompilationSupport {
boolean runCodeCoverage =
buildConfiguration.isCodeCoverageEnabled() && ObjcRuleClasses.isInstrumentable(sourceFile);
boolean hasSwiftSources = compilationArtifacts.hasSwiftSources();
+ DotdFile dotdFile = intermediateArtifacts.dotdFile(sourceFile);
- CustomCommandLine commandLine = compileActionCommandLine(
- sourceFile,
- objFile,
- objcProvider,
- priorityHeaders,
- moduleMap,
- compilationArtifacts.getPchFile(),
- Optional.of(intermediateArtifacts.dotdFile(sourceFile)),
- otherFlags,
- runCodeCoverage,
- isCPlusPlusSource,
- hasSwiftSources);
+ CustomCommandLine commandLine =
+ compileActionCommandLine(
+ sourceFile,
+ objFile,
+ objcProvider,
+ priorityHeaders,
+ moduleMap,
+ compilationArtifacts.getPchFile(),
+ Optional.of(dotdFile.artifact()),
+ otherFlags,
+ runCodeCoverage,
+ isCPlusPlusSource,
+ hasSwiftSources);
Optional<Artifact> gcnoFile = Optional.absent();
if (runCodeCoverage && !buildConfiguration.isLLVMCoverageMapFormatEnabled()) {
@@ -684,24 +687,26 @@ public final class CompilationSupport {
moduleMapInputs = objcProvider.get(MODULE_MAP);
}
- // TODO(bazel-team): Remote private headers from inputs once they're added to the provider.
+ // TODO(bazel-team): Remove private headers from inputs once they're added to the provider.
ruleContext.registerAction(
- ObjcRuleClasses.spawnAppleEnvActionBuilder(
+ ObjcCompileAction.Builder.createObjcCompileActionBuilderWithAppleEnv(
appleConfiguration, appleConfiguration.getSingleArchPlatform())
+ .setDotdPruningPlan(objcConfiguration.getDotdPruningPlan())
+ .setSourceFile(sourceFile)
+ .addMandatoryInputs(swiftHeader.asSet())
+ .addTransitiveMandatoryInputs(moduleMapInputs)
+ .addTransitiveMandatoryInputs(objcProvider.get(STATIC_FRAMEWORK_FILE))
+ .addTransitiveMandatoryInputs(objcProvider.get(DYNAMIC_FRAMEWORK_FILE))
+ .setDotdFile(dotdFile)
+ .addInputs(compilationArtifacts.getPrivateHdrs())
+ .addInputs(compilationArtifacts.getPchFile().asSet())
.setMnemonic("ObjcCompile")
.setExecutable(xcrunwrapper(ruleContext))
.setCommandLine(commandLine)
- .addInput(sourceFile)
- .addInputs(swiftHeader.asSet())
- .addTransitiveInputs(moduleMapInputs)
.addOutput(objFile)
.addOutputs(gcnoFile.asSet())
- .addOutput(intermediateArtifacts.dotdFile(sourceFile))
+ .addOutput(dotdFile.artifact())
.addTransitiveInputs(objcProvider.get(HEADER))
- .addInputs(compilationArtifacts.getPrivateHdrs())
- .addTransitiveInputs(objcProvider.get(STATIC_FRAMEWORK_FILE))
- .addTransitiveInputs(objcProvider.get(DYNAMIC_FRAMEWORK_FILE))
- .addInputs(compilationArtifacts.getPchFile().asSet())
.build(ruleContext));
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/IntermediateArtifacts.java b/src/main/java/com/google/devtools/build/lib/rules/objc/IntermediateArtifacts.java
index 9b8ced2dfd..811e698ff7 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/IntermediateArtifacts.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/IntermediateArtifacts.java
@@ -20,6 +20,7 @@ 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;
import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.rules.cpp.CppCompileAction.DotdFile;
import com.google.devtools.build.lib.rules.cpp.CppModuleMap;
import com.google.devtools.build.lib.util.Preconditions;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
@@ -397,11 +398,9 @@ public final class IntermediateArtifacts {
return appendExtension("_runner.sh");
}
- /**
- * Dependency file that is generated when compiling the {@code source} artifact.
- */
- public Artifact dotdFile(Artifact source) {
- return inUniqueObjsDir(source, ".d");
+ /** Dependency file that is generated when compiling the {@code source} artifact. */
+ public DotdFile dotdFile(Artifact source) {
+ return new DotdFile(inUniqueObjsDir(source, ".d"));
}
/**
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCommandLineOptions.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCommandLineOptions.java
index 86c0c0734f..3efdc8b4d4 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCommandLineOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCommandLineOptions.java
@@ -249,6 +249,16 @@ public class ObjcCommandLineOptions extends FragmentOptions {
)
public boolean experimentalObjcLibrary;
+ @Option(
+ name = "objc_use_dotd_pruning",
+ defaultValue = "false",
+ category = "flags",
+ help =
+ "If set, .d files emited by clang will be used to prune the set of inputs passed into objc "
+ + "compiles."
+ )
+ public boolean useDotdPruning;
+
@VisibleForTesting static final String DEFAULT_MINIMUM_IOS = "7.0";
@VisibleForTesting static final String DEFAULT_MINIMUM_WATCHOS = "2.0";
@VisibleForTesting static final String DEFAULT_MINIMUM_TVOS = "9.0";
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCompileAction.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCompileAction.java
new file mode 100644
index 0000000000..9a617f66ab
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCompileAction.java
@@ -0,0 +1,325 @@
+// Copyright 2016 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.objc;
+
+import static com.google.devtools.build.lib.collect.nestedset.Order.STABLE_ORDER;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.devtools.build.lib.actions.ActionExecutionContext;
+import com.google.devtools.build.lib.actions.ActionExecutionException;
+import com.google.devtools.build.lib.actions.ActionOwner;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.ArtifactResolver;
+import com.google.devtools.build.lib.actions.Executor;
+import com.google.devtools.build.lib.actions.ResourceSet;
+import com.google.devtools.build.lib.analysis.actions.CommandLine;
+import com.google.devtools.build.lib.analysis.actions.SpawnAction;
+import com.google.devtools.build.lib.collect.nestedset.NestedSet;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadCompatible;
+import com.google.devtools.build.lib.profiler.Profiler;
+import com.google.devtools.build.lib.profiler.ProfilerTask;
+import com.google.devtools.build.lib.rules.apple.AppleConfiguration;
+import com.google.devtools.build.lib.rules.apple.Platform;
+import com.google.devtools.build.lib.rules.cpp.CppCompileAction.DotdFile;
+import com.google.devtools.build.lib.rules.cpp.HeaderDiscovery;
+import com.google.devtools.build.lib.rules.cpp.IncludeScanningContext;
+import com.google.devtools.build.lib.util.DependencySet;
+import com.google.devtools.build.lib.util.Fingerprint;
+import com.google.devtools.build.lib.vfs.Path;
+import com.google.devtools.build.lib.vfs.PathFragment;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * An action that compiles objc or objc++ source.
+ *
+ * <p>We don't use a plain SpawnAction here because we implement .d input pruning, which requires
+ * post-execution filtering of input artifacts.
+ *
+ * <p>We don't use a CppCompileAction because the ObjcCompileAction uses custom logic instead of the
+ * CROSSTOOL to construct its command line.
+ */
+public class ObjcCompileAction extends SpawnAction {
+
+ private final DotdFile dotdFile;
+ private final Artifact sourceFile;
+ private final NestedSet<Artifact> mandatoryInputs;
+ private final HeaderDiscovery.DotdPruningMode dotdPruningPlan;
+
+ private static final String GUID = "a00d5bac-a72c-4f0f-99a7-d5fdc6072137";
+
+ private ObjcCompileAction(
+ ActionOwner owner,
+ Iterable<Artifact> tools,
+ Iterable<Artifact> inputs,
+ Iterable<Artifact> outputs,
+ ResourceSet resourceSet,
+ CommandLine argv,
+ ImmutableMap<String, String> environment,
+ ImmutableMap<String, String> executionInfo,
+ String progressMessage,
+ ImmutableMap<PathFragment, Artifact> inputManifests,
+ String mnemonic,
+ boolean executeUnconditionally,
+ ExtraActionInfoSupplier<?> extraActionInfoSupplier,
+ DotdFile dotdFile,
+ Artifact sourceFile,
+ NestedSet<Artifact> mandatoryInputs,
+ HeaderDiscovery.DotdPruningMode dotdPruningPlan) {
+ super(
+ owner,
+ tools,
+ inputs,
+ outputs,
+ resourceSet,
+ argv,
+ environment,
+ ImmutableSet.<String>of(),
+ executionInfo,
+ progressMessage,
+ inputManifests,
+ mnemonic,
+ executeUnconditionally,
+ extraActionInfoSupplier);
+
+ this.dotdFile = dotdFile;
+ this.sourceFile = sourceFile;
+ this.mandatoryInputs = mandatoryInputs;
+ this.dotdPruningPlan = dotdPruningPlan;
+ }
+
+ /** Returns the DotdPruningPlan for this compile */
+ @VisibleForTesting
+ public HeaderDiscovery.DotdPruningMode getDotdPruningPlan() {
+ return dotdPruningPlan;
+ }
+
+ @Override
+ public boolean discoversInputs() {
+ return true;
+ }
+
+ @Override
+ public Iterable<Artifact> discoverInputs(ActionExecutionContext actionExecutionContext) {
+ // We do not use include scanning for objc
+ return null;
+ }
+
+ @Override
+ public void execute(ActionExecutionContext actionExecutionContext)
+ throws ActionExecutionException, InterruptedException {
+ super.execute(actionExecutionContext);
+
+ if (dotdPruningPlan == HeaderDiscovery.DotdPruningMode.USE) {
+ Executor executor = actionExecutionContext.getExecutor();
+ IncludeScanningContext scanningContext = executor.getContext(IncludeScanningContext.class);
+ NestedSet<Artifact> discoveredInputs =
+ discoverInputsFromDotdFiles(
+ executor.getExecRoot(), scanningContext.getArtifactResolver());
+
+ updateActionInputs(discoveredInputs);
+ }
+ }
+
+ @VisibleForTesting
+ public NestedSet<Artifact> discoverInputsFromDotdFiles(
+ Path execRoot, ArtifactResolver artifactResolver) throws ActionExecutionException {
+ if (dotdFile == null) {
+ return NestedSetBuilder.<Artifact>stableOrder().build();
+ }
+ return new HeaderDiscovery.Builder()
+ .setAction(this)
+ .setSourceFile(sourceFile)
+ .setDotdFile(dotdFile)
+ .setDependencySet(processDepset(execRoot))
+ .setPermittedSystemIncludePrefixes(ImmutableList.<Path>of())
+ .setAllowedDerivedinputsMap(getAllowedDerivedInputsMap())
+ .build()
+ .discoverInputsFromDotdFiles(execRoot, artifactResolver);
+ }
+
+ private DependencySet processDepset(Path execRoot) throws ActionExecutionException {
+ try {
+ DependencySet depSet = new DependencySet(execRoot);
+ return depSet.read(dotdFile.getPath());
+ } catch (IOException e) {
+ // Some kind of IO or parse exception--wrap & rethrow it to stop the build.
+ throw new ActionExecutionException("error while parsing .d file", e, this, false);
+ }
+ }
+
+ /** Utility function that adds artifacts to an input map, but only if they are sources. */
+ private void addToMapIfSource(Map<PathFragment, Artifact> map, Iterable<Artifact> artifacts) {
+ for (Artifact artifact : artifacts) {
+ if (!artifact.isSourceArtifact()) {
+ map.put(artifact.getExecPath(), artifact);
+ }
+ }
+ }
+
+ private Map<PathFragment, Artifact> getAllowedDerivedInputsMap() {
+ Map<PathFragment, Artifact> allowedDerivedInputMap = new HashMap<>();
+ addToMapIfSource(allowedDerivedInputMap, getInputs());
+ allowedDerivedInputMap.put(sourceFile.getExecPath(), sourceFile);
+ return allowedDerivedInputMap;
+ }
+
+ /**
+ * Recalculates this action's live input collection, including sources, middlemen.
+ *
+ * @throws ActionExecutionException iff any errors happen during update.
+ */
+ @VisibleForTesting
+ @ThreadCompatible
+ public final synchronized void updateActionInputs(NestedSet<Artifact> discoveredInputs)
+ throws ActionExecutionException {
+ NestedSetBuilder<Artifact> inputs = NestedSetBuilder.stableOrder();
+ Profiler.instance().startTask(ProfilerTask.ACTION_UPDATE, this);
+ try {
+ inputs.addTransitive(mandatoryInputs);
+ inputs.addTransitive(discoveredInputs);
+ } finally {
+ Profiler.instance().completeTask(ProfilerTask.ACTION_UPDATE);
+ setInputs(inputs.build());
+ }
+ }
+
+ @Override
+ public String computeKey() {
+ Fingerprint f = new Fingerprint();
+ f.addString(GUID);
+ f.addString(super.computeKey());
+ f.addBoolean(dotdFile.artifact() == null);
+ f.addBoolean(dotdPruningPlan == HeaderDiscovery.DotdPruningMode.USE);
+ f.addPath(dotdFile.getSafeExecPath());
+ return f.hexDigestAndReset();
+ }
+
+ /** A Builder for ObjcCompileAction */
+ public static class Builder extends SpawnAction.Builder {
+
+ private DotdFile dotdFile;
+ private Artifact sourceFile;
+ private final NestedSetBuilder<Artifact> mandatoryInputs = new NestedSetBuilder<>(STABLE_ORDER);
+ private HeaderDiscovery.DotdPruningMode dotdPruningPlan;
+
+ /**
+ * Creates a new compile action builder with apple environment variables set that are typically
+ * needed by the apple toolchain.
+ */
+ public static ObjcCompileAction.Builder createObjcCompileActionBuilderWithAppleEnv(
+ AppleConfiguration appleConfiguration, Platform targetPlatform) {
+ return (Builder)
+ new ObjcCompileAction.Builder()
+ .setExecutionInfo(ObjcRuleClasses.darwinActionExecutionRequirement())
+ .setEnvironment(
+ ObjcRuleClasses.appleToolchainEnvironment(appleConfiguration, targetPlatform));
+ }
+
+ @Override
+ public Builder addTools(Iterable<Artifact> artifacts) {
+ super.addTools(artifacts);
+ mandatoryInputs.addAll(artifacts);
+ return this;
+ }
+
+ /** Sets a .d file that will used to prune input headers */
+ public Builder setDotdFile(DotdFile dotdFile) {
+ Preconditions.checkNotNull(dotdFile);
+ this.dotdFile = dotdFile;
+ return this;
+ }
+
+ /** Sets the source file that is being compiled in this action */
+ public Builder setSourceFile(Artifact sourceFile) {
+ Preconditions.checkNotNull(sourceFile);
+ this.sourceFile = sourceFile;
+ this.mandatoryInputs.add(sourceFile);
+ this.addInput(sourceFile);
+ return this;
+ }
+
+ /** Add an input that cannot be pruned */
+ public Builder addMandatoryInput(Artifact input) {
+ Preconditions.checkNotNull(input);
+ this.mandatoryInputs.add(input);
+ this.addInput(input);
+ return this;
+ }
+
+ /** Add inputs that cannot be pruned */
+ public Builder addMandatoryInputs(Iterable<Artifact> input) {
+ Preconditions.checkNotNull(input);
+ this.mandatoryInputs.addAll(input);
+ this.addInputs(input);
+ return this;
+ }
+
+ /** Add inputs that cannot be pruned */
+ public Builder addTransitiveMandatoryInputs(NestedSet<Artifact> input) {
+ Preconditions.checkNotNull(input);
+ this.mandatoryInputs.addTransitive(input);
+ this.addTransitiveInputs(input);
+ return this;
+ }
+
+ /** Indicates that this compile action should perform .d pruning */
+ public Builder setDotdPruningPlan(HeaderDiscovery.DotdPruningMode dotdPruningPlan) {
+ Preconditions.checkNotNull(dotdPruningPlan);
+ this.dotdPruningPlan = dotdPruningPlan;
+ return this;
+ }
+
+ @Override
+ protected SpawnAction createSpawnAction(
+ ActionOwner owner,
+ NestedSet<Artifact> tools,
+ NestedSet<Artifact> inputsAndTools,
+ ImmutableList<Artifact> outputs,
+ ResourceSet resourceSet,
+ CommandLine actualCommandLine,
+ ImmutableMap<String, String> env,
+ ImmutableSet<String> clientEnvironmentVariables,
+ ImmutableMap<String, String> executionInfo,
+ String progressMessage,
+ ImmutableMap<PathFragment, Artifact> inputAndToolManifests,
+ String mnemonic) {
+ return new ObjcCompileAction(
+ owner,
+ tools,
+ inputsAndTools,
+ outputs,
+ resourceSet,
+ actualCommandLine,
+ env,
+ executionInfo,
+ progressMessage,
+ inputAndToolManifests,
+ mnemonic,
+ executeUnconditionally,
+ extraActionInfoSupplier,
+ dotdFile,
+ sourceFile,
+ mandatoryInputs.build(),
+ dotdPruningPlan);
+ }
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcConfiguration.java
index 734f5466f3..ebe35c5212 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcConfiguration.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcConfiguration.java
@@ -23,12 +23,12 @@ import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
import com.google.devtools.build.lib.rules.apple.DottedVersion;
import com.google.devtools.build.lib.rules.apple.Platform.PlatformType;
+import com.google.devtools.build.lib.rules.cpp.HeaderDiscovery;
import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory;
import com.google.devtools.build.lib.util.Preconditions;
import com.google.devtools.build.lib.vfs.Path;
-
import javax.annotation.Nullable;
/** A compiler configuration containing flags required for Objective-C compilation. */
@@ -79,6 +79,7 @@ public class ObjcConfiguration extends BuildConfiguration.Fragment {
@Nullable private final Label extraEntitlements;
private final boolean deviceDebugEntitlements;
private final boolean experimentalObjcLibrary;
+ private final HeaderDiscovery.DotdPruningMode dotdPruningPlan;
ObjcConfiguration(ObjcCommandLineOptions objcOptions, BuildConfiguration.Options options,
@Nullable BlazeDirectories directories) {
@@ -115,6 +116,10 @@ public class ObjcConfiguration extends BuildConfiguration.Fragment {
this.extraEntitlements = objcOptions.extraEntitlements;
this.deviceDebugEntitlements = objcOptions.deviceDebugEntitlements;
this.experimentalObjcLibrary = objcOptions.experimentalObjcLibrary;
+ this.dotdPruningPlan =
+ objcOptions.useDotdPruning
+ ? HeaderDiscovery.DotdPruningMode.USE
+ : HeaderDiscovery.DotdPruningMode.DO_NOT_USE;
}
/**
@@ -364,4 +369,9 @@ public class ObjcConfiguration extends BuildConfiguration.Fragment {
public boolean useExperimentalObjcLibrary() {
return experimentalObjcLibrary;
}
+
+ /** Returns the DotdPruningPlan for compiles in this build. */
+ public HeaderDiscovery.DotdPruningMode getDotdPruningPlan() {
+ return dotdPruningPlan;
+ }
}