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 13, 2017
1 parent 5f72b24 commit 04d0693
Show file tree
Hide file tree
Showing 5 changed files with 191 additions and 28 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
Expand Up @@ -14,7 +14,9 @@

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 @@ -63,25 +65,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
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
/** Utility methods for setting up platform and toolchain related tests. */
public abstract class ToolchainTestCase extends SkylarkTestCase {

public PlatformInfo targetPlatform;
public PlatformInfo hostPlatform;
public PlatformInfo linuxPlatform;
public PlatformInfo macPlatform;

public ConstraintSettingInfo setting;
public ConstraintValueInfo linuxConstraint;
Expand All @@ -46,19 +46,22 @@ public void createConstraints() throws Exception {
setting = ConstraintSettingInfo.create(makeLabel("//constraint:os"));
linuxConstraint = ConstraintValueInfo.create(setting, makeLabel("//constraint:linux"));
macConstraint = ConstraintValueInfo.create(setting, makeLabel("//constraint:mac"));
}

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

@Before
public void createToolchains() throws Exception {
rewriteWorkspace(
"register_toolchains(", " '//toolchain:toolchain_1',", " '//toolchain:toolchain_2')");
rewriteWorkspace("register_toolchains('//toolchain:toolchain_1', '//toolchain:toolchain_2')");

scratch.file(
"toolchain/BUILD",
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 @@ -17,7 +17,15 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.devtools.build.skyframe.EvaluationResultSubjectFactory.assertThatEvaluationResult;

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.cmdline.Label;
import com.google.devtools.build.lib.rules.platform.ToolchainTestCase;
import com.google.devtools.build.lib.skyframe.util.SkyframeExecutorTestUtils;
import com.google.devtools.build.skyframe.EvaluationResult;
Expand All @@ -32,6 +40,7 @@ public class ToolchainResolutionFunctionTest extends ToolchainTestCase {

private EvaluationResult<ToolchainResolutionValue> invokeToolchainResolution(SkyKey key)
throws InterruptedException {

try {
getSkyframeExecutor().getSkyframeBuildView().enableAnalysis(true);
return SkyframeExecutorTestUtils.evaluate(
Expand All @@ -41,19 +50,17 @@ private EvaluationResult<ToolchainResolutionValue> invokeToolchainResolution(Sky
}
}

// 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, testToolchainType, targetPlatform, hostPlatform);
ToolchainResolutionValue.key(targetConfig, testToolchainType, linuxPlatform, macPlatform);
EvaluationResult<ToolchainResolutionValue> result = invokeToolchainResolution(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 @@ -62,7 +69,7 @@ public void testResolution_noneFound() throws Exception {
rewriteWorkspace();

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

assertThatEvaluationResult(result)
Expand All @@ -72,6 +79,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 04d0693

Please sign in to comment.