blob: 3ce85d10a0ca1948a224d711ce1020ee9bbc0ff2 [file] [log] [blame]
Damien Martin-Guillerezf88f4d82015-09-25 13:56:55 +00001// Copyright 2014 The Bazel Authors. All rights reserved.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14package com.google.devtools.build.lib.skyframe;
15
Greg Estrenad1a77e2016-09-28 14:49:12 +000016import com.google.common.annotations.VisibleForTesting;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010017import com.google.common.base.Function;
Greg Estren2bc88382016-08-02 21:45:35 +000018import com.google.common.base.Joiner;
Dmitry Lomovb5174c72017-01-10 10:57:17 +000019import com.google.common.base.Predicate;
janakr93e3eea2017-03-30 22:09:37 +000020import com.google.common.base.Supplier;
Greg Estren00049432015-08-25 16:43:47 +000021import com.google.common.base.Verify;
Greg Estrenad1a77e2016-09-28 14:49:12 +000022import com.google.common.base.VerifyException;
Greg Estren00049432015-08-25 16:43:47 +000023import com.google.common.collect.ImmutableList;
Lukacs Berki7894c182016-05-10 12:07:01 +000024import com.google.common.collect.ImmutableMap;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010025import com.google.common.collect.Iterables;
Greg Estrend5353252016-08-11 22:13:31 +000026import com.google.common.collect.LinkedHashMultimap;
Greg Estren123de312015-11-17 19:47:58 +000027import com.google.common.collect.LinkedListMultimap;
Ulf Adams7cb66de2016-01-14 08:46:43 +000028import com.google.common.collect.Maps;
Greg Estren00049432015-08-25 16:43:47 +000029import com.google.common.collect.Multimap;
Greg Estren2bc88382016-08-02 21:45:35 +000030import com.google.common.collect.Sets;
Janak Ramakrishnanb3a6ca72015-03-27 20:07:28 +000031import com.google.devtools.build.lib.actions.Actions;
janakr93e3eea2017-03-30 22:09:37 +000032import com.google.devtools.build.lib.actions.Actions.GeneratingActions;
Janak Ramakrishnanb3a6ca72015-03-27 20:07:28 +000033import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
Dmitry Lomove851fe22017-02-14 23:11:23 +000034import com.google.devtools.build.lib.analysis.AspectCollection;
35import com.google.devtools.build.lib.analysis.AspectCollection.AspectDeps;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010036import com.google.devtools.build.lib.analysis.CachingAnalysisEnvironment;
Dmitry Lomovb487ac62015-11-09 13:09:12 +000037import com.google.devtools.build.lib.analysis.ConfiguredAspect;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010038import com.google.devtools.build.lib.analysis.ConfiguredTarget;
gregcef19fcfe2017-06-02 16:04:07 -040039import com.google.devtools.build.lib.analysis.ConfiguredTargetFactory;
Michael Staib5e573fd2016-01-27 00:33:29 +000040import com.google.devtools.build.lib.analysis.Dependency;
Dmitry Lomovd83af9e2017-02-23 15:44:23 +000041import com.google.devtools.build.lib.analysis.DependencyResolver.InconsistentAspectOrderException;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010042import com.google.devtools.build.lib.analysis.LabelAndConfiguration;
Lukacs Berki549bfce2016-04-22 15:29:12 +000043import com.google.devtools.build.lib.analysis.MergedConfiguredTarget;
Dmitry Lomov9b2fc5c2016-11-11 11:18:48 +000044import com.google.devtools.build.lib.analysis.MergedConfiguredTarget.DuplicateException;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010045import com.google.devtools.build.lib.analysis.TargetAndConfiguration;
46import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
47import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
Greg Estren00049432015-08-25 16:43:47 +000048import com.google.devtools.build.lib.analysis.config.BuildOptions;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010049import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider;
Greg Estren00049432015-08-25 16:43:47 +000050import com.google.devtools.build.lib.analysis.config.HostTransition;
51import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException;
52import com.google.devtools.build.lib.analysis.config.PatchTransition;
Lukacs Berki6e91eb92015-09-21 09:12:37 +000053import com.google.devtools.build.lib.cmdline.Label;
Ulf Adams84901732016-01-28 15:05:16 +000054import com.google.devtools.build.lib.collect.nestedset.NestedSet;
Marian Loburc62faba2015-09-09 10:08:06 +000055import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
Ulf Adams84901732016-01-28 15:05:16 +000056import com.google.devtools.build.lib.collect.nestedset.Order;
Ulf Adams7cb66de2016-01-14 08:46:43 +000057import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010058import com.google.devtools.build.lib.events.Event;
59import com.google.devtools.build.lib.events.StoredEventHandler;
Dmitry Lomovb487ac62015-11-09 13:09:12 +000060import com.google.devtools.build.lib.packages.Aspect;
Dmitry Lomov15756522016-12-16 16:52:37 +000061import com.google.devtools.build.lib.packages.AspectDescriptor;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010062import com.google.devtools.build.lib.packages.Attribute;
Lukacs Berkiffa73ad2015-09-18 11:40:12 +000063import com.google.devtools.build.lib.packages.BuildType;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010064import com.google.devtools.build.lib.packages.NoSuchTargetException;
65import com.google.devtools.build.lib.packages.NoSuchThingException;
Marian Loburc62faba2015-09-09 10:08:06 +000066import com.google.devtools.build.lib.packages.Package;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010067import com.google.devtools.build.lib.packages.RawAttributeMapper;
68import com.google.devtools.build.lib.packages.Rule;
Greg Estren00049432015-08-25 16:43:47 +000069import com.google.devtools.build.lib.packages.RuleClassProvider;
Dmitry Lomovb5174c72017-01-10 10:57:17 +000070import com.google.devtools.build.lib.packages.SkylarkProviderIdentifier;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010071import com.google.devtools.build.lib.packages.Target;
72import com.google.devtools.build.lib.packages.TargetUtils;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010073import com.google.devtools.build.lib.skyframe.AspectFunction.AspectCreationException;
Dmitry Lomovca9bfa42016-11-15 13:22:36 +000074import com.google.devtools.build.lib.skyframe.AspectValue.AspectKey;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010075import com.google.devtools.build.lib.skyframe.SkyframeExecutor.BuildViewProvider;
76import com.google.devtools.build.lib.syntax.EvalException;
Greg Estrend5353252016-08-11 22:13:31 +000077import com.google.devtools.build.lib.util.OrderedSetMultimap;
Mark Schaller6df81792015-12-10 18:47:47 +000078import com.google.devtools.build.lib.util.Preconditions;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010079import com.google.devtools.build.skyframe.SkyFunction;
80import com.google.devtools.build.skyframe.SkyFunctionException;
81import com.google.devtools.build.skyframe.SkyKey;
82import com.google.devtools.build.skyframe.SkyValue;
Greg Estren00049432015-08-25 16:43:47 +000083import com.google.devtools.build.skyframe.ValueOrException;
Ulf Adams84901732016-01-28 15:05:16 +000084import com.google.devtools.build.skyframe.ValueOrException2;
Greg Estrenf4612302016-09-29 17:29:02 +000085import java.util.ArrayList;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010086import java.util.Collection;
Greg Estrendc388242016-12-07 16:47:02 +000087import java.util.Collections;
88import java.util.Comparator;
Dmitry Lomove851fe22017-02-14 23:11:23 +000089import java.util.HashMap;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010090import java.util.HashSet;
Greg Estrenf4612302016-09-29 17:29:02 +000091import java.util.Iterator;
Lukacs Berki7894c182016-05-10 12:07:01 +000092import java.util.LinkedHashMap;
Greg Estren66cadd32016-08-05 21:07:02 +000093import java.util.List;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010094import java.util.Map;
Greg Estren00049432015-08-25 16:43:47 +000095import java.util.Objects;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010096import java.util.Set;
Janak Ramakrishnanbede7b42016-11-17 18:34:08 +000097import java.util.concurrent.Semaphore;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010098import javax.annotation.Nullable;
99
100/**
101 * SkyFunction for {@link ConfiguredTargetValue}s.
Lukacs Berki2300cd62016-05-19 11:06:37 +0000102 *
103 * This class, together with {@link AspectFunction} drives the analysis phase. For more information,
104 * see {@link com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory}.
105 *
106 * @see com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100107 */
108final class ConfiguredTargetFunction implements SkyFunction {
Ulf Adams2ac20962016-02-01 13:04:54 +0000109 // This construction is a bit funky, but guarantees that the Object reference here is globally
110 // unique.
Lukacs Berki7894c182016-05-10 12:07:01 +0000111 static final ImmutableMap<Label, ConfigMatchingProvider> NO_CONFIG_CONDITIONS =
112 ImmutableMap.<Label, ConfigMatchingProvider>of();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100113
114 /**
115 * Exception class that signals an error during the evaluation of a dependency.
116 */
117 public static class DependencyEvaluationException extends Exception {
Ulf Adams25f03d82016-01-25 10:31:46 +0000118 public DependencyEvaluationException(InvalidConfigurationException cause) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100119 super(cause);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100120 }
121
Ulf Adams25f03d82016-01-25 10:31:46 +0000122 public DependencyEvaluationException(ConfiguredValueCreationException cause) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100123 super(cause);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100124 }
125
Dmitry Lomovd83af9e2017-02-23 15:44:23 +0000126 public DependencyEvaluationException(InconsistentAspectOrderException cause) {
127 super(cause);
128 }
129
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100130 @Override
Ulf Adams25f03d82016-01-25 10:31:46 +0000131 public synchronized Exception getCause() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100132 return (Exception) super.getCause();
133 }
134 }
135
136 private static final Function<Dependency, SkyKey> TO_KEYS =
137 new Function<Dependency, SkyKey>() {
138 @Override
139 public SkyKey apply(Dependency input) {
140 return ConfiguredTargetValue.key(input.getLabel(), input.getConfiguration());
141 }
142 };
143
144 private final BuildViewProvider buildViewProvider;
Greg Estren00049432015-08-25 16:43:47 +0000145 private final RuleClassProvider ruleClassProvider;
Janak Ramakrishnanbede7b42016-11-17 18:34:08 +0000146 private final Semaphore cpuBoundSemaphore;
janakr93e3eea2017-03-30 22:09:37 +0000147 private final Supplier<Boolean> removeActionsAfterEvaluation;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100148
Janak Ramakrishnanbede7b42016-11-17 18:34:08 +0000149 ConfiguredTargetFunction(
150 BuildViewProvider buildViewProvider,
151 RuleClassProvider ruleClassProvider,
janakr93e3eea2017-03-30 22:09:37 +0000152 Semaphore cpuBoundSemaphore,
153 Supplier<Boolean> removeActionsAfterEvaluation) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100154 this.buildViewProvider = buildViewProvider;
Greg Estren00049432015-08-25 16:43:47 +0000155 this.ruleClassProvider = ruleClassProvider;
Janak Ramakrishnanbede7b42016-11-17 18:34:08 +0000156 this.cpuBoundSemaphore = cpuBoundSemaphore;
janakr93e3eea2017-03-30 22:09:37 +0000157 this.removeActionsAfterEvaluation = Preconditions.checkNotNull(removeActionsAfterEvaluation);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100158 }
159
Greg Estrenb5692bd2016-06-08 21:09:11 +0000160 private static boolean useDynamicConfigurations(BuildConfiguration config) {
161 return config != null && config.useDynamicConfigurations();
162 }
163
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100164 @Override
165 public SkyValue compute(SkyKey key, Environment env) throws ConfiguredTargetFunctionException,
166 InterruptedException {
167 SkyframeBuildView view = buildViewProvider.getSkyframeBuildView();
Marian Loburc62faba2015-09-09 10:08:06 +0000168 NestedSetBuilder<Package> transitivePackages = NestedSetBuilder.stableOrder();
Ulf Adams84901732016-01-28 15:05:16 +0000169 NestedSetBuilder<Label> transitiveLoadingRootCauses = NestedSetBuilder.stableOrder();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100170 ConfiguredTargetKey configuredTargetKey = (ConfiguredTargetKey) key.argument();
171 LabelAndConfiguration lc = LabelAndConfiguration.of(
172 configuredTargetKey.getLabel(), configuredTargetKey.getConfiguration());
173
174 BuildConfiguration configuration = lc.getConfiguration();
175
176 PackageValue packageValue =
177 (PackageValue) env.getValue(PackageValue.key(lc.getLabel().getPackageIdentifier()));
178 if (packageValue == null) {
179 return null;
180 }
Ulf Adams2ac20962016-02-01 13:04:54 +0000181
182 // TODO(ulfjack): This tries to match the logic in TransitiveTargetFunction /
183 // TargetMarkerFunction. Maybe we can merge the two?
Janak Ramakrishnan0a4c6e42015-09-17 00:37:58 +0000184 Package pkg = packageValue.getPackage();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100185 Target target;
186 try {
Ulf Adams2ac20962016-02-01 13:04:54 +0000187 target = pkg.getTarget(lc.getLabel().getName());
Ulf Adams96683612016-01-25 09:04:54 +0000188 } catch (NoSuchTargetException e) {
Ulf Adams2ac20962016-02-01 13:04:54 +0000189 throw new ConfiguredTargetFunctionException(
190 new ConfiguredValueCreationException(e.getMessage()));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100191 }
Ulf Adams2ac20962016-02-01 13:04:54 +0000192 if (pkg.containsErrors()) {
Lukacs Berki7894c182016-05-10 12:07:01 +0000193 transitiveLoadingRootCauses.add(lc.getLabel());
Ulf Adams2ac20962016-02-01 13:04:54 +0000194 }
195 transitivePackages.add(pkg);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100196 // TODO(bazel-team): This is problematic - we create the right key, but then end up with a value
197 // that doesn't match; we can even have the same value multiple times. However, I think it's
198 // only triggered in tests (i.e., in normal operation, the configuration passed in is already
199 // null).
Greg Estrena6c88962015-09-28 19:35:18 +0000200 if (!target.isConfigurable()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100201 configuration = null;
202 }
Greg Estrenb5692bd2016-06-08 21:09:11 +0000203
204 // This line is only needed for accurate error messaging. Say this target has a circular
205 // dependency with one of its deps. With this line, loading this target fails so Bazel
206 // associates the corresponding error with this target, as expected. Without this line,
207 // the first TransitiveTargetValue call happens on its dep (in trimConfigurations), so Bazel
208 // associates the error with the dep, which is misleading.
Greg Estren8d76f072016-09-23 23:24:59 +0000209 if (useDynamicConfigurations(configuration) && configuration.trimConfigurations()
Greg Estrenb5692bd2016-06-08 21:09:11 +0000210 && env.getValue(TransitiveTargetValue.key(lc.getLabel())) == null) {
211 return null;
212 }
213
Ulf Adams2ac20962016-02-01 13:04:54 +0000214 TargetAndConfiguration ctgValue = new TargetAndConfiguration(target, configuration);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100215
216 SkyframeDependencyResolver resolver = view.createDependencyResolver(env);
Janak Ramakrishnanbede7b42016-11-17 18:34:08 +0000217
218 // TODO(janakr): this acquire() call may tie up this thread indefinitely, reducing the
219 // parallelism of Skyframe. This is a strict improvement over the prior state of the code, in
220 // which we ran with #processors threads, but ideally we would call #tryAcquire here, and if we
221 // failed, would exit this SkyFunction and restart it when permits were available.
222 cpuBoundSemaphore.acquire();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100223 try {
224 // Get the configuration targets that trigger this rule's configurable attributes.
Lukacs Berki7894c182016-05-10 12:07:01 +0000225 ImmutableMap<Label, ConfigMatchingProvider> configConditions = getConfigConditions(
Ulf Adams84901732016-01-28 15:05:16 +0000226 ctgValue.getTarget(), env, resolver, ctgValue, transitivePackages,
227 transitiveLoadingRootCauses);
Greg Estren00049432015-08-25 16:43:47 +0000228 if (env.valuesMissing()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100229 return null;
230 }
Ulf Adams2ac20962016-02-01 13:04:54 +0000231 // TODO(ulfjack): ConfiguredAttributeMapper (indirectly used from computeDependencies) isn't
232 // safe to use if there are missing config conditions, so we stop here, but only if there are
233 // config conditions - though note that we can't check if configConditions is non-empty - it
234 // may be empty for other reasons. It would be better to continue here so that we can collect
235 // more root causes during computeDependencies.
236 // Note that this doesn't apply to AspectFunction, because aspects can't have configurable
237 // attributes.
238 if (!transitiveLoadingRootCauses.isEmpty() && configConditions != NO_CONFIG_CONDITIONS) {
239 throw new ConfiguredTargetFunctionException(
240 new ConfiguredValueCreationException(transitiveLoadingRootCauses.build()));
241 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100242
Greg Estrend5353252016-08-11 22:13:31 +0000243 OrderedSetMultimap<Attribute, ConfiguredTarget> depValueMap =
Dmitry Lomov6231d082015-11-02 17:17:20 +0000244 computeDependencies(
245 env,
246 resolver,
247 ctgValue,
Dmitry Lomovca9bfa42016-11-15 13:22:36 +0000248 ImmutableList.<Aspect>of(),
Dmitry Lomov6231d082015-11-02 17:17:20 +0000249 configConditions,
250 ruleClassProvider,
251 view.getHostConfiguration(configuration),
Ulf Adams84901732016-01-28 15:05:16 +0000252 transitivePackages,
253 transitiveLoadingRootCauses);
254 if (env.valuesMissing()) {
255 return null;
256 }
257 if (!transitiveLoadingRootCauses.isEmpty()) {
258 throw new ConfiguredTargetFunctionException(
259 new ConfiguredValueCreationException(transitiveLoadingRootCauses.build()));
260 }
261 Preconditions.checkNotNull(depValueMap);
Greg Estren00049432015-08-25 16:43:47 +0000262 ConfiguredTargetValue ans = createConfiguredTarget(
Marian Loburc62faba2015-09-09 10:08:06 +0000263 view, env, target, configuration, depValueMap, configConditions, transitivePackages);
Greg Estren00049432015-08-25 16:43:47 +0000264 return ans;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100265 } catch (DependencyEvaluationException e) {
Ulf Adams25f03d82016-01-25 10:31:46 +0000266 if (e.getCause() instanceof ConfiguredValueCreationException) {
267 throw new ConfiguredTargetFunctionException(
268 (ConfiguredValueCreationException) e.getCause());
Dmitry Lomovd83af9e2017-02-23 15:44:23 +0000269 } else if (e.getCause() instanceof InconsistentAspectOrderException) {
270 InconsistentAspectOrderException cause = (InconsistentAspectOrderException) e.getCause();
271 throw new ConfiguredTargetFunctionException(
272 new ConfiguredValueCreationException(cause.getMessage(), target.getLabel()));
Ulf Adams25f03d82016-01-25 10:31:46 +0000273 } else {
274 // Cast to InvalidConfigurationException as a consistency check. If you add any
275 // DependencyEvaluationException constructors, you may need to change this code, too.
276 InvalidConfigurationException cause = (InvalidConfigurationException) e.getCause();
277 throw new ConfiguredTargetFunctionException(
278 new ConfiguredValueCreationException(cause.getMessage(), target.getLabel()));
279 }
Marian Loburfc567b32015-09-14 08:44:25 +0000280 } catch (AspectCreationException e) {
Ulf Adams25f03d82016-01-25 10:31:46 +0000281 // getAnalysisRootCause may be null if the analysis of the aspect itself failed.
Ulf Adams84901732016-01-28 15:05:16 +0000282 Label analysisRootCause = target.getLabel();
Ulf Adams25f03d82016-01-25 10:31:46 +0000283 if (e.getAnalysisRootCause() != null) {
Ulf Adams84901732016-01-28 15:05:16 +0000284 analysisRootCause = e.getAnalysisRootCause();
Ulf Adams25f03d82016-01-25 10:31:46 +0000285 }
Marian Loburfc567b32015-09-14 08:44:25 +0000286 throw new ConfiguredTargetFunctionException(
Ulf Adams84901732016-01-28 15:05:16 +0000287 new ConfiguredValueCreationException(e.getMessage(), analysisRootCause));
Janak Ramakrishnanbede7b42016-11-17 18:34:08 +0000288 } finally {
289 cpuBoundSemaphore.release();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100290 }
291 }
292
293 /**
294 * Computes the direct dependencies of a node in the configured target graph (a configured
Dmitry Lomovca9bfa42016-11-15 13:22:36 +0000295 * target or an aspects).
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100296 *
297 * <p>Returns null if Skyframe hasn't evaluated the required dependencies yet. In this case, the
298 * caller should also return null to Skyframe.
Dmitry Lomov6231d082015-11-02 17:17:20 +0000299 * @param env the Skyframe environment
Greg Estren86045da2016-12-14 19:46:48 +0000300 * @param resolver the dependency resolver
301 * @param ctgValue the label and the configuration of the node
Dmitry Lomovca9bfa42016-11-15 13:22:36 +0000302 * @param aspects
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100303 * @param configConditions the configuration conditions for evaluating the attributes of the node
Greg Estren00049432015-08-25 16:43:47 +0000304 * @param ruleClassProvider rule class provider for determining the right configuration fragments
305 * to apply to deps
306 * @param hostConfiguration the host configuration. There's a noticeable performance hit from
307 * instantiating this on demand for every dependency that wants it, so it's best to compute
308 * the host configuration as early as possible and pass this reference to all consumers
Dmitry Lomov6231d082015-11-02 17:17:20 +0000309 * */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100310 @Nullable
Greg Estrend5353252016-08-11 22:13:31 +0000311 static OrderedSetMultimap<Attribute, ConfiguredTarget> computeDependencies(
Dmitry Lomov6231d082015-11-02 17:17:20 +0000312 Environment env,
313 SkyframeDependencyResolver resolver,
314 TargetAndConfiguration ctgValue,
Dmitry Lomovca9bfa42016-11-15 13:22:36 +0000315 Iterable<Aspect> aspects,
Lukacs Berki7894c182016-05-10 12:07:01 +0000316 ImmutableMap<Label, ConfigMatchingProvider> configConditions,
Dmitry Lomov6231d082015-11-02 17:17:20 +0000317 RuleClassProvider ruleClassProvider,
318 BuildConfiguration hostConfiguration,
Ulf Adams84901732016-01-28 15:05:16 +0000319 NestedSetBuilder<Package> transitivePackages,
320 NestedSetBuilder<Label> transitiveLoadingRootCauses)
Dmitry Lomov9b2fc5c2016-11-11 11:18:48 +0000321 throws DependencyEvaluationException, ConfiguredTargetFunctionException,
322 AspectCreationException, InterruptedException {
Greg Estrend5353252016-08-11 22:13:31 +0000323 // Create the map from attributes to set of (target, configuration) pairs.
324 OrderedSetMultimap<Attribute, Dependency> depValueNames;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100325 try {
Ulf Adams84901732016-01-28 15:05:16 +0000326 depValueNames = resolver.dependentNodeMap(
Dmitry Lomovca9bfa42016-11-15 13:22:36 +0000327 ctgValue, hostConfiguration, aspects, configConditions, transitiveLoadingRootCauses);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100328 } catch (EvalException e) {
Ulf Adams25f03d82016-01-25 10:31:46 +0000329 // EvalException can only be thrown by computed Skylark attributes in the current rule.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100330 env.getListener().handle(Event.error(e.getLocation(), e.getMessage()));
Ulf Adams25f03d82016-01-25 10:31:46 +0000331 throw new DependencyEvaluationException(
332 new ConfiguredValueCreationException(e.print(), ctgValue.getLabel()));
Greg Estren373e3e22016-08-09 22:36:51 +0000333 } catch (InvalidConfigurationException e) {
334 throw new DependencyEvaluationException(e);
Dmitry Lomovd83af9e2017-02-23 15:44:23 +0000335 } catch (InconsistentAspectOrderException e) {
336 env.getListener().handle(Event.error(e.getLocation(), e.getMessage()));
337 throw new DependencyEvaluationException(e);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100338 }
339
Greg Estren00049432015-08-25 16:43:47 +0000340 // Trim each dep's configuration so it only includes the fragments needed by its transitive
341 // closure (only dynamic configurations support this).
Greg Estrenb5692bd2016-06-08 21:09:11 +0000342 if (useDynamicConfigurations(ctgValue.getConfiguration())) {
Greg Estren1d8ba902016-09-21 21:18:19 +0000343 depValueNames = getDynamicConfigurations(env, ctgValue, depValueNames, hostConfiguration,
Greg Estren00049432015-08-25 16:43:47 +0000344 ruleClassProvider);
Greg Estren86045da2016-12-14 19:46:48 +0000345 // It's important that we don't use "if (env.missingValues()) { return null }" here (or
346 // in the following lines). See the comments in getDynamicConfigurations' Skyframe call
347 // for explanation.
Greg Estren00049432015-08-25 16:43:47 +0000348 if (depValueNames == null) {
349 return null;
350 }
351 }
352
353 // Resolve configured target dependencies and handle errors.
Marian Loburc62faba2015-09-09 10:08:06 +0000354 Map<SkyKey, ConfiguredTarget> depValues = resolveConfiguredTargetDependencies(env,
Ulf Adams84901732016-01-28 15:05:16 +0000355 depValueNames.values(), transitivePackages, transitiveLoadingRootCauses);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100356 if (depValues == null) {
357 return null;
358 }
359
Greg Estren00049432015-08-25 16:43:47 +0000360 // Resolve required aspects.
Greg Estrend5353252016-08-11 22:13:31 +0000361 OrderedSetMultimap<SkyKey, ConfiguredAspect> depAspects = resolveAspectDependencies(
Ulf Adams84901732016-01-28 15:05:16 +0000362 env, depValues, depValueNames.values(), transitivePackages);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100363 if (depAspects == null) {
364 return null;
365 }
366
Greg Estren00049432015-08-25 16:43:47 +0000367 // Merge the dependent configured targets and aspects into a single map.
Dmitry Lomov9b2fc5c2016-11-11 11:18:48 +0000368 try {
369 return mergeAspects(depValueNames, depValues, depAspects);
370 } catch (DuplicateException e) {
371 env.getListener().handle(
372 Event.error(ctgValue.getTarget().getLocation(), e.getMessage()));
373
374 throw new ConfiguredTargetFunctionException(
375 new ConfiguredValueCreationException(e.getMessage(), ctgValue.getLabel()));
376 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100377 }
378
379 /**
Greg Estren1d8ba902016-09-21 21:18:19 +0000380 * Helper class for {@link #getDynamicConfigurations} - encapsulates a set of config fragments and
Greg Estren00049432015-08-25 16:43:47 +0000381 * a dynamic transition. This can be used to determine the exact build options needed to
382 * set a dynamic configuration.
383 */
Greg Estrene5c9dbe02015-11-18 20:47:43 +0000384 @Immutable
Greg Estren00049432015-08-25 16:43:47 +0000385 private static final class FragmentsAndTransition {
386 // Treat this as immutable. The only reason this isn't an ImmutableSet is because it
387 // gets bound to a NestedSet.toSet() reference, which returns a Set interface.
388 final Set<Class<? extends BuildConfiguration.Fragment>> fragments;
389 final Attribute.Transition transition;
390 private final int hashCode;
391
392 FragmentsAndTransition(Set<Class<? extends BuildConfiguration.Fragment>> fragments,
393 Attribute.Transition transition) {
394 this.fragments = fragments;
395 this.transition = transition;
396 hashCode = Objects.hash(this.fragments, this.transition);
397 }
398
399 @Override
400 public boolean equals(Object o) {
401 if (o == this) {
402 return true;
403 } else if (o == null) {
404 return false;
405 } else {
406 FragmentsAndTransition other = (FragmentsAndTransition) o;
407 return other.transition.equals(transition) && other.fragments.equals(fragments);
408 }
409 }
410
411 @Override
412 public int hashCode() {
413 return hashCode;
414 }
415 }
416
417 /**
Greg Estren1d8ba902016-09-21 21:18:19 +0000418 * Helper class for {@link #getDynamicConfigurations} - encapsulates an <attribute, label> pair
419 * that can be used to map from an input dependency to a trimmed dependency.
Greg Estrene5c9dbe02015-11-18 20:47:43 +0000420 */
421 @Immutable
422 private static final class AttributeAndLabel {
423 final Attribute attribute;
424 final Label label;
Greg Estren13a73e42016-09-29 18:44:03 +0000425 Integer hashCode;
Greg Estrene5c9dbe02015-11-18 20:47:43 +0000426
427 AttributeAndLabel(Attribute attribute, Label label) {
428 this.attribute = attribute;
429 this.label = label;
Greg Estrene5c9dbe02015-11-18 20:47:43 +0000430 }
431
432 @Override
433 public boolean equals(Object o) {
434 if (!(o instanceof AttributeAndLabel)) {
435 return false;
436 }
437 AttributeAndLabel other = (AttributeAndLabel) o;
438 return Objects.equals(other.attribute, attribute) && other.label.equals(label);
439 }
440
441 @Override
442 public int hashCode() {
Greg Estren13a73e42016-09-29 18:44:03 +0000443 if (hashCode == null) {
444 // Not every <Attribute, Label> pair gets hashed. So only evaluate for the instances that
445 // need it. This can significantly reduce the number of evaluations.
446 hashCode = Objects.hash(this.attribute, this.label);
447 }
Greg Estrene5c9dbe02015-11-18 20:47:43 +0000448 return hashCode;
449 }
450 }
451
452 /**
Greg Estren66cadd32016-08-05 21:07:02 +0000453 * Variation of {@link Multimap#put} that triggers an exception if a value already exists.
Greg Estrene5c9dbe02015-11-18 20:47:43 +0000454 */
Greg Estrenad1a77e2016-09-28 14:49:12 +0000455 @VisibleForTesting
456 static <K, V> void putOnlyEntry(Multimap<K, V> map, K key, V value) {
457 // Performance note: while "Verify.verify(!map.containsKey(key, value), String.format(...)))"
458 // is simpler code, profiling shows a substantial performance penalty to that approach
459 // (~10% extra analysis phase time on a simple cc_binary). Most of that is from the cost of
460 // evaluating value.toString() on every call. This approach essentially eliminates the overhead.
461 if (map.containsKey(key)) {
462 throw new VerifyException(
463 String.format("couldn't insert %s: map already has key %s",
464 value.toString(), key.toString()));
465 }
Greg Estren66cadd32016-08-05 21:07:02 +0000466 map.put(key, value);
Greg Estrene5c9dbe02015-11-18 20:47:43 +0000467 }
468
469 /**
Greg Estren00049432015-08-25 16:43:47 +0000470 * Creates a dynamic configuration for each dep that's custom-fitted specifically for that dep.
471 *
472 * <p>More specifically: given a set of {@link Dependency} instances holding dynamic config
473 * transition requests (e.g. {@link Dependency#hasStaticConfiguration()} == false}), returns
Greg Estren1d8ba902016-09-21 21:18:19 +0000474 * equivalent dependencies containing dynamically created configurations applying those
475 * transitions. If {@link BuildConfiguration.Options#trimConfigurations()} is true, these
476 * configurations only contain the fragments needed by the dep and its transitive closure. Else
477 * the configurations unconditionally include all fragments.
Greg Estren00049432015-08-25 16:43:47 +0000478 *
479 * <p>This method is heavily performance-optimized. Because it, in aggregate, reads over every
Greg Estren86045da2016-12-14 19:46:48 +0000480 * edge in the configured target graph, small inefficiencies can have observable impact on
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +0000481 * analysis time. Keep this in mind when making modifications and performance-test any changes you
482 * make.
Greg Estren86045da2016-12-14 19:46:48 +0000483 *
484 * @param env Skyframe evaluation environment
485 * @param ctgValue the label and the configuration of the node
486 * @param originalDeps the set of configuration transition requests for this target's attributes
487 * @param hostConfiguration the host configuration
488 * @param ruleClassProvider the rule class provider for determining the right configuration
489 * fragments to apply to deps
490 *
491 * @return a mapping from each attribute to the {@link BuildConfiguration}s and {@link Label}s
492 * to use for that attribute's deps. Returns null if not all Skyframe dependencies are
493 * available yet.
Greg Estren00049432015-08-25 16:43:47 +0000494 */
495 @Nullable
Greg Estren1d8ba902016-09-21 21:18:19 +0000496 static OrderedSetMultimap<Attribute, Dependency> getDynamicConfigurations(
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +0000497 Environment env,
498 TargetAndConfiguration ctgValue,
499 OrderedSetMultimap<Attribute, Dependency> originalDeps,
500 BuildConfiguration hostConfiguration,
501 RuleClassProvider ruleClassProvider)
502 throws DependencyEvaluationException, InterruptedException {
Greg Estren00049432015-08-25 16:43:47 +0000503
504 // Maps each Skyframe-evaluated BuildConfiguration to the dependencies that need that
505 // configuration. For cases where Skyframe isn't needed to get the configuration (e.g. when
506 // we just re-used the original rule's configuration), we should skip this outright.
Greg Estren123de312015-11-17 19:47:58 +0000507 Multimap<SkyKey, Map.Entry<Attribute, Dependency>> keysToEntries = LinkedListMultimap.create();
Greg Estren00049432015-08-25 16:43:47 +0000508
509 // Stores the result of applying a dynamic transition to the current configuration using a
510 // particular subset of fragments. By caching this, we save from redundantly computing the
511 // same transition for every dependency edge that requests that transition. This can have
512 // real effect on analysis time for commonly triggered transitions.
Greg Estren66cadd32016-08-05 21:07:02 +0000513 //
514 // Split transitions may map to multiple values. All other transitions map to one.
515 Map<FragmentsAndTransition, List<BuildOptions>> transitionsMap = new LinkedHashMap<>();
Greg Estren00049432015-08-25 16:43:47 +0000516
517 // The fragments used by the current target's configuration.
518 Set<Class<? extends BuildConfiguration.Fragment>> ctgFragments =
519 ctgValue.getConfiguration().fragmentClasses();
520 BuildOptions ctgOptions = ctgValue.getConfiguration().getOptions();
521
Greg Estrendc388242016-12-07 16:47:02 +0000522 // Stores the dynamically configured versions of each dependency. This method must preserve the
523 // original label ordering of each attribute. For example, if originalDeps.get("data") is
524 // [":a", ":b"], the dynamic variant must also be [":a", ":b"] in the same order. Because we may
525 // not actualize the results in order (some results need Skyframe-evaluated configurations while
526 // others can be computed trivially), we dump them all into this map, then as a final step
527 // iterate through the original list and pluck out values from here for the final value.
528 //
529 // For split transitions, originaldeps.get("data") = [":a", ":b"] can produce the output
530 // [":a"<config1>, ":a"<config2>, ..., ":b"<config1>, ":b"<config2>, ...]. All instances of ":a"
531 // still appear before all instances of ":b". But the [":a"<config1>, ":a"<config2>"] subset may
532 // be in any (deterministic) order. In particular, this may not be the same order as
533 // SplitTransition.split. If needed, this code can be modified to use that order, but that
534 // involves more runtime in performance-critical code, so we won't make that change without a
535 // clear need.
Greg Estrenad1a77e2016-09-28 14:49:12 +0000536 //
537 // This map is used heavily by all builds. Inserts and gets should be as fast as possible.
Greg Estrendc388242016-12-07 16:47:02 +0000538 Multimap<AttributeAndLabel, Dependency> dynamicDeps = LinkedHashMultimap.create();
Greg Estren00049432015-08-25 16:43:47 +0000539
Greg Estrenf4612302016-09-29 17:29:02 +0000540 // Performance optimization: This method iterates over originalDeps twice. By storing
541 // AttributeAndLabel instances in this list, we avoid having to recreate them the second time
542 // (particularly avoid recomputing their hash codes). Profiling shows this shaves 25% off this
543 // method's execution time (at the time of this comment).
544 ArrayList<AttributeAndLabel> attributesAndLabels = new ArrayList<>(originalDeps.size());
545
Greg Estren00049432015-08-25 16:43:47 +0000546 for (Map.Entry<Attribute, Dependency> depsEntry : originalDeps.entries()) {
547 Dependency dep = depsEntry.getValue();
Greg Estrene5c9dbe02015-11-18 20:47:43 +0000548 AttributeAndLabel attributeAndLabel =
549 new AttributeAndLabel(depsEntry.getKey(), dep.getLabel());
Greg Estrenf4612302016-09-29 17:29:02 +0000550 attributesAndLabels.add(attributeAndLabel);
Greg Estrenad1a77e2016-09-28 14:49:12 +0000551 // Certain targets (like output files) trivially re-use their input configuration. Likewise,
552 // deps with null configurations (e.g. source files), can be trivially computed. So we skip
553 // all logic in this method for these cases and just reinsert their original configurations
Greg Estren9e26f0f2016-09-29 01:01:57 +0000554 // back at the end (note that null-configured targets will have a static
555 // NullConfigurationDependency instead of dynamic
556 // Dependency(label, transition=Attribute.Configuration.Transition.NULL)).
Greg Estrenad1a77e2016-09-28 14:49:12 +0000557 //
558 // A *lot* of targets have null deps, so this produces real savings. Profiling tests over a
559 // simple cc_binary show this saves ~1% of total analysis phase time.
Greg Estren9e26f0f2016-09-29 01:01:57 +0000560 if (dep.hasStaticConfiguration()) {
Greg Estren00049432015-08-25 16:43:47 +0000561 continue;
562 }
563
564 // Figure out the required fragments for this dep and its transitive closure.
Greg Estren1d8ba902016-09-21 21:18:19 +0000565 Set<Class<? extends BuildConfiguration.Fragment>> depFragments =
566 getTransitiveFragments(env, dep.getLabel(), ctgValue.getConfiguration());
567 if (depFragments == null) {
Greg Estren00049432015-08-25 16:43:47 +0000568 return null;
569 }
Greg Estren2bc88382016-08-02 21:45:35 +0000570 // TODO(gregce): remove the below call once we have confidence dynamic configurations always
Greg Estrenad1a77e2016-09-28 14:49:12 +0000571 // provide needed fragments. This unnecessarily drags performance on the critical path (up
572 // to 0.5% of total analysis time as profiled over a simple cc_binary).
573 if (ctgValue.getConfiguration().trimConfigurations()) {
574 checkForMissingFragments(env, ctgValue, attributeAndLabel.attribute.getName(), dep,
575 depFragments);
576 }
Greg Estren00049432015-08-25 16:43:47 +0000577
578 boolean sameFragments = depFragments.equals(ctgFragments);
579 Attribute.Transition transition = dep.getTransition();
580
581 if (sameFragments) {
582 if (transition == Attribute.ConfigurationTransition.NONE) {
583 // The dep uses the same exact configuration.
Michael Staib5e573fd2016-01-27 00:33:29 +0000584 putOnlyEntry(
Greg Estrendc388242016-12-07 16:47:02 +0000585 dynamicDeps,
Michael Staib5e573fd2016-01-27 00:33:29 +0000586 attributeAndLabel,
587 Dependency.withConfigurationAndAspects(
588 dep.getLabel(), ctgValue.getConfiguration(), dep.getAspects()));
Greg Estren00049432015-08-25 16:43:47 +0000589 continue;
590 } else if (transition == HostTransition.INSTANCE) {
591 // The current rule's host configuration can also be used for the dep. We short-circuit
592 // the standard transition logic for host transitions because these transitions are
593 // uniquely frequent. It's possible, e.g., for every node in the configured target graph
594 // to incur multiple host transitions. So we aggressively optimize to avoid hurting
595 // analysis time.
Michael Staib5e573fd2016-01-27 00:33:29 +0000596 putOnlyEntry(
Greg Estrendc388242016-12-07 16:47:02 +0000597 dynamicDeps,
Michael Staib5e573fd2016-01-27 00:33:29 +0000598 attributeAndLabel,
599 Dependency.withConfigurationAndAspects(
600 dep.getLabel(), hostConfiguration, dep.getAspects()));
Greg Estren00049432015-08-25 16:43:47 +0000601 continue;
602 }
603 }
604
605 // Apply the transition or use the cached result if it was already applied.
606 FragmentsAndTransition transitionKey = new FragmentsAndTransition(depFragments, transition);
Greg Estren66cadd32016-08-05 21:07:02 +0000607 List<BuildOptions> toOptions = transitionsMap.get(transitionKey);
Greg Estren00049432015-08-25 16:43:47 +0000608 if (toOptions == null) {
Greg Estrenb0de9192016-11-16 17:44:16 +0000609 toOptions = getDynamicTransitionOptions(ctgOptions, transition, depFragments,
610 ruleClassProvider, !sameFragments);
Greg Estren00049432015-08-25 16:43:47 +0000611 transitionsMap.put(transitionKey, toOptions);
612 }
613
614 // If the transition doesn't change the configuration, trivially re-use the original
615 // configuration.
Greg Estren66cadd32016-08-05 21:07:02 +0000616 if (sameFragments && toOptions.size() == 1
617 && Iterables.getOnlyElement(toOptions).equals(ctgOptions)) {
Michael Staib5e573fd2016-01-27 00:33:29 +0000618 putOnlyEntry(
Greg Estrendc388242016-12-07 16:47:02 +0000619 dynamicDeps,
Michael Staib5e573fd2016-01-27 00:33:29 +0000620 attributeAndLabel,
621 Dependency.withConfigurationAndAspects(
622 dep.getLabel(), ctgValue.getConfiguration(), dep.getAspects()));
Greg Estren00049432015-08-25 16:43:47 +0000623 continue;
624 }
625
626 // If we get here, we have to get the configuration from Skyframe.
Greg Estren66cadd32016-08-05 21:07:02 +0000627 for (BuildOptions options : toOptions) {
628 keysToEntries.put(BuildConfigurationValue.key(depFragments, options), depsEntry);
629 }
Greg Estren00049432015-08-25 16:43:47 +0000630 }
631
Greg Estren86045da2016-12-14 19:46:48 +0000632 // Get all BuildConfigurations we need from Skyframe. While not every value might be available,
633 // we don't call env.valuesMissing() here because that could be true from the earlier
634 // resolver.dependentNodeMap call in computeDependencies, which also calls Skyframe. This method
635 // doesn't need those missing values, but it still has to be called after
636 // resolver.dependentNodeMap because it consumes that method's output. The reason the missing
637 // values don't matter is because resolver.dependentNodeMap still returns "partial" results
638 // and this method runs over whatever's available.
639 //
640 // While there would be no *correctness* harm in nulling out early, there's significant
641 // *performance* harm. Profiling shows that putting "if (env.valuesMissing()) { return null; }"
642 // here (or even after resolver.dependentNodeMap) produces a ~30% performance hit on the
643 // analysis phase. That's because resolveConfiguredTargetDependencies and
644 // resolveAspectDependencies don't get a chance to make their own Skyframe requests before
645 // bailing out of this ConfiguredTargetFunction call. Ideally we could batch all requests
646 // from all methods into a single Skyframe call, but there are enough subtle data flow
647 // dependencies in ConfiguredTargetFucntion to make that impractical.
Greg Estren00049432015-08-25 16:43:47 +0000648 Map<SkyKey, ValueOrException<InvalidConfigurationException>> depConfigValues =
649 env.getValuesOrThrow(keysToEntries.keySet(), InvalidConfigurationException.class);
Greg Estren00049432015-08-25 16:43:47 +0000650
651 // Now fill in the remaining unresolved deps with the now-resolved configurations.
652 try {
653 for (Map.Entry<SkyKey, ValueOrException<InvalidConfigurationException>> entry :
654 depConfigValues.entrySet()) {
655 SkyKey key = entry.getKey();
Greg Estren86045da2016-12-14 19:46:48 +0000656 ValueOrException<InvalidConfigurationException> valueOrException = entry.getValue();
657 if (valueOrException.get() == null) {
658 // Instead of env.missingValues(), check for missing values here. This guarantees we only
659 // null out on missing values from *this specific Skyframe request*.
660 return null;
661 }
662 BuildConfigurationValue trimmedConfig = (BuildConfigurationValue) valueOrException.get();
Greg Estren00049432015-08-25 16:43:47 +0000663 for (Map.Entry<Attribute, Dependency> info : keysToEntries.get(key)) {
Greg Estren00049432015-08-25 16:43:47 +0000664 Dependency originalDep = info.getValue();
Greg Estren66cadd32016-08-05 21:07:02 +0000665 AttributeAndLabel attr = new AttributeAndLabel(info.getKey(), originalDep.getLabel());
666 Dependency resolvedDep = Dependency.withConfigurationAndAspects(originalDep.getLabel(),
667 trimmedConfig.getConfiguration(), originalDep.getAspects());
Greg Estren373e3e22016-08-09 22:36:51 +0000668 if (attr.attribute.hasSplitConfigurationTransition()) {
Greg Estrendc388242016-12-07 16:47:02 +0000669 dynamicDeps.put(attr, resolvedDep);
Greg Estren66cadd32016-08-05 21:07:02 +0000670 } else {
Greg Estrendc388242016-12-07 16:47:02 +0000671 putOnlyEntry(dynamicDeps, attr, resolvedDep);
Greg Estren66cadd32016-08-05 21:07:02 +0000672 }
Greg Estren00049432015-08-25 16:43:47 +0000673 }
674 }
675 } catch (InvalidConfigurationException e) {
676 throw new DependencyEvaluationException(e);
677 }
678
Greg Estrendc388242016-12-07 16:47:02 +0000679 return sortDynamicallyConfiguredDeps(originalDeps, dynamicDeps, attributesAndLabels);
Greg Estren00049432015-08-25 16:43:47 +0000680 }
681
682 /**
Greg Estren1d8ba902016-09-21 21:18:19 +0000683 * Returns the configuration fragments required by a dep and its transitive closure.
684 * Returns null if Skyframe dependencies aren't yet available.
685 *
686 * @param env Skyframe evaluation environment
687 * @param dep label of the dep to check
688 * @param parentConfig configuration of the rule depending on the dep
689 */
690 @Nullable
691 private static Set<Class<? extends BuildConfiguration.Fragment>> getTransitiveFragments(
692 Environment env, Label dep, BuildConfiguration parentConfig) throws InterruptedException {
693 Preconditions.checkArgument(parentConfig.useDynamicConfigurations());
694 if (!parentConfig.trimConfigurations()) {
695 return parentConfig.getAllFragments().keySet();
696 }
697 SkyKey fragmentsKey = TransitiveTargetValue.key(dep);
698 TransitiveTargetValue transitiveDepInfo = (TransitiveTargetValue) env.getValue(fragmentsKey);
699 if (transitiveDepInfo == null) {
700 // This should only be possible for tests. In actual runs, this was already called
701 // as a routine part of the loading phase.
702 // TODO(bazel-team): check this only occurs in a test context.
703 return null;
704 }
705 return transitiveDepInfo.getTransitiveConfigFragments().toSet();
706 }
707
708 /**
Greg Estren66cadd32016-08-05 21:07:02 +0000709 * Applies a dynamic configuration transition over a set of build options.
710 *
Greg Estrenb0de9192016-11-16 17:44:16 +0000711 * @return the build options for the transitioned configuration. If trimResults is true,
712 * only options needed by the required fragments are included. Else the same options as the
713 * original input are included (with different possible values, of course).
Greg Estren66cadd32016-08-05 21:07:02 +0000714 */
Greg Estrenb0de9192016-11-16 17:44:16 +0000715 static List<BuildOptions> getDynamicTransitionOptions(BuildOptions fromOptions,
716 Attribute.Transition transition,
717 Iterable<Class<? extends BuildConfiguration.Fragment>> requiredFragments,
718 RuleClassProvider ruleClassProvider, boolean trimResults) {
719 List<BuildOptions> result;
Greg Estren66cadd32016-08-05 21:07:02 +0000720 if (transition == Attribute.ConfigurationTransition.NONE) {
Greg Estrenb0de9192016-11-16 17:44:16 +0000721 result = ImmutableList.<BuildOptions>of(fromOptions);
Greg Estren66cadd32016-08-05 21:07:02 +0000722 } else if (transition instanceof PatchTransition) {
723 // TODO(bazel-team): safety-check that this never mutates fromOptions.
Greg Estrenb0de9192016-11-16 17:44:16 +0000724 result = ImmutableList.<BuildOptions>of(((PatchTransition) transition).apply(fromOptions));
Greg Estren66cadd32016-08-05 21:07:02 +0000725 } else if (transition instanceof Attribute.SplitTransition) {
726 @SuppressWarnings("unchecked") // Attribute.java doesn't have the BuildOptions symbol.
727 List<BuildOptions> toOptions =
728 ((Attribute.SplitTransition<BuildOptions>) transition).split(fromOptions);
729 if (toOptions.isEmpty()) {
730 // When the split returns an empty list, it's signaling it doesn't apply to this instance.
731 // Check that it's safe to skip the transition and return the original options.
732 Verify.verify(transition.defaultsToSelf());
Greg Estrenb0de9192016-11-16 17:44:16 +0000733 result = ImmutableList.<BuildOptions>of(fromOptions);
Greg Estren66cadd32016-08-05 21:07:02 +0000734 } else {
Greg Estrenb0de9192016-11-16 17:44:16 +0000735 result = toOptions;
Greg Estren66cadd32016-08-05 21:07:02 +0000736 }
737 } else {
738 throw new IllegalStateException(String.format(
739 "unsupported dynamic transition type: %s", transition.getClass().getName()));
740 }
Greg Estren66cadd32016-08-05 21:07:02 +0000741
Greg Estrenb0de9192016-11-16 17:44:16 +0000742 if (!trimResults) {
743 return result;
744 } else {
745 ImmutableList.Builder<BuildOptions> trimmedOptions = ImmutableList.builder();
746 for (BuildOptions toOptions : result) {
747 trimmedOptions.add(toOptions.trim(
748 BuildConfiguration.getOptionsClasses(requiredFragments, ruleClassProvider)));
749 }
750 return trimmedOptions.build();
751 }
752 }
Greg Estren66cadd32016-08-05 21:07:02 +0000753
754 /**
Greg Estren2bc88382016-08-02 21:45:35 +0000755 * Diagnostic helper method for dynamic configurations: checks the config fragments required by
756 * a dep against the fragments in its actual configuration. If any are missing, triggers a
757 * descriptive "missing fragments" error.
758 */
759 private static void checkForMissingFragments(Environment env, TargetAndConfiguration ctgValue,
760 String attribute, Dependency dep,
761 Set<Class<? extends BuildConfiguration.Fragment>> expectedDepFragments)
762 throws DependencyEvaluationException {
763 Set<String> ctgFragmentNames = new HashSet<>();
764 for (BuildConfiguration.Fragment fragment :
765 ctgValue.getConfiguration().getAllFragments().values()) {
766 ctgFragmentNames.add(fragment.getClass().getSimpleName());
767 }
768 Set<String> depFragmentNames = new HashSet<>();
769 for (Class<? extends BuildConfiguration.Fragment> fragmentClass : expectedDepFragments) {
770 depFragmentNames.add(fragmentClass.getSimpleName());
771 }
772 Set<String> missing = Sets.difference(depFragmentNames, ctgFragmentNames);
773 if (!missing.isEmpty()) {
774 String msg = String.format(
775 "%s: dependency %s from attribute \"%s\" is missing required config fragments: %s",
776 ctgValue.getLabel(), dep.getLabel(), attribute, Joiner.on(", ").join(missing));
777 env.getListener().handle(Event.error(msg));
778 throw new DependencyEvaluationException(new InvalidConfigurationException(msg));
779 }
780 }
781
Greg Estrendc388242016-12-07 16:47:02 +0000782 /**
783 * Determines the output ordering of each <attribute, depLabel> ->
784 * [dep<config1>, dep<config2>, ...] collection produced by a split transition.
785 */
786 @VisibleForTesting
787 static final Comparator<Dependency> DYNAMIC_SPLIT_DEP_ORDERING =
788 new Comparator<Dependency>() {
789 @Override
790 public int compare(Dependency d1, Dependency d2) {
791 return d1.getConfiguration().getMnemonic().compareTo(d2.getConfiguration().getMnemonic());
792 }
793 };
794
795 /**
796 * Helper method for {@link #getDynamicConfigurations}: returns a copy of the output deps
797 * using the same key and value ordering as the input deps.
798 *
799 * @param originalDeps the input deps with the ordering to preserve
800 * @param dynamicDeps the unordered output deps
801 * @param attributesAndLabels collection of <attribute, depLabel> pairs guaranteed to match
802 * the ordering of originalDeps.entries(). This is a performance optimization: see
803 * {@link #getDynamicConfigurations#attributesAndLabels} for details.
804 */
805 private static OrderedSetMultimap<Attribute, Dependency> sortDynamicallyConfiguredDeps(
806 OrderedSetMultimap<Attribute, Dependency> originalDeps,
807 Multimap<AttributeAndLabel, Dependency> dynamicDeps,
808 ArrayList<AttributeAndLabel> attributesAndLabels) {
809 Iterator<AttributeAndLabel> iterator = attributesAndLabels.iterator();
810 OrderedSetMultimap<Attribute, Dependency> result = OrderedSetMultimap.create();
811 for (Map.Entry<Attribute, Dependency> depsEntry : originalDeps.entries()) {
812 AttributeAndLabel attrAndLabel = iterator.next();
813 if (depsEntry.getValue().hasStaticConfiguration()) {
814 result.put(attrAndLabel.attribute, depsEntry.getValue());
815 } else {
816 Collection<Dependency> dynamicAttrDeps = dynamicDeps.get(attrAndLabel);
817 Verify.verify(!dynamicAttrDeps.isEmpty());
818 if (dynamicAttrDeps.size() > 1) {
819 List<Dependency> sortedSplitList = new ArrayList<>(dynamicAttrDeps);
820 Collections.sort(sortedSplitList, DYNAMIC_SPLIT_DEP_ORDERING);
821 dynamicAttrDeps = sortedSplitList;
822 }
823 result.putAll(depsEntry.getKey(), dynamicAttrDeps);
824 }
825 }
826 return result;
827 }
Greg Estren2bc88382016-08-02 21:45:35 +0000828
829 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100830 * Merges the each direct dependency configured target with the aspects associated with it.
831 *
832 * <p>Note that the combination of a configured target and its associated aspects are not
833 * represented by a Skyframe node. This is because there can possibly be many different
834 * combinations of aspects for a particular configured target, so it would result in a
835 * combinatiorial explosion of Skyframe nodes.
836 */
Greg Estrend5353252016-08-11 22:13:31 +0000837 private static OrderedSetMultimap<Attribute, ConfiguredTarget> mergeAspects(
838 OrderedSetMultimap<Attribute, Dependency> depValueNames,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100839 Map<SkyKey, ConfiguredTarget> depConfiguredTargetMap,
Dmitry Lomov9b2fc5c2016-11-11 11:18:48 +0000840 OrderedSetMultimap<SkyKey, ConfiguredAspect> depAspectMap)
841 throws DuplicateException {
Greg Estrend5353252016-08-11 22:13:31 +0000842 OrderedSetMultimap<Attribute, ConfiguredTarget> result = OrderedSetMultimap.create();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100843
844 for (Map.Entry<Attribute, Dependency> entry : depValueNames.entries()) {
845 Dependency dep = entry.getValue();
846 SkyKey depKey = TO_KEYS.apply(dep);
847 ConfiguredTarget depConfiguredTarget = depConfiguredTargetMap.get(depKey);
Dmitry Lomovca9bfa42016-11-15 13:22:36 +0000848
Lukacs Berki047b7422015-07-22 08:32:37 +0000849 result.put(entry.getKey(),
Lukacs Berki549bfce2016-04-22 15:29:12 +0000850 MergedConfiguredTarget.of(depConfiguredTarget, depAspectMap.get(depKey)));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100851 }
852
853 return result;
854 }
855
856 /**
857 * Given a list of {@link Dependency} objects, returns a multimap from the {@link SkyKey} of the
Dmitry Lomovb487ac62015-11-09 13:09:12 +0000858 * dependency to the {@link ConfiguredAspect} instances that should be merged into it.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100859 *
860 * <p>Returns null if the required aspects are not computed yet.
861 */
862 @Nullable
Greg Estrend5353252016-08-11 22:13:31 +0000863 private static OrderedSetMultimap<SkyKey, ConfiguredAspect> resolveAspectDependencies(
Dmitry Lomovb487ac62015-11-09 13:09:12 +0000864 Environment env,
865 Map<SkyKey, ConfiguredTarget> configuredTargetMap,
866 Iterable<Dependency> deps,
Marian Loburc62faba2015-09-09 10:08:06 +0000867 NestedSetBuilder<Package> transitivePackages)
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +0000868 throws AspectCreationException, InterruptedException {
Greg Estrend5353252016-08-11 22:13:31 +0000869 OrderedSetMultimap<SkyKey, ConfiguredAspect> result = OrderedSetMultimap.create();
kaipi64e952c2017-05-22 17:12:08 +0200870 OrderedSetMultimap<SkyKey, SkyKey> processedAspects = OrderedSetMultimap.create();
Dmitry Lomove851fe22017-02-14 23:11:23 +0000871 Set<SkyKey> allAspectKeys = new HashSet<>();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100872 for (Dependency dep : deps) {
Dmitry Lomove851fe22017-02-14 23:11:23 +0000873 allAspectKeys.addAll(getAspectKeys(dep).values());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100874 }
875
Ulf Adams84901732016-01-28 15:05:16 +0000876 Map<SkyKey, ValueOrException2<AspectCreationException, NoSuchThingException>> depAspects =
Dmitry Lomove851fe22017-02-14 23:11:23 +0000877 env.getValuesOrThrow(allAspectKeys,
878 AspectCreationException.class, NoSuchThingException.class);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100879
880 for (Dependency dep : deps) {
881 SkyKey depKey = TO_KEYS.apply(dep);
Dmitry Lomove851fe22017-02-14 23:11:23 +0000882 Map<AspectDescriptor, SkyKey> aspectToKeys = getAspectKeys(dep);
883
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100884 ConfiguredTarget depConfiguredTarget = configuredTargetMap.get(depKey);
Dmitry Lomove851fe22017-02-14 23:11:23 +0000885 for (AspectDeps depAspect : dep.getAspects().getVisibleAspects()) {
886 SkyKey aspectKey = aspectToKeys.get(depAspect.getAspect());
kaipi64e952c2017-05-22 17:12:08 +0200887 // Skip if the aspect was already applied to the target (perhaps through different
888 // attributes).
889 if (!processedAspects.put(depKey, aspectKey)) {
890 continue;
891 }
Dmitry Lomove851fe22017-02-14 23:11:23 +0000892
Dmitry Lomovca9bfa42016-11-15 13:22:36 +0000893 AspectValue aspectValue;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100894 try {
Ulf Adams84901732016-01-28 15:05:16 +0000895 // TODO(ulfjack): Catch all thrown AspectCreationException and NoSuchThingException
896 // instances and merge them into a single Exception to get full root cause data.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100897 aspectValue = (AspectValue) depAspects.get(aspectKey).get();
Marian Loburfc567b32015-09-14 08:44:25 +0000898 } catch (NoSuchThingException e) {
Marian Loburfc567b32015-09-14 08:44:25 +0000899 throw new AspectCreationException(
Dmitry Lomovc15ba2e2015-10-30 15:50:01 +0000900 String.format(
901 "Evaluation of aspect %s on %s failed: %s",
Dmitry Lomove851fe22017-02-14 23:11:23 +0000902 depAspect.getAspect().getAspectClass().getName(),
Dmitry Lomovc15ba2e2015-10-30 15:50:01 +0000903 dep.getLabel(),
904 e.toString()));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100905 }
906
907 if (aspectValue == null) {
908 // Dependent aspect has either not been computed yet or is in error.
909 return null;
910 }
Dmitry Lomove8040172016-04-06 14:53:43 +0000911 if (!aspectMatchesConfiguredTarget(depConfiguredTarget, aspectValue.getAspect())) {
912 continue;
913 }
914
Dmitry Lomovb487ac62015-11-09 13:09:12 +0000915 result.put(depKey, aspectValue.getConfiguredAspect());
Marian Loburc62faba2015-09-09 10:08:06 +0000916 transitivePackages.addTransitive(aspectValue.getTransitivePackages());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100917 }
918 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100919 return result;
920 }
921
Dmitry Lomove851fe22017-02-14 23:11:23 +0000922 private static Map<AspectDescriptor, SkyKey> getAspectKeys(Dependency dep) {
923 HashMap<AspectDescriptor, SkyKey> result = new HashMap<>();
924 AspectCollection aspects = dep.getAspects();
925 for (AspectDeps aspectDeps : aspects.getVisibleAspects()) {
926 buildAspectKey(aspectDeps, result, dep);
Dmitry Lomovca9bfa42016-11-15 13:22:36 +0000927 }
Dmitry Lomove851fe22017-02-14 23:11:23 +0000928 return result;
929 }
930
931 private static AspectKey buildAspectKey(AspectDeps aspectDeps,
932 HashMap<AspectDescriptor, SkyKey> result, Dependency dep) {
933 if (result.containsKey(aspectDeps.getAspect())) {
934 return (AspectKey) result.get(aspectDeps.getAspect()).argument();
935 }
936
937 ImmutableList.Builder<AspectKey> dependentAspects = ImmutableList.builder();
938 for (AspectDeps path : aspectDeps.getDependentAspects()) {
939 dependentAspects.add(buildAspectKey(path, result, dep));
940 }
941 AspectKey aspectKey = AspectValue.createAspectKey(
942 dep.getLabel(), dep.getConfiguration(),
943 dependentAspects.build(),
944 aspectDeps.getAspect(),
945 dep.getAspectConfiguration(aspectDeps.getAspect()));
946 result.put(aspectKey.getAspectDescriptor(), aspectKey.getSkyKey());
947 return aspectKey;
Marian Lobur702cad72015-09-02 09:53:58 +0000948 }
949
Dmitry Lomov6cd98972017-03-01 15:44:00 +0000950 static boolean aspectMatchesConfiguredTarget(final ConfiguredTarget dep, Aspect aspect) {
dslomovfa50c3d2017-05-08 08:47:44 -0400951 if (!aspect.getDefinition().applyToFiles() && !(dep.getTarget() instanceof Rule)) {
952 return false;
953 }
Dmitry Lomovb5174c72017-01-10 10:57:17 +0000954 return aspect.getDefinition().getRequiredProviders().isSatisfiedBy(
955 new Predicate<Class<?>>() {
956 @Override
957 public boolean apply(Class<?> provider) {
958 return dep.getProvider(provider.asSubclass(TransitiveInfoProvider.class)) != null;
959 }
960 },
961 new Predicate<SkylarkProviderIdentifier>() {
962 @Override
963 public boolean apply(SkylarkProviderIdentifier skylarkProviderIdentifier) {
964 return dep.get(skylarkProviderIdentifier) != null;
965 }
Rumou Duan6f8393f2016-11-30 16:03:10 +0000966 }
Dmitry Lomovb5174c72017-01-10 10:57:17 +0000967 );
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100968 }
969
970 /**
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +0000971 * Returns the set of {@link ConfigMatchingProvider}s that key the configurable attributes used by
972 * this rule.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100973 *
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +0000974 * <p>>If the configured targets supplying those providers aren't yet resolved by the dependency
975 * resolver, returns null.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100976 */
977 @Nullable
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +0000978 static ImmutableMap<Label, ConfigMatchingProvider> getConfigConditions(
979 Target target,
980 Environment env,
981 SkyframeDependencyResolver resolver,
982 TargetAndConfiguration ctgValue,
Ulf Adams84901732016-01-28 15:05:16 +0000983 NestedSetBuilder<Package> transitivePackages,
984 NestedSetBuilder<Label> transitiveLoadingRootCauses)
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +0000985 throws DependencyEvaluationException, InterruptedException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100986 if (!(target instanceof Rule)) {
Ulf Adams2ac20962016-02-01 13:04:54 +0000987 return NO_CONFIG_CONDITIONS;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100988 }
989
Lukacs Berki7894c182016-05-10 12:07:01 +0000990 Map<Label, ConfigMatchingProvider> configConditions = new LinkedHashMap<>();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100991
992 // Collect the labels of the configured targets we need to resolve.
Greg Estrend5353252016-08-11 22:13:31 +0000993 OrderedSetMultimap<Attribute, Label> configLabelMap = OrderedSetMultimap.create();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100994 RawAttributeMapper attributeMap = RawAttributeMapper.of(((Rule) target));
995 for (Attribute a : ((Rule) target).getAttributes()) {
996 for (Label configLabel : attributeMap.getConfigurabilityKeys(a.getName(), a.getType())) {
Lukacs Berkiffa73ad2015-09-18 11:40:12 +0000997 if (!BuildType.Selector.isReservedLabel(configLabel)) {
Greg Estren974bbd92016-07-27 14:22:41 +0000998 configLabelMap.put(a, target.getLabel().resolveRepositoryRelative(configLabel));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100999 }
1000 }
1001 }
1002 if (configLabelMap.isEmpty()) {
Ulf Adams2ac20962016-02-01 13:04:54 +00001003 return NO_CONFIG_CONDITIONS;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001004 }
1005
1006 // Collect the corresponding Skyframe configured target values. Abort early if they haven't
1007 // been computed yet.
Dmitry Lomovd83af9e2017-02-23 15:44:23 +00001008 Collection<Dependency> configValueNames = null;
1009 try {
1010 configValueNames = resolver.resolveRuleLabels(
1011 ctgValue, configLabelMap, transitiveLoadingRootCauses);
1012 } catch (InconsistentAspectOrderException e) {
1013 throw new DependencyEvaluationException(e);
1014 }
Lukacs Berki7894c182016-05-10 12:07:01 +00001015 if (env.valuesMissing()) {
1016 return null;
1017 }
1018
Greg Estren00049432015-08-25 16:43:47 +00001019
1020 // No need to get new configs from Skyframe - config_setting rules always use the current
1021 // target's config.
1022 // TODO(bazel-team): remove the need for this special transformation. We can probably do this by
1023 // simply passing this through trimConfigurations.
1024 BuildConfiguration targetConfig = ctgValue.getConfiguration();
Greg Estrenb5692bd2016-06-08 21:09:11 +00001025 if (useDynamicConfigurations(targetConfig)) {
Greg Estren00049432015-08-25 16:43:47 +00001026 ImmutableList.Builder<Dependency> staticConfigs = ImmutableList.builder();
1027 for (Dependency dep : configValueNames) {
Michael Staib5e573fd2016-01-27 00:33:29 +00001028 staticConfigs.add(
1029 Dependency.withConfigurationAndAspects(dep.getLabel(), targetConfig, dep.getAspects()));
Greg Estren00049432015-08-25 16:43:47 +00001030 }
1031 configValueNames = staticConfigs.build();
1032 }
1033
Ulf Adams7cb66de2016-01-14 08:46:43 +00001034 Map<SkyKey, ConfiguredTarget> configValues = resolveConfiguredTargetDependencies(
Ulf Adams84901732016-01-28 15:05:16 +00001035 env, configValueNames, transitivePackages, transitiveLoadingRootCauses);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001036 if (configValues == null) {
1037 return null;
1038 }
1039
1040 // Get the configured targets as ConfigMatchingProvider interfaces.
1041 for (Dependency entry : configValueNames) {
1042 ConfiguredTarget value = configValues.get(TO_KEYS.apply(entry));
1043 // The code above guarantees that value is non-null here.
1044 ConfigMatchingProvider provider = value.getProvider(ConfigMatchingProvider.class);
1045 if (provider != null) {
Lukacs Berki7894c182016-05-10 12:07:01 +00001046 configConditions.put(entry.getLabel(), provider);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001047 } else {
1048 // Not a valid provider for configuration conditions.
1049 String message =
1050 entry.getLabel() + " is not a valid configuration key for " + target.getLabel();
1051 env.getListener().handle(Event.error(TargetUtils.getLocationMaybe(target), message));
Ulf Adams25f03d82016-01-25 10:31:46 +00001052 throw new DependencyEvaluationException(new ConfiguredValueCreationException(
1053 message, target.getLabel()));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001054 }
1055 }
1056
Lukacs Berki7894c182016-05-10 12:07:01 +00001057 return ImmutableMap.copyOf(configConditions);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001058 }
1059
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +00001060 /**
1061 * * Resolves the targets referenced in depValueNames and returns their ConfiguredTarget
1062 * instances.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001063 *
1064 * <p>Returns null if not all instances are available yet.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001065 */
1066 @Nullable
1067 private static Map<SkyKey, ConfiguredTarget> resolveConfiguredTargetDependencies(
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +00001068 Environment env,
1069 Collection<Dependency> deps,
1070 NestedSetBuilder<Package> transitivePackages,
1071 NestedSetBuilder<Label> transitiveLoadingRootCauses)
1072 throws DependencyEvaluationException, InterruptedException {
Ulf Adams84901732016-01-28 15:05:16 +00001073 boolean missedValues = env.valuesMissing();
1074 boolean failed = false;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001075 Iterable<SkyKey> depKeys = Iterables.transform(deps, TO_KEYS);
Ulf Adams84901732016-01-28 15:05:16 +00001076 Map<SkyKey, ValueOrException<ConfiguredValueCreationException>> depValuesOrExceptions =
gregcef19fcfe2017-06-02 16:04:07 -04001077 env.getValuesOrThrow(depKeys, ConfiguredValueCreationException.class);
Ulf Adams84901732016-01-28 15:05:16 +00001078 Map<SkyKey, ConfiguredTarget> result =
1079 Maps.newHashMapWithExpectedSize(depValuesOrExceptions.size());
1080 for (Map.Entry<SkyKey, ValueOrException<ConfiguredValueCreationException>> entry
1081 : depValuesOrExceptions.entrySet()) {
Ulf Adams25f03d82016-01-25 10:31:46 +00001082 try {
Ulf Adams84901732016-01-28 15:05:16 +00001083 ConfiguredTargetValue depValue = (ConfiguredTargetValue) entry.getValue().get();
1084 if (depValue == null) {
1085 missedValues = true;
1086 } else {
1087 result.put(entry.getKey(), depValue.getConfiguredTarget());
1088 transitivePackages.addTransitive(depValue.getTransitivePackages());
1089 }
Ulf Adams25f03d82016-01-25 10:31:46 +00001090 } catch (ConfiguredValueCreationException e) {
Ulf Adams84901732016-01-28 15:05:16 +00001091 // TODO(ulfjack): If there is an analysis root cause, we drop all loading root causes.
1092 if (e.getAnalysisRootCause() != null) {
1093 throw new DependencyEvaluationException(e);
1094 }
1095 transitiveLoadingRootCauses.addTransitive(e.loadingRootCauses);
1096 failed = true;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001097 }
1098 }
Ulf Adams84901732016-01-28 15:05:16 +00001099 if (missedValues) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001100 return null;
Ulf Adams84901732016-01-28 15:05:16 +00001101 } else if (failed) {
1102 throw new DependencyEvaluationException(
1103 new ConfiguredValueCreationException(transitiveLoadingRootCauses.build()));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001104 } else {
Ulf Adams7cb66de2016-01-14 08:46:43 +00001105 return result;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001106 }
1107 }
1108
1109
1110 @Override
1111 public String extractTag(SkyKey skyKey) {
1112 return Label.print(((ConfiguredTargetKey) skyKey.argument()).getLabel());
1113 }
1114
1115 @Nullable
1116 private ConfiguredTargetValue createConfiguredTarget(SkyframeBuildView view,
1117 Environment env, Target target, BuildConfiguration configuration,
Greg Estrend5353252016-08-11 22:13:31 +00001118 OrderedSetMultimap<Attribute, ConfiguredTarget> depValueMap,
Lukacs Berki7894c182016-05-10 12:07:01 +00001119 ImmutableMap<Label, ConfigMatchingProvider> configConditions,
Marian Loburc62faba2015-09-09 10:08:06 +00001120 NestedSetBuilder<Package> transitivePackages)
Greg Estren9eb1cf02015-06-26 22:18:35 +00001121 throws ConfiguredTargetFunctionException, InterruptedException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001122 StoredEventHandler events = new StoredEventHandler();
gregcef19fcfe2017-06-02 16:04:07 -04001123 BuildConfiguration ownerConfig =
1124 ConfiguredTargetFactory.getArtifactOwnerConfiguration(env, configuration);
1125 if (env.valuesMissing()) {
1126 return null;
1127 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001128 CachingAnalysisEnvironment analysisEnvironment = view.createAnalysisEnvironment(
1129 new ConfiguredTargetKey(target.getLabel(), ownerConfig), false,
Ulf Adamsbfb76a92015-04-22 20:44:35 +00001130 events, env, configuration);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001131 if (env.valuesMissing()) {
1132 return null;
1133 }
1134
Ulf Adams84901732016-01-28 15:05:16 +00001135 Preconditions.checkNotNull(depValueMap);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001136 ConfiguredTarget configuredTarget = view.createConfiguredTarget(target, configuration,
Greg Estren00049432015-08-25 16:43:47 +00001137 analysisEnvironment, depValueMap, configConditions);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001138
1139 events.replayOn(env.getListener());
1140 if (events.hasErrors()) {
1141 analysisEnvironment.disable(target);
1142 throw new ConfiguredTargetFunctionException(new ConfiguredValueCreationException(
Ulf Adams25f03d82016-01-25 10:31:46 +00001143 "Analysis of target '" + target.getLabel() + "' failed; build aborted",
1144 target.getLabel()));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001145 }
1146 Preconditions.checkState(!analysisEnvironment.hasErrors(),
1147 "Analysis environment hasError() but no errors reported");
1148 if (env.valuesMissing()) {
1149 return null;
1150 }
1151
1152 analysisEnvironment.disable(target);
1153 Preconditions.checkNotNull(configuredTarget, target);
1154
janakr93e3eea2017-03-30 22:09:37 +00001155 GeneratingActions generatingActions;
Ulf Adamsd55d7af2016-01-19 11:03:22 +00001156 // Check for conflicting actions within this configured target (that indicates a bug in the
1157 // rule implementation).
Janak Ramakrishnanb3a6ca72015-03-27 20:07:28 +00001158 try {
Rumou Duan0eb5a0c2016-04-18 19:13:51 +00001159 generatingActions = Actions.filterSharedActionsAndThrowActionConflict(
1160 analysisEnvironment.getRegisteredActions());
Janak Ramakrishnanb3a6ca72015-03-27 20:07:28 +00001161 } catch (ActionConflictException e) {
1162 throw new ConfiguredTargetFunctionException(e);
1163 }
Ulf Adamsd55d7af2016-01-19 11:03:22 +00001164 return new ConfiguredTargetValue(
janakr93e3eea2017-03-30 22:09:37 +00001165 configuredTarget,
1166 generatingActions,
1167 transitivePackages.build(),
1168 removeActionsAfterEvaluation.get());
Janak Ramakrishnanb3a6ca72015-03-27 20:07:28 +00001169 }
1170
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001171 /**
1172 * An exception indicating that there was a problem during the construction of
1173 * a ConfiguredTargetValue.
1174 */
1175 public static final class ConfiguredValueCreationException extends Exception {
Ulf Adams84901732016-01-28 15:05:16 +00001176 private final NestedSet<Label> loadingRootCauses;
Ulf Adams25f03d82016-01-25 10:31:46 +00001177 // TODO(ulfjack): Collect all analysis root causes, not just the first one.
Ulf Adams84901732016-01-28 15:05:16 +00001178 @Nullable private final Label analysisRootCause;
Ulf Adams25f03d82016-01-25 10:31:46 +00001179
1180 public ConfiguredValueCreationException(String message, Label currentTarget) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001181 super(message);
Ulf Adams84901732016-01-28 15:05:16 +00001182 this.loadingRootCauses = NestedSetBuilder.<Label>emptySet(Order.STABLE_ORDER);
Ulf Adams25f03d82016-01-25 10:31:46 +00001183 this.analysisRootCause = Preconditions.checkNotNull(currentTarget);
1184 }
1185
Ulf Adams84901732016-01-28 15:05:16 +00001186 public ConfiguredValueCreationException(String message, NestedSet<Label> rootCauses) {
1187 super(message);
1188 this.loadingRootCauses = rootCauses;
1189 this.analysisRootCause = null;
1190 }
1191
1192 public ConfiguredValueCreationException(NestedSet<Label> rootCauses) {
1193 this("Loading failed", rootCauses);
1194 }
1195
1196 public ConfiguredValueCreationException(String message) {
1197 this(message, NestedSetBuilder.<Label>emptySet(Order.STABLE_ORDER));
1198 }
1199
1200 public NestedSet<Label> getRootCauses() {
1201 return loadingRootCauses;
1202 }
1203
Ulf Adams25f03d82016-01-25 10:31:46 +00001204 public Label getAnalysisRootCause() {
1205 return analysisRootCause;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001206 }
1207 }
1208
1209 /**
1210 * Used to declare all the exception types that can be wrapped in the exception thrown by
1211 * {@link ConfiguredTargetFunction#compute}.
1212 */
1213 public static final class ConfiguredTargetFunctionException extends SkyFunctionException {
Ulf Adamsd55d7af2016-01-19 11:03:22 +00001214 public ConfiguredTargetFunctionException(NoSuchThingException e) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001215 super(e, Transience.PERSISTENT);
1216 }
1217
Ulf Adams25f03d82016-01-25 10:31:46 +00001218 private ConfiguredTargetFunctionException(ConfiguredValueCreationException e) {
1219 super(e, Transience.PERSISTENT);
Ulf Adams3ab82f72015-09-04 12:10:53 +00001220 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001221
Janak Ramakrishnanb3a6ca72015-03-27 20:07:28 +00001222 private ConfiguredTargetFunctionException(ActionConflictException e) {
1223 super(e, Transience.PERSISTENT);
1224 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001225 }
1226}