// 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 static com.google.devtools.build.lib.packages.Attribute.attr; import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST; import static com.google.devtools.build.lib.packages.BuildType.LICENSE; import static com.google.devtools.build.lib.packages.BuildType.OUTPUT_LIST; import static com.google.devtools.build.lib.syntax.Type.BOOLEAN; import static com.google.devtools.build.lib.syntax.Type.STRING; import com.google.devtools.build.lib.analysis.BaseRuleClasses; import com.google.devtools.build.lib.analysis.RuleDefinition; import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment; import com.google.devtools.build.lib.analysis.TemplateVariableInfo; import com.google.devtools.build.lib.analysis.config.HostTransition; import com.google.devtools.build.lib.packages.Attribute; import com.google.devtools.build.lib.packages.Attribute.ComputedDefault; import com.google.devtools.build.lib.packages.Attribute.LabelLateBoundDefault; import com.google.devtools.build.lib.packages.AttributeMap; import com.google.devtools.build.lib.packages.BuildType; import com.google.devtools.build.lib.packages.RuleClass; import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType; import com.google.devtools.build.lib.rules.cpp.CppConfiguration; import com.google.devtools.build.lib.rules.cpp.CppRuleClasses; import com.google.devtools.build.lib.syntax.Type; import com.google.devtools.build.lib.util.FileTypeSet; /** * Rule definition for the genrule rule, intended to be inherited by specific GenRule * implementations. Implementations will need to include any needed additional dependencies, such * as a setup script target. */ public class GenRuleBaseRule implements RuleDefinition { /** * Late-bound dependency on the C++ toolchain iff the genrule has make variables that need * that toolchain. */ public static LabelLateBoundDefault ccToolchainAttribute(RuleDefinitionEnvironment env) { return LabelLateBoundDefault.fromTargetConfiguration( CppConfiguration.class, env.getToolsLabel(CppRuleClasses.CROSSTOOL_LABEL), // null guards are needed for LateBoundAttributeTest (rule, attributes, cppConfig) -> attributes != null && attributes.get("cmd", Type.STRING) != null && GenRuleBase.requiresCrosstool(attributes.get("cmd", Type.STRING)) ? CppRuleClasses.ccToolchainAttribute(env).resolve(rule, attributes, cppConfig) : null); } /** Computed dependency on the C++ toolchain type. */ public static ComputedDefault ccToolchainTypeAttribute(RuleDefinitionEnvironment env) { return new ComputedDefault("cmd") { @Override public Object getDefault(AttributeMap rule) { return GenRuleBase.requiresCrosstool(rule.get("cmd", Type.STRING)) ? CppRuleClasses.ccToolchainTypeAttribute(env) : null; } }; } @Override public RuleClass build( RuleClass.Builder builder, RuleDefinitionEnvironment env) { return builder /* A list of inputs for this rule, such as source files to process.

This attributes is not suitable to list tools executed by the cmd; use the tools attribute for them instead.

The build system ensures these prerequisites are built before running the genrule command; they are built using the same configuration as the original build request. The names of the files of these prerequisites are available to the command as a space-separated list in $(SRCS); alternatively the path of an individual srcs target //x:y can be obtained using $(location //x:y), or using $< provided it's the only entry in //srcs.

*/ .add( attr("srcs", LABEL_LIST) .direct_compile_time_input() .allowedFileTypes(FileTypeSet.ANY_FILE)) /* A list of tool dependencies for this rule. See the definition of dependencies for more information.

The build system ensures these prerequisites are built before running the genrule command; they are built using the host configuration, since these tools are executed as part of the build. The path of an individual tools target //x:y can be obtained using $(location //x:y).

Any *_binary or tool to be executed by cmd must appear in this list, not in srcs, to ensure they are built in the correct configuration.

*/ .add(attr("tools", LABEL_LIST) .cfg(HostTransition.INSTANCE) .allowedFileTypes(FileTypeSet.ANY_FILE)) .add( attr("toolchains", LABEL_LIST) .allowedFileTypes(FileTypeSet.NO_FILE) .mandatoryProviders(TemplateVariableInfo.PROVIDER.id()) ) /* A list of files generated by this rule.

Output files must not cross package boundaries. Output filenames are interpreted as relative to the package.

If the executable flag is set, outs must contain exactly one label.

*/ .add(attr("outs", OUTPUT_LIST).mandatory()) /* The command to run. Subject to $(location) and "Make" variable substitution.
  1. First $(location) substitution is applied, replacing all occurrences of $(location label) and of $(locations label).
  2. Note that outs are not included in this substitution. Output files are always generated into a predictable location (available via $(@D), $@, $(OUTS) or $(location output_name); see below).

  3. Next, "Make" variables are expanded. Note that predefined variables $(JAVA), $(JAVAC) and $(JAVABASE) expand under the host configuration, so Java invocations that run as part of a build step can correctly load shared libraries and other dependencies.
  4. Finally, the resulting command is executed using the Bash shell. If its exit code is non-zero the command is considered to have failed.

The command may refer to *_binary targets; it should use a label for this. The following variables are available within the cmd sublanguage:

*/ .add(attr("cmd", STRING).mandatory()) /*

If set to 1, this option causes output files to be written into the bin directory instead of the genfiles directory.

*/ // TODO(bazel-team): find a location to document genfiles/binfiles, link to them from here. .add( attr("output_to_bindir", BOOLEAN) .value(false) .nonconfigurable( "policy decision: no reason for this to depend on the configuration")) /*

If set to 1, this option force this genrule to run with the standalone strategy, without sandboxing.

This is equivalent to providing 'local' as a tag (tags=["local"]). The local strategy is applied if either one is specified.

The --genrule_strategy option value local overrides this attribute. */ .add(attr("local", BOOLEAN).value(false)) /* A progress message.

A progress message that will be printed as this build step is executed. By default, the message is "Generating output" (or something equally bland) but you may provide a more specific one. Use this attribute instead of echo or other print statements in your cmd command, as this allows the build tool to control whether such progress messages are printed or not.

*/ .add(attr("message", STRING)) /* See common attributes */ .add(attr("output_licenses", LICENSE)) /* Declare output to be executable.

Setting this flag to 1 means the output is an executable file and can be run using the run command. The genrule must produce exactly one output in this case. If this attribute is set, run will try executing the file regardless of its content.

Declaring data dependencies for the generated executable is not supported.

*/ .add( attr("executable", BOOLEAN) .value(false) .nonconfigurable( "Used in computed default for $is_executable, which is itself non-configurable" + " (and thus expects its dependencies to be non-configurable), because" + " $is_executable is called from RunCommand.isExecutable, which has no" + " configuration context")) .add( attr("$is_executable", BOOLEAN) .nonconfigurable("Called from RunCommand.isExecutable, which takes a Target") .value( new Attribute.ComputedDefault() { @Override public Object getDefault(AttributeMap rule) { return (rule.get("outs", BuildType.OUTPUT_LIST).size() == 1) && rule.get("executable", BOOLEAN); } })) // This is a misfeature, so don't document it. We would like to get rid of it, but that // would require a cleanup of existing rules. .add(attr("heuristic_label_expansion", BOOLEAN).value(false)) .removeAttribute("data") .removeAttribute("deps") .build(); } @Override public RuleDefinition.Metadata getMetadata() { return RuleDefinition.Metadata.builder() .name("$genrule_base") .type(RuleClassType.ABSTRACT) .ancestors(BaseRuleClasses.RuleBase.class) .build(); } }