Skip to content

Commit

Permalink
Adding toolchain provider and function to Skylark.
Browse files Browse the repository at this point in the history
Change-Id: Ied06efd4bc68f604975b1e8e3fc70817a577d563
PiperOrigin-RevId: 152412538
  • Loading branch information
katre authored and hlopko committed Apr 7, 2017
1 parent fc03bf3 commit edbeafe
Show file tree
Hide file tree
Showing 4 changed files with 304 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,20 @@

package com.google.devtools.build.lib.rules.platform;

import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.packages.ClassObjectConstructor;
import com.google.devtools.build.lib.skylarkinterface.Param;
import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
import com.google.devtools.build.lib.skylarkinterface.SkylarkSignature;
import com.google.devtools.build.lib.syntax.BuiltinFunction;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.SkylarkDict;
import com.google.devtools.build.lib.syntax.SkylarkList;
import com.google.devtools.build.lib.syntax.SkylarkSignatureProcessor;
import com.google.devtools.build.lib.syntax.Type.ConversionException;

/** Skylark namespace used to interact with Blaze's platform APIs. */
@SkylarkModule(
Expand Down Expand Up @@ -51,4 +62,75 @@ public ClassObjectConstructor getConstraintSettingInfoConstructor() {
public ClassObjectConstructor getConstraintValueInfoConstructor() {
return ConstraintValueInfo.SKYLARK_CONSTRUCTOR;
}

@SkylarkCallable(
name = ToolchainInfo.SKYLARK_NAME,
doc = "The key used to retrieve the provider containing toolchain data.",
structField = true
)
public ClassObjectConstructor getToolchainInfoConstructor() {
return ToolchainInfo.SKYLARK_CONSTRUCTOR;
}

@SkylarkSignature(
name = "toolchain",
doc =
"<i>(Experimental)</i> "
+ "Returns a toolchain provider that can be configured to provide rule implementations "
+ "access to needed configuration.",
objectType = PlatformCommon.class,
returnType = ToolchainInfo.class,
parameters = {
@Param(name = "self", type = PlatformCommon.class, doc = "the platform_rules instance"),
@Param(
name = "exec_compatible_with",
type = SkylarkList.class,
defaultValue = "[]",
named = true,
positional = false,
doc = "Constraints the platform must fulfill to execute this toolchain."
),
@Param(
name = "target_compatible_with",
type = SkylarkList.class,
defaultValue = "[]",
named = true,
positional = false,
doc = "Constraints fulfilled by the target platform for this toolchain."
),
},
extraKeywords =
@Param(
name = "toolchainData",
doc = "Extra information stored for the consumer of the toolchain."
),
useLocation = true
)
private static final BuiltinFunction createToolchain =
new BuiltinFunction("toolchain") {
@SuppressWarnings("unchecked")
public ToolchainInfo invoke(
PlatformCommon self,
SkylarkList<TransitiveInfoCollection> execCompatibleWith,
SkylarkList<TransitiveInfoCollection> targetCompatibleWith,
SkylarkDict<String, Object> skylarkToolchainData,
Location loc)
throws ConversionException, EvalException {

Iterable<ConstraintValueInfo> execConstraints =
ConstraintValueInfo.fromTargets(execCompatibleWith);
Iterable<ConstraintValueInfo> targetConstraints =
ConstraintValueInfo.fromTargets(targetCompatibleWith);
ImmutableMap<String, Object> toolchainData =
ImmutableMap.copyOf(
SkylarkDict.castSkylarkDictOrNoneToDict(
skylarkToolchainData, String.class, Object.class, "toolchainData"));

return new ToolchainInfo(execConstraints, targetConstraints, toolchainData, loc);
}
};

static {
SkylarkSignatureProcessor.configureSkylarkFunctions(PlatformCommon.class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// 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.rules.platform;

import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.packages.ClassObjectConstructor;
import com.google.devtools.build.lib.packages.NativeClassObjectConstructor;
import com.google.devtools.build.lib.packages.SkylarkClassObject;
import com.google.devtools.build.lib.packages.SkylarkProviderIdentifier;
import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory;
import com.google.devtools.build.lib.util.Preconditions;
import java.util.Map;

/**
* A provider that supplied information about a specific language toolchain, including what platform
* constraints are required for execution and for the target platform.
*/
@SkylarkModule(
name = "ToolchainInfo",
doc = "Provides access to data about a specific toolchain.",
category = SkylarkModuleCategory.PROVIDER
)
@Immutable
public class ToolchainInfo extends SkylarkClassObject implements TransitiveInfoProvider {

/** Name used in Skylark for accessing this provider. */
static final String SKYLARK_NAME = "ToolchainInfo";

/** Skylark constructor and identifier for this provider. */
static final ClassObjectConstructor SKYLARK_CONSTRUCTOR =
new NativeClassObjectConstructor(SKYLARK_NAME) {};

/** Identifier used to retrieve this provider from rules which export it. */
private static final SkylarkProviderIdentifier SKYLARK_IDENTIFIER =
SkylarkProviderIdentifier.forKey(SKYLARK_CONSTRUCTOR.getKey());

private final ImmutableList<ConstraintValueInfo> execConstraints;
private final ImmutableList<ConstraintValueInfo> targetConstraints;

public ToolchainInfo(
Iterable<ConstraintValueInfo> execConstraints,
Iterable<ConstraintValueInfo> targetConstraints,
Map<String, Object> toolchainData,
Location loc) {
this(
ImmutableList.copyOf(execConstraints),
ImmutableList.copyOf(targetConstraints),
toolchainData,
loc);
}

public ToolchainInfo(
ImmutableList<ConstraintValueInfo> execConstraints,
ImmutableList<ConstraintValueInfo> targetConstraints,
Map<String, Object> toolchainData,
Location loc) {
super(
SKYLARK_CONSTRUCTOR,
ImmutableMap.<String, Object>builder()
.put("exec_compatible_with", execConstraints)
.put("target_compatible_with", targetConstraints)
.putAll(toolchainData)
.build(),
loc);

this.execConstraints = execConstraints;
this.targetConstraints = targetConstraints;
}

@SkylarkCallable(
name = "exec_compatible_with",
doc = "The constraints on the execution platforms this toolchain supports.",
structField = true
)
public ImmutableList<ConstraintValueInfo> execConstraints() {
return execConstraints;
}

@SkylarkCallable(
name = "target_compatible_with",
doc = "The constraints on the target platforms this toolchain supports.",
structField = true
)
public ImmutableList<ConstraintValueInfo> targetConstraints() {
return targetConstraints;
}

/** Retrieves and casts the provider from the given target. */
public static ToolchainInfo fromTarget(TransitiveInfoCollection target) {
Object provider = target.get(SKYLARK_IDENTIFIER);
if (provider == null) {
return null;
}
Preconditions.checkState(provider instanceof ToolchainInfo);
return (ToolchainInfo) provider;
}

/** Retrieves and casts the providers from the given targets. */
public static Iterable<ToolchainInfo> fromTargets(
Iterable<? extends TransitiveInfoCollection> targets) {
return Iterables.transform(
targets,
new Function<TransitiveInfoCollection, ToolchainInfo>() {
@Override
public ToolchainInfo apply(TransitiveInfoCollection target) {
return fromTarget(target);
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ java_test(
"//src/main/java/com/google/devtools/build/lib/rules/platform",
"//src/test/java/com/google/devtools/build/lib:analysis_testutil",
"//src/test/java/com/google/devtools/build/lib:packages_testutil",
"//src/test/java/com/google/devtools/build/lib/skylark:testutil",
"//third_party:guava",
"//third_party:junit4",
"//third_party:truth",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// 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.rules.platform;

import static com.google.common.truth.Truth.assertThat;

import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
import com.google.devtools.build.lib.skylark.util.SkylarkTestCase;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/** Tests for {@link PlatformCommon}. */
@RunWith(JUnit4.class)
public class PlatformCommonTest extends SkylarkTestCase {

@Test
public void testCreateToolchain() throws Exception {
scratch.file(
"test/toolchain.bzl",
"def _impl(ctx):",
" return platform_common.toolchain(",
" exec_compatible_with = ctx.attr.exec_compatible_with,",
" target_compatible_with = ctx.attr.target_compatible_with,",
" extra_label = ctx.attr.extra_label,",
" extra_str = ctx.attr.extra_str,",
" )",
"test_toolchain = rule(",
" implementation = _impl,",
" attrs = {",
" 'runs': attr.label_list(allow_files=True),",
" 'exec_compatible_with': attr.label_list(",
" providers = [platform_common.ConstraintValueInfo]),",
" 'target_compatible_with': attr.label_list(",
" providers = [platform_common.ConstraintValueInfo]),",
" 'extra_label': attr.label(),",
" 'extra_str': attr.string(),",
" }",
")");
scratch.file(
"test/BUILD",
"load(':toolchain.bzl', 'test_toolchain')",
"constraint_setting(name = 'os')",
"constraint_value(name = 'linux',",
" constraint_setting = ':os')",
"constraint_value(name = 'mac',",
" constraint_setting = ':os')",
"filegroup(name = 'dep_rule')",
"test_toolchain(",
" name = 'linux_toolchain',",
" exec_compatible_with = [",
" ':linux',",
" ],",
" target_compatible_with = [",
" ':mac',",
" ],",
" extra_label = ':dep_rule',",
" extra_str = 'bar',",
")");
TransitiveInfoCollection toolchainProvider = getConfiguredTarget("//test:linux_toolchain");
assertThat(toolchainProvider).isNotNull();

assertThat((List<?>) toolchainProvider.get("exec_compatible_with"))
.containsExactly(
ConstraintValueInfo.create(
ConstraintSettingInfo.create(makeLabel("//test:os")), makeLabel("//test:linux")));
assertThat((List<?>) toolchainProvider.get("target_compatible_with"))
.containsExactly(
ConstraintValueInfo.create(
ConstraintSettingInfo.create(makeLabel("//test:os")), makeLabel("//test:mac")));

assertThat(((ConfiguredTarget) toolchainProvider.get("extra_label")).getLabel())
.isEqualTo(makeLabel("//test:dep_rule"));
assertThat(toolchainProvider.get("extra_str")).isEqualTo("bar");
}
}

0 comments on commit edbeafe

Please sign in to comment.