// 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.genrule;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.CompositeRunfilesSupplier;
import com.google.devtools.build.lib.analysis.AliasProvider;
import com.google.devtools.build.lib.analysis.CommandHelper;
import com.google.devtools.build.lib.analysis.ConfigurationMakeVariableContext;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.FileProvider;
import com.google.devtools.build.lib.analysis.FilesToRunProvider;
import com.google.devtools.build.lib.analysis.MakeVariableExpander.ExpansionException;
import com.google.devtools.build.lib.analysis.MakeVariableSupplier;
import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.Runfiles;
import com.google.devtools.build.lib.analysis.RunfilesProvider;
import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.collect.nestedset.Order;
import com.google.devtools.build.lib.packages.TargetUtils;
import com.google.devtools.build.lib.rules.cpp.CcCommon.CcFlagsSupplier;
import com.google.devtools.build.lib.rules.cpp.CppHelper;
import com.google.devtools.build.lib.rules.java.JavaHelper;
import com.google.devtools.build.lib.syntax.Type;
import com.google.devtools.build.lib.util.LazyString;
import com.google.devtools.build.lib.vfs.PathFragment;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
/**
* A base implementation of genrule, to be used by specific implementing rules which can change some
* of the semantics around when the execution info and inputs are changed.
*/
public abstract class GenRuleBase implements RuleConfiguredTargetFactory {
private static final Pattern CROSSTOOL_MAKE_VARIABLE =
Pattern.compile("\\$\\((CC|CC_FLAGS|AR|NM|OBJCOPY|STRIP|GCOVTOOL)\\)");
private static final Pattern JDK_MAKE_VARIABLE =
Pattern.compile("\\$\\((JAVABASE|JAVA)\\)");
protected static boolean requiresCrosstool(String command) {
return CROSSTOOL_MAKE_VARIABLE.matcher(command).find();
}
protected boolean requiresJdk(String command) {
return JDK_MAKE_VARIABLE.matcher(command).find();
}
/**
* Returns a {@link Map} of execution info, which will be used in later processing to construct
* the actual command line that will be executed.
*
*
GenRule implementations can override this method to include additional specific information
* needed.
*/
protected Map getExtraExecutionInfo(RuleContext ruleContext, String command) {
return ImmutableMap.of();
}
/**
* Returns an {@link Iterable} of {@link NestedSet}s, which will be added to the genrule's inputs
* using the {@link NestedSetBuilder#addTransitive} method.
*
*
GenRule implementations can override this method to better control what inputs are needed
* for specific command inputs.
*/
protected Iterable> getExtraInputArtifacts(
RuleContext ruleContext, String command) {
return ImmutableList.of();
}
/**
* Returns {@code true} if the rule should be stamped.
*
*
Genrule implementations can set this based on the rule context, including by defining their
* own attributes over and above what is present in {@link GenRuleBaseRule}.
*/
protected abstract boolean isStampingEnabled(RuleContext ruleContext);
/**
* Updates the {@link RuleConfiguredTargetBuilder} that is used for this rule.
*
*
GenRule implementations can override this method to enhance and update the builder without
* needing to entirely override the {@link #create} method.
*/
protected RuleConfiguredTargetBuilder updateBuilder(
RuleConfiguredTargetBuilder builder,
RuleContext ruleContext,
NestedSet filesToBuild) {
return builder;
}
@Override
public ConfiguredTarget create(RuleContext ruleContext)
throws RuleErrorException, InterruptedException {
NestedSet filesToBuild =
NestedSetBuilder.wrap(Order.STABLE_ORDER, ruleContext.getOutputArtifacts());
NestedSetBuilder resolvedSrcsBuilder = NestedSetBuilder.stableOrder();
if (filesToBuild.isEmpty()) {
ruleContext.attributeError("outs", "Genrules without outputs don't make sense");
}
if (ruleContext.attributes().get("executable", Type.BOOLEAN)
&& Iterables.size(filesToBuild) > 1) {
ruleContext.attributeError(
"executable",
"if genrules produce executables, they are allowed only one output. "
+ "If you need the executable=1 argument, then you should split this genrule into "
+ "genrules producing single outputs");
}
ImmutableMap.Builder