Skip to content

Commit

Permalink
Implement toolchain resolution via constraint checks.
Browse files Browse the repository at this point in the history
Part of bazelbuild#2219.

Change-Id: I5777e9b6cafbb7586cbbfb5b300344fd4417513d
  • Loading branch information
katre committed Jul 11, 2017
1 parent fe6f923 commit 412e598
Show file tree
Hide file tree
Showing 4 changed files with 189 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;

/** Provider for a platform, which is a group of constraints and values. */
@SkylarkModule(
Expand Down Expand Up @@ -90,7 +91,7 @@ protected PlatformInfo createInstanceFromSkylark(Object[] args, Location loc)
};

private final Label label;
private final ImmutableList<ConstraintValueInfo> constraints;
private final ImmutableMap<ConstraintSettingInfo, ConstraintValueInfo> constraints;
private final ImmutableMap<String, String> remoteExecutionProperties;

private PlatformInfo(
Expand All @@ -106,8 +107,14 @@ private PlatformInfo(
location);

this.label = label;
this.constraints = constraints;
this.remoteExecutionProperties = remoteExecutionProperties;

ImmutableMap.Builder<ConstraintSettingInfo, ConstraintValueInfo> constraintsBuilder =
new ImmutableMap.Builder<>();
for (ConstraintValueInfo constraint : constraints) {
constraintsBuilder.put(constraint.constraint(), constraint);
}
this.constraints = constraintsBuilder.build();
}

