diff --git a/site/docs/skylark/macros.md b/site/docs/skylark/macros.md
index e879106bd44500..85048a5cafe111 100644
--- a/site/docs/skylark/macros.md
+++ b/site/docs/skylark/macros.md
@@ -143,6 +143,38 @@ macro), use the function [native.package_name()](lib/native.html#package_name).
Note that `native` can only be used in `.bzl` files, and not in `WORKSPACE` or
`BUILD` files.
+## Label resolution in macros
+
+Since macros are evaluated in the [loading phase](concepts.md#evaluation-model),
+label strings such as `"//foo:bar"` that occur in a macro are interpreted
+relative to the `BUILD` file in which the macro is used rather than relative to
+the `.bzl` file in which it is defined. This behavior is generally undesirable
+for macros that are meant to be used in other repositories, e.g. because they
+are part of a published Starlark ruleset.
+
+To get the same behavior as for Starlark rules, wrap the label strings with the
+[`Label`](lib/Label.html#Label) constructor:
+
+```python
+# @my_ruleset//rules:defs.bzl
+def my_cc_wrapper(name, deps = [], **kwargs):
+ native.cc_library(
+ name = name,
+ deps = deps + select({
+ # Due to the use of Label, this label is resolved within @my_ruleset,
+ # regardless of its site of use.
+ Label("//config:needs_foo"): [
+ # Due to the use of Label, this label will resolve to the correct target
+ # even if the canonical name of @dep_of_my_ruleset should be different
+ # in the main workspace, e.g. due to repo mappings.
+ Label("@dep_of_my_ruleset//tools:foo"),
+ ],
+ "//conditions:default": [],
+ }),
+ **kwargs,
+ )
+```
+
## Debugging
* `bazel query --output=build //my/path:all` will show you how the `BUILD` file
diff --git a/src/main/java/com/google/devtools/build/lib/packages/SelectorList.java b/src/main/java/com/google/devtools/build/lib/packages/SelectorList.java
index 3352cc12b19e4e..1c5d40b0bd1833 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/SelectorList.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/SelectorList.java
@@ -16,6 +16,7 @@
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
+import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.collect.nestedset.Depset;
import java.util.Arrays;
import java.util.List;
@@ -84,9 +85,9 @@ public static Object select(Dict, ?> dict, String noMatchError) throws EvalExc
+ " to match");
}
for (Object key : dict.keySet()) {
- if (!(key instanceof String)) {
+ if (!(key instanceof String || key instanceof Label)) {
throw Starlark.errorf(
- "select: got %s for dict key, want a label string", Starlark.type(key));
+ "select: got %s for dict key, want a Label or a label string", Starlark.type(key));
}
}
return SelectorList.of(new SelectorValue(dict, noMatchError));
diff --git a/src/main/java/com/google/devtools/build/lib/packages/StarlarkLibrary.java b/src/main/java/com/google/devtools/build/lib/packages/StarlarkLibrary.java
index 75bf5538a31545..6c9025e81923b9 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/StarlarkLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/StarlarkLibrary.java
@@ -330,8 +330,10 @@ public Depset depset(
name = "x",
positional = true,
doc =
- "A dict that maps configuration conditions to values. Each key is a label string"
- + " that identifies a config_setting instance."),
+ "A dict that maps configuration conditions to values. Each key is a "
+ + "Label or a label string"
+ + " that identifies a config_setting, constraint_setting, or constraint_value"
+ + " instance."),
@Param(
name = "no_match_error",
defaultValue = "''",
diff --git a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/StarlarkRuleFunctionsApi.java b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/StarlarkRuleFunctionsApi.java
index 5af218fe924b36..2fc5d6cf043d2a 100644
--- a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/StarlarkRuleFunctionsApi.java
+++ b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/StarlarkRuleFunctionsApi.java
@@ -579,10 +579,11 @@ StarlarkAspectApi aspect(
@StarlarkMethod(
name = "Label",
doc =
- "Creates a Label referring to a BUILD target. Use this function only when you want to"
- + " give a default value for the label attributes. The argument must refer to an"
- + " absolute label. The repo part of the label (or its absence) is interpreted in the"
- + " context of the repo where this Label() call appears. Example:
Label(\"//tools:default\")", parameters = { @Param(name = "label_string", doc = "the label string."), diff --git a/src/test/java/com/google/devtools/build/lib/analysis/ConfigurableAttributesTest.java b/src/test/java/com/google/devtools/build/lib/analysis/ConfigurableAttributesTest.java index 264c3e166449cf..dd42fbe601ab45 100644 --- a/src/test/java/com/google/devtools/build/lib/analysis/ConfigurableAttributesTest.java +++ b/src/test/java/com/google/devtools/build/lib/analysis/ConfigurableAttributesTest.java @@ -1569,4 +1569,39 @@ public void publicVisibilityConfigSetting_defaultIsPrivate() throws Exception { assertThat(getConfiguredTarget("//a:binary")).isNotNull(); assertNoEvents(); } + + @Test + public void selectWithLabelKeys() throws Exception { + writeConfigRules(); + scratch.file("java/foo/BUILD", + "java_binary(", + " name = 'binary',", + " srcs = ['binary.java'],", + " deps = select({", + " Label('//conditions:a'): [':a'],", + " '//conditions:b': [':b'],", + " }) + select({", + " '//conditions:a': [':a2'],", + " Label('//conditions:b'): [':b2'],", + " })", + ")", + "java_library(", + " name = 'a',", + " srcs = ['a.java'])", + "java_library(", + " name = 'b',", + " srcs = ['b.java'])", + "java_library(", + " name = 'a2',", + " srcs = ['a2.java'])", + "java_library(", + " name = 'b2',", + " srcs = ['b2.java'])"); + + checkRule( + "//java/foo:binary", + "--foo=b", + /*expected:*/ ImmutableList.of("bin java/foo/libb.jar", "bin java/foo/libb2.jar"), + /*not expected:*/ ImmutableList.of("bin java/foo/liba.jar", "bin java/foo/liba2.jar")); + } }