private void collectTransitiveClosure( PackageProviderForConfigurations packageProvider, Set<Label> reachableLabels, Label from) throws NoSuchThingException { if (!reachableLabels.add(from)) { return; } Target fromTarget = packageProvider.getTarget(from); if (fromTarget instanceof Rule) { Rule rule = (Rule) fromTarget; if (rule.getRuleClassObject().hasAttr("srcs", BuildType.LABEL_LIST)) { // TODO(bazel-team): refine this. This visits "srcs" reachable under *any* configuration, // not necessarily the configuration actually applied to the rule. We should correlate the // two. However, doing so requires faithfully reflecting the configuration transitions that // might happen as we traverse the dependency chain. // TODO(bazel-team): Why don't we use AbstractAttributeMapper#visitLabels() here? for (List<Label> labelsForConfiguration : AggregatingAttributeMapper.of(rule).visitAttribute("srcs", BuildType.LABEL_LIST)) { for (Label label : labelsForConfiguration) { collectTransitiveClosure( packageProvider, reachableLabels, from.resolveRepositoryRelative(label)); } } } if (rule.getRuleClass().equals("bind")) { Label actual = AggregatingAttributeMapper.of(rule).get("actual", BuildType.LABEL); if (actual != null) { collectTransitiveClosure(packageProvider, reachableLabels, actual); } } } }
@Override @Nullable public BuildConfiguration createConfigurations( ConfigurationFactory configurationFactory, Cache<String, BuildConfiguration> cache, PackageProviderForConfigurations packageProvider, BuildOptions buildOptions, EventHandler eventHandler, boolean performSanityCheck) throws InvalidConfigurationException { // Target configuration BuildConfiguration targetConfiguration = configurationFactory.getConfiguration(packageProvider, buildOptions, false, cache); if (targetConfiguration == null) { return null; } BuildConfiguration dataConfiguration = targetConfiguration; // Host configuration // Note that this passes in the dataConfiguration, not the target // configuration. This is intentional. BuildConfiguration hostConfiguration = getHostConfigurationFromRequest( configurationFactory, packageProvider, dataConfiguration, buildOptions, cache); if (hostConfiguration == null) { return null; } ListMultimap<SplitTransition<?>, BuildConfiguration> splitTransitionsTable = ArrayListMultimap.create(); for (SplitTransition<BuildOptions> transition : buildOptions.getPotentialSplitTransitions()) { List<BuildOptions> splitOptionsList = transition.split(buildOptions); // While it'd be clearer to condition the below on "if (!splitOptionsList.empty())", // IosExtension.ExtensionSplitArchTransition defaults to a single-value split. If we failed // that case then no builds would work, whether or not they're iOS builds (since iOS // configurations are unconditionally loaded). Once we have dynamic configuraiton support // for split transitions, this will all go away. if (splitOptionsList.size() > 1 && targetConfiguration.useDynamicConfigurations()) { throw new InvalidConfigurationException( "dynamic configurations don't yet support split transitions"); } for (BuildOptions splitOptions : splitOptionsList) { BuildConfiguration splitConfig = configurationFactory.getConfiguration(packageProvider, splitOptions, false, cache); splitTransitionsTable.put(transition, splitConfig); } } if (packageProvider.valuesMissing()) { return null; } // Sanity check that the implicit labels are all in the transitive closure of explicit ones. // This also registers all targets in the cache entry and validates them on subsequent requests. Set<Label> reachableLabels = new HashSet<>(); if (performSanityCheck) { // We allow the package provider to be null for testing. for (Map.Entry<String, Label> entry : buildOptions.getAllLabels().entries()) { Label label = entry.getValue(); try { collectTransitiveClosure(packageProvider, reachableLabels, label); } catch (NoSuchThingException e) { eventHandler.handle(Event.error(e.getMessage())); throw new InvalidConfigurationException( String.format("Failed to load required %s target: '%s'", entry.getKey(), label)); } } if (packageProvider.valuesMissing()) { return null; } sanityCheckImplicitLabels(reachableLabels, targetConfiguration); sanityCheckImplicitLabels(reachableLabels, hostConfiguration); } BuildConfiguration result = setupTransitions( targetConfiguration, dataConfiguration, hostConfiguration, splitTransitionsTable); result.reportInvalidOptions(eventHandler); return result; }