@SkylarkCallable(
Expand All @@ -126,8 +133,17 @@ public Label label() {
+ "this platform.",
structField = true
)
public ImmutableList<ConstraintValueInfo> constraints() {
return constraints;
public Iterable<ConstraintValueInfo> constraints() {
return constraints.values();
}

/**
* Returns the {@link ConstraintValueInfo} for the given {@link ConstraintSettingInfo}, or {@code
* null} if none exists.
*/
@Nullable
public ConstraintValueInfo getConstraint(ConstraintSettingInfo constraint) {
return constraints.get(constraint);
}

@SkylarkCallable(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.google.devtools.build.lib.skyframe;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.analysis.platform.ConstraintValueInfo;
import com.google.devtools.build.lib.analysis.platform.DeclaredToolchainInfo;
import com.google.devtools.build.lib.analysis.platform.PlatformInfo;
import com.google.devtools.build.lib.cmdline.Label;
Expand Down Expand Up @@ -50,25 +52,55 @@ public SkyValue compute(SkyKey skyKey, Environment env)
DeclaredToolchainInfo toolchain =
resolveConstraints(
key.toolchainType(),
key.targetPlatform(),
key.execPlatform(),
key.targetPlatform(),
toolchains.registeredToolchains());

if (toolchain == null) {
throw new ToolchainResolutionFunctionException(
new NoToolchainFoundException(key.toolchainType()));
}
return ToolchainResolutionValue.create(toolchain.toolchainLabel());
}

// TODO(katre): Implement real resolution.
private DeclaredToolchainInfo resolveConstraints(
@VisibleForTesting
static DeclaredToolchainInfo resolveConstraints(
Label toolchainType,
PlatformInfo targetPlatform,
PlatformInfo execPlatform,
ImmutableList<DeclaredToolchainInfo> toolchains)
throws ToolchainResolutionFunctionException {
PlatformInfo targetPlatform,
ImmutableList<DeclaredToolchainInfo> toolchains) {
for (DeclaredToolchainInfo toolchain : toolchains) {
if (toolchain.toolchainType().equals(toolchainType)) {
return toolchain;
// Make sure the type matches.
if (!toolchain.toolchainType().equals(toolchainType)) {
continue;
}
if (!checkConstraints(toolchain.execConstraints(), execPlatform)) {
continue;
}
if (!checkConstraints(toolchain.targetConstraints(), targetPlatform)) {
continue;
}

return toolchain;
}

return null;
}

/**
* Returns {@code true} iff all constraints set by the toolchain are present in the {@link
* PlatformInfo}.
*/
private static boolean checkConstraints(
Iterable<ConstraintValueInfo> toolchainConstraints, PlatformInfo platform) {

for (ConstraintValueInfo constraint : toolchainConstraints) {
ConstraintValueInfo found = platform.getConstraint(constraint.constraint());
if (!constraint.equals(found)) {
return false;
}
}
throw new ToolchainResolutionFunctionException(new NoToolchainFoundException(toolchainType));
return true;
}

@Nullable
Expand Down
1 change: 1 addition & 0 deletions src/test/java/com/google/devtools/build/lib/skyframe/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ java_test(
"//src/main/java/com/google/devtools/build/lib:vfs",
"//src/main/java/com/google/devtools/build/lib/actions",
"//src/main/java/com/google/devtools/build/lib/analysis/platform",
"//src/main/java/com/google/devtools/build/lib/analysis/platform:utils",
"//src/main/java/com/google/devtools/build/lib/cmdline",
"//src/main/java/com/google/devtools/build/lib/rules/cpp",
"//src/main/java/com/google/devtools/build/lib/rules/platform",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,13 @@

import com.google.common.collect.ImmutableList;
import com.google.common.testing.EqualsTester;
import com.google.common.truth.DefaultSubject;
import com.google.common.truth.Subject;
import com.google.devtools.build.lib.analysis.platform.ConstraintSettingInfo;
import com.google.devtools.build.lib.analysis.platform.ConstraintValueInfo;
import com.google.devtools.build.lib.analysis.platform.DeclaredToolchainInfo;
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.util.SkyframeExecutorTestUtils;
import com.google.devtools.build.lib.skylark.util.SkylarkTestCase;
Expand All @@ -35,15 +41,8 @@ public class ToolchainResolutionFunctionTest extends SkylarkTestCase {

private Label toolchainType;

private PlatformInfo targetPlatform;
private PlatformInfo hostPlatform;

@Before
public void createPlatforms() throws Exception {
targetPlatform =
PlatformInfo.builder().setLabel(makeLabel("//platforms:target_platform")).build();
hostPlatform = PlatformInfo.builder().setLabel(makeLabel("//platforms:host_platform")).build();
}
private PlatformInfo linuxPlatform;
private PlatformInfo macPlatform;

private void rewriteWorkspace(String... lines) throws Exception {
scratch.overwriteFile(
Expand Down Expand Up @@ -72,6 +71,14 @@ public void createToolchains() throws Exception {
" constraint_setting = ':os')",
"constraint_value(name = 'mac',",
" constraint_setting = ':os')");

scratch.file(
"platform/BUILD",
"platform(name = 'mac_platform',",
" constraint_values = ['//constraint:mac'])",
"platform(name = 'linux_platform',",
" constraint_values = ['//constraint:linux'])");

scratch.file(
"toolchain/BUILD",
"load(':toolchain_def.bzl', 'test_toolchain')",
Expand All @@ -94,6 +101,7 @@ public void createToolchains() throws Exception {
"test_toolchain(",
" name='test_toolchain_2',",
" data = 'bar')");

scratch.file(
"toolchain/toolchain_def.bzl",
"def _impl(ctx):",
Expand All @@ -110,6 +118,9 @@ public void createToolchains() throws Exception {
getSkyframeExecutor().injectWorkspaceStatusData("test");

toolchainType = makeLabel("//toolchain:test_toolchain");
linuxPlatform =
PlatformProviderUtils.platform(getConfiguredTarget("//platform:linux_platform"));
macPlatform = PlatformProviderUtils.platform(getConfiguredTarget("//platform:mac_platform"));
}

private EvaluationResult<ToolchainResolutionValue> eval(SkyKey key) throws InterruptedException {
Expand All @@ -122,20 +133,18 @@ private EvaluationResult<ToolchainResolutionValue> eval(SkyKey key) throws Inter
}
}

// TODO(katre): Current toolchain resolution does not actually check the constraints, it just
// returns the first toolchain available.
@Test
public void testResolution() throws Exception {

SkyKey key =
ToolchainResolutionValue.key(targetConfig, toolchainType, targetPlatform, hostPlatform);
ToolchainResolutionValue.key(targetConfig, toolchainType, linuxPlatform, macPlatform);
EvaluationResult<ToolchainResolutionValue> result = eval(key);

assertThatEvaluationResult(result).hasNoError();

ToolchainResolutionValue toolchainResolutionValue = result.get(key);
assertThat(toolchainResolutionValue.toolchainLabel())
.isEqualTo(makeLabel("//toolchain:test_toolchain_1"));
.isEqualTo(makeLabel("//toolchain:test_toolchain_2"));
}

@Test
Expand All @@ -144,7 +153,7 @@ public void testResolution_noneFound() throws Exception {
rewriteWorkspace();

SkyKey key =
ToolchainResolutionValue.key(targetConfig, toolchainType, targetPlatform, hostPlatform);
ToolchainResolutionValue.key(targetConfig, toolchainType, linuxPlatform, macPlatform);
EvaluationResult<ToolchainResolutionValue> result = eval(key);

assertThatEvaluationResult(result)
Expand All @@ -154,6 +163,110 @@ public void testResolution_noneFound() throws Exception {
.contains("no matching toolchain found for //toolchain:test_toolchain");
}

@Test
public void testResolveConstraints() throws Exception {
ConstraintSettingInfo setting1 =
ConstraintSettingInfo.create(makeLabel("//constraint:setting1"));
ConstraintSettingInfo setting2 =
ConstraintSettingInfo.create(makeLabel("//constraint:setting2"));
ConstraintValueInfo constraint1a =
ConstraintValueInfo.create(setting1, makeLabel("//constraint:value1a"));
ConstraintValueInfo constraint1b =
ConstraintValueInfo.create(setting1, makeLabel("//constraint:value1b"));
ConstraintValueInfo constraint2a =
ConstraintValueInfo.create(setting2, makeLabel("//constraint:value2a"));
ConstraintValueInfo constraint2b =
ConstraintValueInfo.create(setting2, makeLabel("//constraint:value2b"));

Label toolchainType1 = makeLabel("//toolchain:type1");
Label toolchainType2 = makeLabel("//toolchain:type2");

DeclaredToolchainInfo toolchain1a =
DeclaredToolchainInfo.create(
toolchainType1,
ImmutableList.of(constraint1a, constraint2a),
ImmutableList.of(constraint1a, constraint2a),
makeLabel("//toolchain:toolchain1a"));
DeclaredToolchainInfo toolchain1b =
DeclaredToolchainInfo.create(
toolchainType1,
ImmutableList.of(constraint1a, constraint2b),
ImmutableList.of(constraint1a, constraint2b),
makeLabel("//toolchain:toolchain1b"));
DeclaredToolchainInfo toolchain2a =
DeclaredToolchainInfo.create(
toolchainType2,
ImmutableList.of(constraint1b, constraint2a),
ImmutableList.of(constraint1b, constraint2a),
makeLabel("//toolchain:toolchain2a"));
DeclaredToolchainInfo toolchain2b =
DeclaredToolchainInfo.create(
toolchainType2,
ImmutableList.of(constraint1b, constraint2b),
ImmutableList.of(constraint1b, constraint2b),
makeLabel("//toolchain:toolchain2b"));

ImmutableList<DeclaredToolchainInfo> allToolchains =
ImmutableList.of(toolchain1a, toolchain1b, toolchain2a, toolchain2b);

assertToolchainResolution(
toolchainType1,
ImmutableList.of(constraint1a, constraint2a),
ImmutableList.of(constraint1a, constraint2a),
allToolchains)
.isEqualTo(toolchain1a);
assertToolchainResolution(
toolchainType1,
ImmutableList.of(constraint1a, constraint2b),
ImmutableList.of(constraint1a, constraint2b),
allToolchains)
.isEqualTo(toolchain1b);
assertToolchainResolution(
toolchainType2,
ImmutableList.of(constraint1b, constraint2a),
ImmutableList.of(constraint1b, constraint2a),
allToolchains)
.isEqualTo(toolchain2a);
assertToolchainResolution(
toolchainType2,
ImmutableList.of(constraint1b, constraint2b),
ImmutableList.of(constraint1b, constraint2b),
allToolchains)
.isEqualTo(toolchain2b);

// No toolchains of type.
assertToolchainResolution(
makeLabel("//toolchain:type3"),
ImmutableList.of(constraint1a, constraint2a),
ImmutableList.of(constraint1a, constraint2a),
allToolchains)
.isNull();
}

private Subject<DefaultSubject, Object> assertToolchainResolution(
Label toolchainType,
Iterable<ConstraintValueInfo> targetConstraints,
Iterable<ConstraintValueInfo> execConstraints,
ImmutableList<DeclaredToolchainInfo> toolchains)
throws Exception {

PlatformInfo execPlatform =
PlatformInfo.builder()
.setLabel(makeLabel("//platform:exec"))
.addConstraints(execConstraints)
.build();
PlatformInfo targetPlatform =
PlatformInfo.builder()
.setLabel(makeLabel("//platform:target"))
.addConstraints(targetConstraints)
.build();

DeclaredToolchainInfo resolvedToolchain =
ToolchainResolutionFunction.resolveConstraints(
toolchainType, execPlatform, targetPlatform, toolchains);
return assertThat(resolvedToolchain);
}

@Test
public void testToolchainResolutionValue_equalsAndHashCode() {
new EqualsTester()
Expand Down

0 comments on commit 412e598

Please sign in to comment.