aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/analysis
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/analysis')
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/ConfiguredTargetFactory.java57
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java64
2 files changed, 104 insertions, 17 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredTargetFactory.java b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredTargetFactory.java
index b1ec35db8b..87a31e2718 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredTargetFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredTargetFactory.java
@@ -28,6 +28,8 @@ import com.google.devtools.build.lib.actions.Root;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration.Fragment;
import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider;
+import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException;
+import com.google.devtools.build.lib.analysis.config.PatchTransition;
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;
@@ -56,10 +58,13 @@ import com.google.devtools.build.lib.packages.SkylarkProviderIdentifier;
import com.google.devtools.build.lib.packages.Target;
import com.google.devtools.build.lib.rules.SkylarkRuleConfiguredTargetBuilder;
import com.google.devtools.build.lib.rules.fileset.FilesetProvider;
+import com.google.devtools.build.lib.skyframe.BuildConfigurationValue;
import com.google.devtools.build.lib.skyframe.ConfiguredTargetKey;
import com.google.devtools.build.lib.util.OrderedSetMultimap;
import com.google.devtools.build.lib.util.Preconditions;
import com.google.devtools.build.lib.vfs.PathFragment;
+import com.google.devtools.build.skyframe.SkyFunction;
+
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
@@ -142,14 +147,21 @@ public final class ConfiguredTargetFactory {
return null;
}
- private Artifact getOutputArtifact(OutputFile outputFile, BuildConfiguration configuration,
- boolean isFileset, ArtifactFactory artifactFactory) {
+ /**
+ * Returns the output artifact for the given file, or null if Skyframe deps are missing.
+ */
+ private Artifact getOutputArtifact(AnalysisEnvironment analysisEnvironment, OutputFile outputFile,
+ BuildConfiguration configuration, boolean isFileset, ArtifactFactory artifactFactory)
+ throws InterruptedException {
Rule rule = outputFile.getAssociatedRule();
Root root = rule.hasBinaryOutput()
? configuration.getBinDirectory(rule.getRepository())
: configuration.getGenfilesDirectory(rule.getRepository());
- ArtifactOwner owner =
- new ConfiguredTargetKey(rule.getLabel(), configuration.getArtifactOwnerConfiguration());
+ ArtifactOwner owner = new ConfiguredTargetKey(rule.getLabel(),
+ getArtifactOwnerConfiguration(analysisEnvironment.getSkyframeEnv(), configuration));
+ if (analysisEnvironment.getSkyframeEnv().valuesMissing()) {
+ return null;
+ }
PathFragment rootRelativePath =
outputFile.getLabel().getPackageIdentifier().getSourceRoot().getRelative(
outputFile.getLabel().getName());
@@ -162,6 +174,37 @@ public final class ConfiguredTargetFactory {
}
/**
+ * Returns the configuration's artifact owner (which may be null). Also returns null if the
+ * owning configuration isn't yet available from Skyframe.
+ */
+ public static BuildConfiguration getArtifactOwnerConfiguration(SkyFunction.Environment env,
+ BuildConfiguration fromConfig) throws InterruptedException {
+ if (fromConfig == null) {
+ return null;
+ }
+ if (!fromConfig.useDynamicConfigurations()) {
+ return fromConfig.getArtifactOwnerConfiguration();
+ }
+ PatchTransition ownerTransition = fromConfig.getArtifactOwnerTransition();
+ if (ownerTransition == null) {
+ return fromConfig;
+ }
+ try {
+ BuildConfigurationValue ownerConfig = (BuildConfigurationValue) env.getValueOrThrow(
+ BuildConfigurationValue.key(
+ fromConfig.fragmentClasses(), ownerTransition.apply(fromConfig.getOptions())),
+ InvalidConfigurationException.class);
+ return ownerConfig == null ? null : ownerConfig.getConfiguration();
+ } catch (InvalidConfigurationException e) {
+ // We don't expect to have to handle an invalid configuration because in practice the owning
+ // configuration should already exist. For example, the main user of this feature, the LIPO
+ // context collector, expects the owning configuration to be the top-level target config.
+ throw new IllegalStateException(
+ "this method should only return a pre-existing valid configuration");
+ }
+ }
+
+ /**
* Invokes the appropriate constructor to create a {@link ConfiguredTarget} instance.
* <p>For use in {@code ConfiguredTargetFunction}.
*
@@ -187,7 +230,11 @@ public final class ConfiguredTargetFactory {
if (target instanceof OutputFile) {
OutputFile outputFile = (OutputFile) target;
boolean isFileset = outputFile.getGeneratingRule().getRuleClass().equals("Fileset");
- Artifact artifact = getOutputArtifact(outputFile, config, isFileset, artifactFactory);
+ Artifact artifact =
+ getOutputArtifact(analysisEnvironment, outputFile, config, isFileset, artifactFactory);
+ if (analysisEnvironment.getSkyframeEnv().valuesMissing()) {
+ return null;
+ }
TransitiveInfoCollection rule = targetContext.findDirectPrerequisite(
outputFile.getGeneratingRule().getLabel(), config);
if (isFileset) {
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java
index af68c8b9fa..e942556160 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java
@@ -200,6 +200,18 @@ public final class BuildConfiguration {
public boolean compatibleWithStrategy(String strategyName) {
return true;
}
+
+ /**
+ * Returns the transition that produces the "artifact owner" for this configuration, or null
+ * if this configuration is its own owner.
+ *
+ * <p>If multiple fragments return the same transition, that transition is only applied
+ * once. Multiple fragments may not return different non-null transitions.
+ */
+ @Nullable
+ public PatchTransition getArtifactOwnerTransition() {
+ return null;
+ }
}
private static final Label convertLabel(String input) throws OptionsParsingException {
@@ -1968,16 +1980,21 @@ public final class BuildConfiguration {
if (currentTransition == ConfigurationTransition.NONE) {
currentTransition = ruleClassTransition;
} else {
- currentTransition = new ComposingSplitTransition(ruleClassTransition,
- currentTransition);
+ currentTransition = new ComposingSplitTransition(currentTransition,
+ ruleClassTransition);
}
}
}
- // We don't support rule class configurators (which may need intermediate configurations to
- // apply). The only current use of that is LIPO, which can't currently be invoked with dynamic
- // configurations (e.g. this code can never get called for LIPO builds). So check that
- // if there is a configurator, it's for LIPO, in which case we can ignore it.
+ /**
+ * Dynamic configurations don't support rule class configurators (which may need intermediate
+ * configurations to apply). The only current use of that is LIPO, which dynamic
+ * configurations have a different code path for:
+ * {@link com.google.devtools.build.lib.rules.cpp.CppRuleClasses.LIPO_ON_DEMAND}.
+ *
+ * So just check that if there is a configurator, it's for LIPO, in which case we can ignore
+ * it.
+ */
if (associatedRule != null) {
@SuppressWarnings("unchecked")
RuleClass.Configurator<?, ?> func =
@@ -2606,15 +2623,38 @@ public final class BuildConfiguration {
}
/**
+ * Returns the transition that produces the "artifact owner" for this configuration, or null
+ * if this configuration is its own owner.
+ *
+ * <p>This is the dynamic configuration version of {@link #getArtifactOwnerConfiguration}.
+ */
+ @Nullable
+ public PatchTransition getArtifactOwnerTransition() {
+ Preconditions.checkState(useDynamicConfigurations());
+ PatchTransition ownerTransition = null;
+ for (Fragment fragment : fragments.values()) {
+ PatchTransition fragmentTransition = fragment.getArtifactOwnerTransition();
+ if (fragmentTransition != null) {
+ if (ownerTransition != null) {
+ Verify.verify(ownerTransition == fragmentTransition,
+ String.format(
+ "cannot determine owner transition: fragments returning both %s and %s",
+ ownerTransition.toString(), fragmentTransition.toString()));
+ }
+ ownerTransition = fragmentTransition;
+ }
+ }
+ return ownerTransition;
+ }
+
+ /**
* See {@code BuildConfigurationCollection.Transitions.getArtifactOwnerConfiguration()}.
+ *
+ * <p>This is the static configuration version of {@link #getArtifactOwnerTransition}.
*/
public BuildConfiguration getArtifactOwnerConfiguration() {
- // Dynamic configurations inherit transitions objects from other configurations exclusively
- // for use of Transitions.getDynamicTransition. No other calls to transitions should be
- // made for dynamic configurations.
- // TODO(bazel-team): enforce the above automatically (without having to explicitly check
- // for dynamic configuration mode).
- return useDynamicConfigurations() ? this : transitions.getArtifactOwnerConfiguration();
+ Preconditions.checkState(!useDynamicConfigurations());
+ return transitions.getArtifactOwnerConfiguration();
}
/**