diff options
author | 2017-07-20 19:43:20 +0200 | |
---|---|---|
committer | 2017-07-21 09:14:45 +0200 | |
commit | 2e56f0664d91fce3974938198d8a30e1aeef8d62 (patch) | |
tree | a3e05e61f632804e162f8c626e5e656d00905cba /src/main/java/com/google/devtools/build/lib/skyframe/ToolchainUtil.java | |
parent | 520bbbc5ff375d3c4aebe09ee51442dd5511e7b8 (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.java | 220 |
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); + } + } +} |