Skip to content

Commit c637fbb

Browse files
katremeteorcloudy
authored andcommitted
Create a base implementation of GenRule that can be used by both Bazel and
internal Google code. -- PiperOrigin-RevId: 145795255 MOS_MIGRATED_REVID=145795255
1 parent a4d719d commit c637fbb

File tree

11 files changed

+821
-452
lines changed

11 files changed

+821
-452
lines changed

src/main/java/com/google/devtools/build/lib/BUILD

+3
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ filegroup(
3232
"//src/main/java/com/google/devtools/build/lib/rules/cpp:srcs",
3333
"//src/main/java/com/google/devtools/build/lib/rules/cpp/proto:srcs",
3434
"//src/main/java/com/google/devtools/build/lib/rules/genquery:srcs",
35+
"//src/main/java/com/google/devtools/build/lib/rules/genrule:srcs",
3536
"//src/main/java/com/google/devtools/build/lib/rules/objc:srcs",
3637
"//src/main/java/com/google/devtools/build/lib/sandbox:srcs",
3738
"//src/main/java/com/google/devtools/build/lib/ssd:srcs",
@@ -570,6 +571,7 @@ java_library(
570571
"//src/main/java/com/google/devtools/build/lib/rules/cpp",
571572
"//src/main/java/com/google/devtools/build/lib/rules/cpp/proto:CcProtoLibrary",
572573
"//src/main/java/com/google/devtools/build/lib/rules/genquery",
574+
"//src/main/java/com/google/devtools/build/lib/rules/genrule",
573575
"//src/main/java/com/google/devtools/build/lib/rules/objc",
574576
"//src/main/java/com/google/devtools/build/skyframe",
575577
"//src/main/java/com/google/devtools/common/options",
@@ -1112,6 +1114,7 @@ filegroup(
11121114
"//src/main/java/com/google/devtools/build/lib/rules/apple/cpp:srcs",
11131115
"//src/main/java/com/google/devtools/build/lib/rules/cpp:srcs",
11141116
"//src/main/java/com/google/devtools/build/lib/rules/genquery:srcs",
1117+
"//src/main/java/com/google/devtools/build/lib/rules/genrule:srcs",
11151118
"//src/main/java/com/google/devtools/build/lib/rules/objc:srcs",
11161119
],
11171120
)

src/main/java/com/google/devtools/build/lib/analysis/CommandHelper.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -99,15 +99,15 @@ public final class CommandHelper {
9999
public CommandHelper(
100100
RuleContext ruleContext,
101101
Iterable<? extends TransitiveInfoCollection> tools,
102-
ImmutableMap<Label, Iterable<Artifact>> labelMap) {
102+
ImmutableMap<Label, ? extends Iterable<Artifact>> labelMap) {
103103
this.ruleContext = ruleContext;
104104

105105
ImmutableList.Builder<Artifact> resolvedToolsBuilder = ImmutableList.builder();
106106
ImmutableMap.Builder<PathFragment, Artifact> remoteRunfileManifestBuilder =
107107
ImmutableMap.builder();
108108
Map<Label, Collection<Artifact>> tempLabelMap = new HashMap<>();
109109

110-
for (Map.Entry<Label, Iterable<Artifact>> entry : labelMap.entrySet()) {
110+
for (Map.Entry<Label, ? extends Iterable<Artifact>> entry : labelMap.entrySet()) {
111111
Iterables.addAll(mapGet(tempLabelMap, entry.getKey()), entry.getValue());
112112
}
113113

src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java

+2
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@
113113
import com.google.devtools.build.lib.rules.extra.ActionListenerRule;
114114
import com.google.devtools.build.lib.rules.extra.ExtraActionRule;
115115
import com.google.devtools.build.lib.rules.genquery.GenQueryRule;
116+
import com.google.devtools.build.lib.rules.genrule.GenRuleBaseRule;
116117
import com.google.devtools.build.lib.rules.java.JavaConfigurationLoader;
117118
import com.google.devtools.build.lib.rules.java.JavaImportBaseRule;
118119
import com.google.devtools.build.lib.rules.java.JavaOptions;
@@ -342,6 +343,7 @@ public void init(Builder builder) {
342343
builder.addRuleDefinition(new AliasRule());
343344
builder.addRuleDefinition(new BazelFilegroupRule());
344345
builder.addRuleDefinition(new TestSuiteRule());
346+
builder.addRuleDefinition(new GenRuleBaseRule());
345347
builder.addRuleDefinition(new BazelGenRuleRule());
346348
builder.addRuleDefinition(new GenQueryRule());
347349

src/main/java/com/google/devtools/build/lib/bazel/rules/genrule/BazelGenRule.java

+7-214
Original file line numberDiff line numberDiff line change
@@ -14,227 +14,20 @@
1414

1515
package com.google.devtools.build.lib.bazel.rules.genrule;
1616

17-
import static com.google.devtools.build.lib.analysis.RunfilesProvider.withData;
18-
19-
import com.google.common.collect.ImmutableList;
20-
import com.google.common.collect.ImmutableMap;
21-
import com.google.common.collect.ImmutableSet;
22-
import com.google.common.collect.Iterables;
23-
import com.google.common.collect.Lists;
24-
import com.google.common.collect.Maps;
25-
import com.google.devtools.build.lib.actions.Artifact;
26-
import com.google.devtools.build.lib.analysis.CommandHelper;
27-
import com.google.devtools.build.lib.analysis.ConfigurationMakeVariableContext;
28-
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
29-
import com.google.devtools.build.lib.analysis.FileProvider;
30-
import com.google.devtools.build.lib.analysis.FilesToRunProvider;
31-
import com.google.devtools.build.lib.analysis.MakeVariableExpander.ExpansionException;
32-
import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
33-
import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
3417
import com.google.devtools.build.lib.analysis.RuleContext;
35-
import com.google.devtools.build.lib.analysis.Runfiles;
36-
import com.google.devtools.build.lib.analysis.RunfilesProvider;
37-
import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
38-
import com.google.devtools.build.lib.cmdline.Label;
39-
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
40-
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
41-
import com.google.devtools.build.lib.collect.nestedset.Order;
42-
import com.google.devtools.build.lib.packages.TargetUtils;
43-
import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory;
44-
import com.google.devtools.build.lib.rules.ToolchainProvider;
18+
import com.google.devtools.build.lib.rules.genrule.GenRuleBase;
4519
import com.google.devtools.build.lib.syntax.Type;
46-
import com.google.devtools.build.lib.vfs.PathFragment;
47-
import java.util.List;
48-
import java.util.Map;
4920

5021
/**
51-
* An implementation of genrule.
22+
* An implementation of genrule for Bazel.
5223
*/
53-
public class BazelGenRule implements RuleConfiguredTargetFactory {
54-
55-
private Artifact getExecutable(RuleContext ruleContext, NestedSet<Artifact> filesToBuild) {
56-
if (Iterables.size(filesToBuild) == 1) {
57-
Artifact out = Iterables.getOnlyElement(filesToBuild);
58-
if (ruleContext.attributes().get("executable", Type.BOOLEAN)) {
59-
return out;
60-
}
61-
}
62-
return null;
63-
}
24+
public class BazelGenRule extends GenRuleBase {
6425

6526
@Override
66-
public ConfiguredTarget create(RuleContext ruleContext)
67-
throws RuleErrorException, InterruptedException {
68-
final List<Artifact> resolvedSrcs = Lists.newArrayList();
69-
70-
final NestedSet<Artifact> filesToBuild =
71-
NestedSetBuilder.wrap(Order.STABLE_ORDER, ruleContext.getOutputArtifacts());
72-
if (filesToBuild.isEmpty()) {
73-
ruleContext.attributeError("outs", "Genrules without outputs don't make sense");
74-
}
75-
if (ruleContext.attributes().get("executable", Type.BOOLEAN)
76-
&& Iterables.size(filesToBuild) > 1) {
77-
ruleContext.attributeError("executable",
78-
"if genrules produce executables, they are allowed only one output. "
79-
+ "If you need the executable=1 argument, then you should split this genrule into "
80-
+ "genrules producing single outputs");
81-
}
82-
83-
ImmutableMap.Builder<Label, Iterable<Artifact>> labelMap = ImmutableMap.builder();
84-
for (TransitiveInfoCollection dep : ruleContext.getPrerequisites("srcs", Mode.TARGET)) {
85-
Iterable<Artifact> files = dep.getProvider(FileProvider.class).getFilesToBuild();
86-
Iterables.addAll(resolvedSrcs, files);
87-
labelMap.put(dep.getLabel(), files);
88-
}
89-
90-
CommandHelper commandHelper =
91-
new CommandHelper(
92-
ruleContext, ruleContext.getPrerequisites("tools", Mode.HOST), labelMap.build());
93-
94-
if (ruleContext.hasErrors()) {
95-
return null;
96-
}
97-
98-
String baseCommand = commandHelper.resolveCommandAndExpandLabels(
99-
ruleContext.attributes().get("heuristic_label_expansion", Type.BOOLEAN), false);
100-
101-
// Adds the genrule environment setup script before the actual shell command
102-
String command = String.format("source %s; %s",
103-
ruleContext.getPrerequisiteArtifact("$genrule_setup", Mode.HOST).getExecPath(),
104-
baseCommand);
105-
106-
command = resolveCommand(ruleContext, command, resolvedSrcs, filesToBuild);
107-
108-
String message = ruleContext.attributes().get("message", Type.STRING);
109-
if (message.isEmpty()) {
110-
message = "Executing genrule";
111-
}
112-
113-
ImmutableMap<String, String> env = ruleContext.getConfiguration().getLocalShellEnvironment();
114-
ImmutableSet<String> clientEnvVars =
115-
ruleContext.getConfiguration().getVariableShellEnvironment();
116-
117-
Map<String, String> executionInfo = Maps.newLinkedHashMap();
118-
executionInfo.putAll(TargetUtils.getExecutionInfo(ruleContext.getRule()));
119-
120-
if (ruleContext.attributes().get("local", Type.BOOLEAN)) {
121-
executionInfo.put("local", "");
122-
}
123-
124-
NestedSetBuilder<Artifact> inputs = NestedSetBuilder.stableOrder();
125-
inputs.addAll(resolvedSrcs);
126-
inputs.addAll(commandHelper.getResolvedTools());
127-
FilesToRunProvider genruleSetup =
128-
ruleContext.getPrerequisite("$genrule_setup", Mode.HOST, FilesToRunProvider.class);
129-
inputs.addAll(genruleSetup.getFilesToRun());
130-
List<String> argv = commandHelper.buildCommandLine(command, inputs, ".genrule_script.sh",
131-
ImmutableMap.copyOf(executionInfo));
132-
133-
if (ruleContext.attributes().get("stamp", Type.BOOLEAN)) {
134-
inputs.add(ruleContext.getAnalysisEnvironment().getStableWorkspaceStatusArtifact());
135-
inputs.add(ruleContext.getAnalysisEnvironment().getVolatileWorkspaceStatusArtifact());
136-
}
137-
138-
ruleContext.registerAction(
139-
new BazelGenRuleAction(
140-
ruleContext.getActionOwner(),
141-
ImmutableList.copyOf(commandHelper.getResolvedTools()),
142-
inputs.build(),
143-
filesToBuild,
144-
argv,
145-
env,
146-
clientEnvVars,
147-
ImmutableMap.copyOf(executionInfo),
148-
ImmutableMap.copyOf(commandHelper.getRemoteRunfileManifestMap()),
149-
message + ' ' + ruleContext.getLabel()));
150-
151-
RunfilesProvider runfilesProvider = withData(
152-
// No runfiles provided if not a data dependency.
153-
Runfiles.EMPTY,
154-
// We only need to consider the outputs of a genrule
155-
// No need to visit the dependencies of a genrule. They cross from the target into the host
156-
// configuration, because the dependencies of a genrule are always built for the host
157-
// configuration.
158-
new Runfiles.Builder(
159-
ruleContext.getWorkspaceName(),
160-
ruleContext.getConfiguration().legacyExternalRunfiles())
161-
.addTransitiveArtifacts(filesToBuild)
162-
.build());
163-
164-
return new RuleConfiguredTargetBuilder(ruleContext)
165-
.setFilesToBuild(filesToBuild)
166-
.setRunfilesSupport(null, getExecutable(ruleContext, filesToBuild))
167-
.addProvider(RunfilesProvider.class, runfilesProvider)
168-
.build();
169-
}
170-
171-
private String resolveCommand(final RuleContext ruleContext, final String command,
172-
final List<Artifact> resolvedSrcs, final NestedSet<Artifact> filesToBuild) {
173-
return ruleContext.expandMakeVariables(
174-
"cmd",
175-
command,
176-
new ConfigurationMakeVariableContext(
177-
ruleContext.getRule().getPackage(), ruleContext.getConfiguration(),
178-
ToolchainProvider.getToolchainMakeVariables(ruleContext, "toolchains")) {
179-
@Override
180-
public String lookupMakeVariable(String name) throws ExpansionException {
181-
if (name.equals("SRCS")) {
182-
return Artifact.joinExecPaths(" ", resolvedSrcs);
183-
} else if (name.equals("<")) {
184-
return expandSingletonArtifact(resolvedSrcs, "$<", "input file");
185-
} else if (name.equals("OUTS")) {
186-
return Artifact.joinExecPaths(" ", filesToBuild);
187-
} else if (name.equals("@")) {
188-
return expandSingletonArtifact(filesToBuild, "$@", "output file");
189-
} else if (name.equals("@D")) {
190-
// The output directory. If there is only one filename in outs,
191-
// this expands to the directory containing that file. If there are
192-
// multiple filenames, this variable instead expands to the
193-
// package's root directory in the genfiles tree, even if all the
194-
// generated files belong to the same subdirectory!
195-
if (Iterables.size(filesToBuild) == 1) {
196-
Artifact outputFile = Iterables.getOnlyElement(filesToBuild);
197-
PathFragment relativeOutputFile = outputFile.getExecPath();
198-
if (relativeOutputFile.segmentCount() <= 1) {
199-
// This should never happen, since the path should contain at
200-
// least a package name and a file name.
201-
throw new IllegalStateException(
202-
"$(@D) for genrule " + ruleContext.getLabel() + " has less than one segment");
203-
}
204-
return relativeOutputFile.getParentDirectory().getPathString();
205-
} else {
206-
PathFragment dir;
207-
if (ruleContext.getRule().hasBinaryOutput()) {
208-
dir = ruleContext.getConfiguration().getBinFragment();
209-
} else {
210-
dir = ruleContext.getConfiguration().getGenfilesFragment();
211-
}
212-
PathFragment relPath =
213-
ruleContext.getRule().getLabel().getPackageIdentifier().getSourceRoot();
214-
return dir.getRelative(relPath).getPathString();
215-
}
216-
} else {
217-
return super.lookupMakeVariable(name);
218-
}
219-
}
220-
});
221-
}
222-
223-
// Returns the path of the sole element "artifacts", generating an exception
224-
// with an informative error message iff the set is not a singleton.
225-
//
226-
// Used to expand "$<", "$@"
227-
private String expandSingletonArtifact(Iterable<Artifact> artifacts,
228-
String variable,
229-
String artifactName)
230-
throws ExpansionException {
231-
if (Iterables.isEmpty(artifacts)) {
232-
throw new ExpansionException("variable '" + variable
233-
+ "' : no " + artifactName);
234-
} else if (Iterables.size(artifacts) > 1) {
235-
throw new ExpansionException("variable '" + variable
236-
+ "' : more than one " + artifactName);
27+
protected boolean isStampingEnabled(RuleContext ruleContext) {
28+
if (!ruleContext.attributes().has("stamp", Type.BOOLEAN)) {
29+
return false;
23730
}
238-
return Iterables.getOnlyElement(artifacts).getExecPathString();
31+
return ruleContext.attributes().get("stamp", Type.BOOLEAN);
23932
}
24033
}

0 commit comments

Comments
 (0)