aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/skyframe/ToolchainUtil.java
diff options
context:
space:
mode:
authorGravatar John Cater <jcater@google.com>2017-07-20 19:43:20 +0200
committerGravatar Klaus Aehlig <aehlig@google.com>2017-07-21 09:14:45 +0200
commit2e56f0664d91fce3974938198d8a30e1aeef8d62 (patch)
treea3e05e61f632804e162f8c626e5e656d00905cba /src/main/java/com/google/devtools/build/lib/skyframe/ToolchainUtil.java
parent520bbbc5ff375d3c4aebe09ee51442dd5511e7b8 (diff)
Use toolchain resolution in rule creation.
Part of #2219. Change-Id: Id4929d5ddcd57b4635af5e513eb9a09f16a78e71 PiperOrigin-RevId: 162634398
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/skyframe/ToolchainUtil.java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/ToolchainUtil.java220
1 files changed, 220 insertions, 0 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ToolchainUtil.java b/src/main/java/com/google/devtools/build/lib/skyframe/ToolchainUtil.java
new file mode 100644
index 0000000000..3afe90af6c
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ToolchainUtil.java
@@ -0,0 +1,220 @@
+// Copyright 2017 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.skyframe;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableBiMap;
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.analysis.ConfiguredTarget;
+import com.google.devtools.build.lib.analysis.PlatformConfiguration;
+import com.google.devtools.build.lib.analysis.ToolchainContext;
+import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.analysis.platform.PlatformInfo;
+import com.google.devtools.build.lib.analysis.platform.PlatformProviderUtils;
+import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.skyframe.ConfiguredTargetFunction.ConfiguredValueCreationException;
+import com.google.devtools.build.lib.skyframe.RegisteredToolchainsFunction.InvalidTargetException;
+import com.google.devtools.build.lib.skyframe.ToolchainResolutionFunction.NoToolchainFoundException;
+import com.google.devtools.build.lib.skyframe.ToolchainResolutionValue.ToolchainResolutionKey;
+import com.google.devtools.build.lib.syntax.EvalException;
+import com.google.devtools.build.skyframe.LegacySkyKey;
+import com.google.devtools.build.skyframe.SkyFunction.Environment;
+import com.google.devtools.build.skyframe.SkyKey;
+import com.google.devtools.build.skyframe.ValueOrException;
+import com.google.devtools.build.skyframe.ValueOrException4;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Common code to create a {@link ToolchainContext} given a set of required toolchain type labels.
+ */
+public class ToolchainUtil {
+
+ /**
+ * Returns a new {@link ToolchainContext}, with the correct toolchain labels based on the results
+ * of the {@link ToolchainResolutionFunction}.
+ */
+ public static ToolchainContext createToolchainContext(
+ Environment env, List<Label> requiredToolchains, BuildConfiguration configuration)
+ throws ToolchainContextException, InterruptedException {
+ ImmutableBiMap<Label, Label> resolvedLabels =
+ resolveToolchainLabels(env, requiredToolchains, configuration);
+ ToolchainContext toolchainContext = ToolchainContext.create(requiredToolchains, resolvedLabels);
+ return toolchainContext;
+ }
+
+ /**
+ * Data class to hold platform descriptors loaded based on the current {@link BuildConfiguration}.
+ */
+ @AutoValue
+ protected abstract static class PlatformDescriptors {
+ abstract PlatformInfo execPlatform();
+
+ abstract PlatformInfo targetPlatform();
+
+ protected static PlatformDescriptors create(
+ PlatformInfo execPlatform, PlatformInfo targetPlatform) {
+ return new AutoValue_ToolchainUtil_PlatformDescriptors(execPlatform, targetPlatform);
+ }
+ }
+
+ private static PlatformDescriptors loadPlatformDescriptors(
+ Environment env, BuildConfiguration configuration)
+ throws InterruptedException, ToolchainContextException {
+ PlatformConfiguration platformConfiguration =
+ configuration.getFragment(PlatformConfiguration.class);
+ Label executionPlatformLabel = platformConfiguration.getExecutionPlatform();
+ Label targetPlatformLabel = platformConfiguration.getTargetPlatforms().get(0);
+
+ SkyKey executionPlatformKey =
+ LegacySkyKey.create(
+ SkyFunctions.CONFIGURED_TARGET,
+ new ConfiguredTargetKey(executionPlatformLabel, configuration));
+ SkyKey targetPlatformKey =
+ LegacySkyKey.create(
+ SkyFunctions.CONFIGURED_TARGET,
+ new ConfiguredTargetKey(targetPlatformLabel, configuration));
+
+ Map<SkyKey, ValueOrException<ConfiguredValueCreationException>> values =
+ env.getValuesOrThrow(
+ ImmutableList.of(executionPlatformKey, targetPlatformKey),
+ ConfiguredValueCreationException.class);
+ if (env.valuesMissing()) {
+ return null;
+ }
+ try {
+ ConfiguredTarget executionPlatformTarget =
+ ((ConfiguredTargetValue) values.get(executionPlatformKey).get()).getConfiguredTarget();
+ ConfiguredTarget targetPlatformTarget =
+ ((ConfiguredTargetValue) values.get(targetPlatformKey).get()).getConfiguredTarget();
+ PlatformInfo execPlatform = PlatformProviderUtils.platform(executionPlatformTarget);
+ PlatformInfo targetPlatform = PlatformProviderUtils.platform(targetPlatformTarget);
+
+ return PlatformDescriptors.create(execPlatform, targetPlatform);
+ } catch (ConfiguredValueCreationException e) {
+ throw new ToolchainContextException(e);
+ }
+ }
+
+ private static ImmutableBiMap<Label, Label> resolveToolchainLabels(
+ Environment env, List<Label> requiredToolchains, BuildConfiguration configuration)
+ throws InterruptedException, ToolchainContextException {
+
+ // If there are no required toolchains, bail out early.
+ if (requiredToolchains.isEmpty()) {
+ return ImmutableBiMap.of();
+ }
+
+ // Load the execution and target platforms for the current configuration.
+ PlatformDescriptors platforms = loadPlatformDescriptors(env, configuration);
+ if (platforms == null) {
+ return null;
+ }
+
+ // Find the toolchains for the required toolchain types.
+ List<SkyKey> registeredToolchainKeys = new ArrayList<>();
+ for (Label toolchainType : requiredToolchains) {
+ registeredToolchainKeys.add(
+ ToolchainResolutionValue.key(
+ configuration, toolchainType, platforms.targetPlatform(), platforms.execPlatform()));
+ }
+
+ Map<
+ SkyKey,
+ ValueOrException4<
+ NoToolchainFoundException, ConfiguredValueCreationException, InvalidTargetException,
+ EvalException>>
+ results =
+ env.getValuesOrThrow(
+ registeredToolchainKeys,
+ NoToolchainFoundException.class,
+ ConfiguredValueCreationException.class,
+ InvalidTargetException.class,
+ EvalException.class);
+ if (env.valuesMissing()) {
+ return null;
+ }
+
+ // Load the toolchains.
+ ImmutableBiMap.Builder<Label, Label> builder = new ImmutableBiMap.Builder<>();
+ List<Label> missingToolchains = new ArrayList<>();
+ for (Map.Entry<
+ SkyKey,
+ ValueOrException4<
+ NoToolchainFoundException, ConfiguredValueCreationException, InvalidTargetException,
+ EvalException>>
+ entry : results.entrySet()) {
+ try {
+ Label requiredToolchainType =
+ ((ToolchainResolutionKey) entry.getKey().argument()).toolchainType();
+ Label toolchainLabel = ((ToolchainResolutionValue) entry.getValue().get()).toolchainLabel();
+ builder.put(requiredToolchainType, toolchainLabel);
+ } catch (NoToolchainFoundException e) {
+ // Save the missing type and continue looping to check for more.
+ missingToolchains.add(e.missingToolchainType());
+ } catch (ConfiguredValueCreationException e) {
+ throw new ToolchainContextException(e);
+ } catch (InvalidTargetException e) {
+ throw new ToolchainContextException(e);
+ } catch (EvalException e) {
+ throw new ToolchainContextException(e);
+ }
+ }
+
+ if (!missingToolchains.isEmpty()) {
+ throw new ToolchainContextException(new UnresolvedToolchainsException(missingToolchains));
+ }
+
+ return builder.build();
+ }
+
+ /** Exception used when a toolchain type is required but no matching toolchain is found. */
+ public static final class UnresolvedToolchainsException extends Exception {
+ private final ImmutableList<Label> missingToolchainTypes;
+
+ public UnresolvedToolchainsException(List<Label> missingToolchainTypes) {
+ super(
+ String.format(
+ "no matching toolchains found for types %s",
+ Joiner.on(", ").join(missingToolchainTypes)));
+ this.missingToolchainTypes = ImmutableList.copyOf(missingToolchainTypes);
+ }
+
+ public ImmutableList<Label> missingToolchainTypes() {
+ return missingToolchainTypes;
+ }
+ }
+
+ /** Exception used to wrap exceptions during toolchain resolution. */
+ public static class ToolchainContextException extends Exception {
+ public ToolchainContextException(UnresolvedToolchainsException e) {
+ super(e);
+ }
+
+ public ToolchainContextException(ConfiguredValueCreationException e) {
+ super(e);
+ }
+
+ public ToolchainContextException(InvalidTargetException e) {
+ super(e);
+ }
+
+ public ToolchainContextException(EvalException e) {
+ super(e);
+ }
+ }
+}