Add RULEDIR to genrule's cmd
###Description of the problem / feature request:
Add new Make variable to genrule's cmd which always points to the output directory containing output from running genrule. See #7248 for details.
Closes #7249.
RELNOTES[NEW]: genrules now support a $(RULEDIR) variable that resolves to the directory where the outputs of the rule are put.
PiperOrigin-RevId: 236612681
diff --git a/src/main/java/com/google/devtools/build/lib/rules/genrule/GenRuleBase.java b/src/main/java/com/google/devtools/build/lib/rules/genrule/GenRuleBase.java
index 7228f4b..2b2ab5c 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/genrule/GenRuleBase.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/genrule/GenRuleBase.java
@@ -309,6 +309,15 @@
return expandSingletonArtifact(filesToBuild, "$@", "output file");
}
+ if (variableName.equals("RULEDIR")) {
+ // The output root directory. This variable expands to the package's root directory
+ // in the genfiles tree.
+ PathFragment dir = ruleContext.getBinOrGenfilesDirectory().getExecPath();
+ PathFragment relPath =
+ ruleContext.getRule().getLabel().getPackageIdentifier().getSourceRoot();
+ return dir.getRelative(relPath).getPathString();
+ }
+
if (variableName.equals("@D")) {
// The output directory. If there is only one filename in outs,
// this expands to the directory containing that file. If there are
diff --git a/src/main/java/com/google/devtools/build/lib/rules/genrule/GenRuleBaseRule.java b/src/main/java/com/google/devtools/build/lib/rules/genrule/GenRuleBaseRule.java
index c0287c3..3534938 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/genrule/GenRuleBaseRule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/genrule/GenRuleBaseRule.java
@@ -131,9 +131,10 @@
list, not in <code>srcs</code>, to ensure they are built in the correct configuration.
</p>
<!-- #END_BLAZE_RULE.ATTRIBUTE --> */
- .add(attr("tools", LABEL_LIST)
- .cfg(HostTransition.INSTANCE)
- .allowedFileTypes(FileTypeSet.ANY_FILE))
+ .add(
+ attr("tools", LABEL_LIST)
+ .cfg(HostTransition.INSTANCE)
+ .allowedFileTypes(FileTypeSet.ANY_FILE))
/* <!-- #BLAZE_RULE(genrule).ATTRIBUTE(outs) -->
A list of files generated by this rule.
<p>
@@ -161,8 +162,8 @@
<p>
Note that <code>outs</code> are <i>not</i> included in this substitution. Output files
are always generated into a predictable location (available via <code>$(@D)</code>,
- <code>$@</code>, <code>$(OUTS)</code> or <code>$(location <i>output_name</i>)</code>;
- see below).
+ <code>$@</code>, <code>$(OUTS)</code> or <code>$(RULEDIR)</code> or
+ <code>$(location <i>output_name</i>)</code>; see below).
</p>
</li>
<li>
diff --git a/src/main/java/com/google/devtools/build/lib/vfs/PathFragment.java b/src/main/java/com/google/devtools/build/lib/vfs/PathFragment.java
index 0fc6a89..4c7e219 100644
--- a/src/main/java/com/google/devtools/build/lib/vfs/PathFragment.java
+++ b/src/main/java/com/google/devtools/build/lib/vfs/PathFragment.java
@@ -241,8 +241,9 @@
/**
* Returns the {@link PathFragment} relative to the base {@link PathFragment}.
*
- * <p>For example, <code>FilePath.create("foo/bar/wiz").relativeTo(FilePath.create("foo"))</code>
- * returns <code>"bar/wiz"</code>.
+ * <p>For example, <code>
+ * {@link PathFragment}.create("foo/bar/wiz").relativeTo({@link PathFragment}.create("foo"))
+ * </code> returns <code>"bar/wiz"</code>.
*
* <p>If the {@link PathFragment} is not a child of the passed {@link PathFragment} an {@link
* IllegalArgumentException} is thrown. In particular, this will happen whenever the two {@link
diff --git a/src/test/java/com/google/devtools/build/lib/bazel/rules/genrule/GenRuleConfiguredTargetTest.java b/src/test/java/com/google/devtools/build/lib/bazel/rules/genrule/GenRuleConfiguredTargetTest.java
index ece88bd..a8e9bbb 100644
--- a/src/test/java/com/google/devtools/build/lib/bazel/rules/genrule/GenRuleConfiguredTargetTest.java
+++ b/src/test/java/com/google/devtools/build/lib/bazel/rules/genrule/GenRuleConfiguredTargetTest.java
@@ -283,6 +283,26 @@
assertThat(bazExpected.equals(barExpected)).isFalse();
}
+ /** Ensure that variable $(RULE_DIR) gets expanded correctly in the genrule cmd. */
+ @Test
+ public void testRuleDirExpansion() throws Exception {
+ scratch.file(
+ "foo/BUILD",
+ "genrule(name = 'bar',",
+ " srcs = ['bar_in.txt'],",
+ " cmd = 'touch $(RULEDIR)',",
+ " outs = ['bar/bar_out.txt'])",
+ "genrule(name = 'baz',",
+ " srcs = ['bar/bar_out.txt'],",
+ " cmd = 'touch $(RULEDIR)',",
+ " outs = ['baz/baz_out.txt', 'logs/baz.log'])");
+
+ // Make sure the expansion for $(RULE_DIR) results in the directory of the BUILD file ("foo")
+ String expectedRegex = "touch b.{4}-out.*foo";
+ assertThat(getCommand("//foo:bar")).containsMatch(expectedRegex);
+ assertThat(getCommand("//foo:baz")).containsMatch(expectedRegex);
+ }
+
/** Ensure that variable $(CC) gets expanded correctly in the genrule cmd. */
@Test
public void testMakeVarExpansion() throws Exception {