blob: e2657e8c39f19daa32f734fbe9ef13466e88b7db [file] [log] [blame]
Damien Martin-Guillerezf88f4d82015-09-25 13:56:55 +00001// Copyright 2014 The Bazel Authors. All rights reserved.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package com.google.devtools.build.lib.packages;
16
juliexxia44cd3a62018-12-19 11:57:16 -080017import static com.google.devtools.build.lib.packages.Attribute.ANY_RULE;
Florian Weikertea6c82d2016-09-05 12:15:31 +000018import static com.google.devtools.build.lib.packages.Attribute.attr;
Lukacs Berkiffa73ad2015-09-18 11:40:12 +000019import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST;
juliexxiaadd1ddb2020-06-19 09:34:09 -070020import static com.google.devtools.build.lib.packages.ExecGroup.EMPTY_EXEC_GROUP;
Googlerc5fcc862019-09-06 16:17:47 -070021import static com.google.devtools.build.lib.packages.Type.BOOLEAN;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010022
23import com.google.common.annotations.VisibleForTesting;
Lukacs Berki0e1a9942015-06-18 08:53:18 +000024import com.google.common.base.Function;
25import com.google.common.base.Functions;
tomlua155b532017-11-08 20:12:47 +010026import com.google.common.base.Preconditions;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010027import com.google.common.base.Predicate;
28import com.google.common.base.Predicates;
29import com.google.common.collect.ImmutableList;
Lukacs Berki0e1a9942015-06-18 08:53:18 +000030import com.google.common.collect.ImmutableMap;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010031import com.google.common.collect.ImmutableSet;
nharmataf3e99412019-01-28 10:06:29 -080032import com.google.common.collect.Interner;
John Cater9a8d16e2017-07-05 16:12:07 -040033import com.google.common.collect.Iterables;
cpeyserd852e482017-09-07 22:16:06 +020034import com.google.common.collect.Lists;
ulfjack5756b352020-01-23 04:53:22 -080035import com.google.common.collect.Maps;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010036import com.google.common.collect.Ordering;
gregcebe55e112018-01-30 11:04:53 -080037import com.google.devtools.build.lib.analysis.config.transitions.ConfigurationTransition;
mstaib860975a2018-04-26 15:00:52 -070038import com.google.devtools.build.lib.analysis.config.transitions.PatchTransition;
gregce74a895d2018-05-29 11:26:03 -070039import com.google.devtools.build.lib.analysis.config.transitions.SplitTransition;
John Caterb3b3e8b2019-04-03 09:18:42 -070040import com.google.devtools.build.lib.analysis.config.transitions.TransitionFactory;
Lukacs Berki6e91eb92015-09-21 09:12:37 +000041import com.google.devtools.build.lib.cmdline.Label;
Lukacs Berkia6434362015-09-15 13:56:14 +000042import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
Brian Silvermand7d6d622016-03-17 09:53:39 +000043import com.google.devtools.build.lib.cmdline.PackageIdentifier;
dannarkf24479d2018-06-21 11:55:44 -070044import com.google.devtools.build.lib.cmdline.RepositoryName;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010045import com.google.devtools.build.lib.events.EventHandler;
Michajlo Matijkiw581f2c22016-07-25 20:12:16 +000046import com.google.devtools.build.lib.events.NullEventHandler;
schmitta4080da92019-05-20 13:12:46 -070047import com.google.devtools.build.lib.packages.Attribute.ComputedDefault;
gregce18694cd2020-05-12 15:40:05 -070048import com.google.devtools.build.lib.packages.Attribute.StarlarkComputedDefaultTemplate;
49import com.google.devtools.build.lib.packages.Attribute.StarlarkComputedDefaultTemplate.CannotPrecomputeDefaultsException;
dannarkf24479d2018-06-21 11:55:44 -070050import com.google.devtools.build.lib.packages.BuildType.LabelConversionContext;
Lukacs Berkiffa73ad2015-09-18 11:40:12 +000051import com.google.devtools.build.lib.packages.BuildType.SelectorList;
Michael Staibb51251e2015-09-29 23:31:51 +000052import com.google.devtools.build.lib.packages.ConfigurationFragmentPolicy.MissingFragmentPolicy;
janakr6ff110e2018-03-21 21:44:27 -070053import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType;
gregce4aa059a2019-02-26 13:20:47 -080054import com.google.devtools.build.lib.packages.RuleClass.Builder.ThirdPartyLicenseExistencePolicy;
nharmata65a173a2017-08-07 16:11:04 +020055import com.google.devtools.build.lib.packages.RuleFactory.AttributeValues;
Googlerc5fcc862019-09-06 16:17:47 -070056import com.google.devtools.build.lib.packages.Type.ConversionException;
mjhalupka49581922018-02-28 11:04:31 -080057import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
58import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec.VisibleForSerialization;
Yue Gan36a26572016-05-25 11:48:10 +000059import com.google.devtools.build.lib.syntax.EvalException;
adonovanf5262c52020-04-02 09:25:14 -070060import com.google.devtools.build.lib.syntax.Location;
Googler641bdf72019-11-12 10:32:26 -080061import com.google.devtools.build.lib.syntax.Starlark;
adonovanc568d842020-04-14 09:20:01 -070062import com.google.devtools.build.lib.syntax.StarlarkCallable;
adonovan40a737c2020-03-11 14:32:19 -070063import com.google.devtools.build.lib.syntax.StarlarkThread;
juliexxia1f332e02018-10-31 14:20:55 -070064import com.google.devtools.build.lib.util.FileTypeSet;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010065import com.google.devtools.build.lib.util.StringUtil;
66import com.google.devtools.build.lib.vfs.PathFragment;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010067import java.util.ArrayList;
Googler72f3a102017-12-01 16:28:28 -080068import java.util.Arrays;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010069import java.util.BitSet;
70import java.util.Collection;
gregceda4c9592017-07-27 22:09:34 +020071import java.util.Collections;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010072import java.util.HashMap;
cpeyserfb829992017-09-07 17:17:03 +020073import java.util.HashSet;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010074import java.util.LinkedHashMap;
gregceb46208d2019-03-11 13:21:34 -070075import java.util.LinkedHashSet;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010076import java.util.List;
77import java.util.Map;
mjhalupka49581922018-02-28 11:04:31 -080078import java.util.Objects;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010079import java.util.Set;
80import java.util.regex.Pattern;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010081import javax.annotation.Nullable;
82import javax.annotation.concurrent.Immutable;
83
84/**
85 * Instances of RuleClass encapsulate the set of attributes of a given "class" of rule, such as
86 * <code>cc_binary</code>.
87 *
janakrd3fe5e72018-03-30 12:49:12 -070088 * <p>This is an instance of the "meta-class" pattern for Rules: we achieve using <i>values</i> what
89 * subclasses achieve using <i>types</i>. (The "Design Patterns" book doesn't include this pattern,
90 * so think of it as something like a cross between a Flyweight and a State pattern. Like Flyweight,
91 * we avoid repeatedly storing data that belongs to many instances. Like State, we delegate from
92 * Rule to RuleClass for the specific behavior of that rule (though unlike state, a Rule object
93 * never changes its RuleClass). This avoids the need to declare one Java class per class of Rule,
94 * yet achieves the same behavior.)
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010095 *
96 * <p>The use of a metaclass also allows us to compute a mapping from Attributes to small integers
janakrd3fe5e72018-03-30 12:49:12 -070097 * and share this between all rules of the same metaclass. This means we can save the attribute
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010098 * dictionary for each rule instance using an array, which is much more compact than a hashtable.
99 *
100 * <p>Rule classes whose names start with "$" are considered "abstract"; since they are not valid
101 * identifiers, they cannot be named in the build language. However, they are useful for grouping
102 * related attributes which are inherited.
103 *
janakrd3fe5e72018-03-30 12:49:12 -0700104 * <p>The exact values in this class are important. In particular:
105 *
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100106 * <ul>
janakrd3fe5e72018-03-30 12:49:12 -0700107 * <li>Changing an attribute from MANDATORY to OPTIONAL creates the potential for null-pointer
108 * exceptions in code that expects a value.
109 * <li>Attributes whose names are preceded by a "$" or a ":" are "hidden", and cannot be redefined
110 * in a BUILD file. They are a useful way of adding a special dependency. By convention,
111 * attributes starting with "$" are implicit dependencies, and those starting with a ":" are
112 * late-bound implicit dependencies, i.e. dependencies that can only be resolved when the
113 * configuration is known.
114 * <li>Attributes should not be introduced into the hierarchy higher then necessary.
115 * <li>The 'deps' and 'data' attributes are treated specially by the code that builds the runfiles
116 * tree. All targets appearing in these attributes appears beneath the ".runfiles" tree; in
117 * addition, "deps" may have rule-specific semantics.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100118 * </ul>
juliexxia1f332e02018-10-31 14:20:55 -0700119 *
120 * TODO(bazel-team): Consider breaking up this class in more manageable subclasses.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100121 */
Janak Ramakrishnanc97ec7b2017-02-15 23:58:24 +0000122// Non-final only for mocking in tests. Do not subclass!
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100123@Immutable
janakrd3fe5e72018-03-30 12:49:12 -0700124@AutoCodec
Janak Ramakrishnanc97ec7b2017-02-15 23:58:24 +0000125public class RuleClass {
John Caterae6f7d52019-04-12 10:42:59 -0700126
michajlob839a512020-03-11 10:04:23 -0700127 /**
michajlo0a89cef2020-04-06 12:04:12 -0700128 * Maximum attributes per RuleClass. Current value was chosen to be high enough to be considered a
michajlob839a512020-03-11 10:04:23 -0700129 * non-breaking change for reasonable use. It was also chosen to be low enough to give significant
130 * headroom before hitting {@link AttributeContainer}'s limits.
131 */
michajlo7475b772020-03-12 15:10:11 -0700132 private static final int MAX_ATTRIBUTES = 200;
michajlob839a512020-03-11 10:04:23 -0700133
michajlo0a89cef2020-04-06 12:04:12 -0700134 /**
135 * Maximum attribute name length. Chosen to accommodate existing and prevent extreme outliers from
136 * forming - extreme values create bloat, both in memory usage and various outputs, including but
137 * not limited to, query output.
138 */
139 private static final int MAX_ATTRIBUTE_NAME_LENGTH = 128;
140
janakrd3fe5e72018-03-30 12:49:12 -0700141 @AutoCodec
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +0000142 static final Function<? super Rule, Map<String, Label>> NO_EXTERNAL_BINDINGS =
John Cater39401a92020-07-09 10:12:55 -0700143 Functions.constant(ImmutableMap.of());
144
145 @AutoCodec
146 static final Function<? super Rule, List<String>> NO_TOOLCHAINS_TO_REGISTER =
147 Functions.constant(ImmutableList.of());
janakrd3fe5e72018-03-30 12:49:12 -0700148
149 @AutoCodec
mstaibe5538ad2017-04-04 18:32:23 +0000150 static final Function<? super Rule, Set<String>> NO_OPTION_REFERENCE =
John Cater39401a92020-07-09 10:12:55 -0700151 Functions.constant(ImmutableSet.of());
Brian Silvermand7d6d622016-03-17 09:53:39 +0000152
nharmatab4060b62017-04-04 17:11:39 +0000153 public static final PathFragment THIRD_PARTY_PREFIX = PathFragment.create("third_party");
Googler9ad95082019-05-13 13:38:22 -0700154 public static final PathFragment EXPERIMENTAL_PREFIX = PathFragment.create("experimental");
John Caterae6f7d52019-04-12 10:42:59 -0700155 public static final String EXEC_COMPATIBLE_WITH_ATTR = "exec_compatible_with";
Googlerb5082462019-08-26 14:28:09 -0700156 public static final String EXEC_PROPERTIES = "exec_properties";
twerth54a4e082020-04-28 01:39:48 -0700157 /*
158 * The attribute that declares the set of license labels which apply to this target.
159 */
aiuto4d9bb522020-02-19 13:26:10 -0800160 public static final String APPLICABLE_LICENSES_ATTR = "applicable_licenses";
Brian Silvermand7d6d622016-03-17 09:53:39 +0000161
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100162 /**
163 * A constraint for the package name of the Rule instances.
164 */
165 public static class PackageNameConstraint implements PredicateWithMessage<Rule> {
166
167 public static final int ANY_SEGMENT = 0;
168
169 private final int pathSegment;
170
171 private final Set<String> values;
172
173 /**
174 * The pathSegment-th segment of the package must be one of the specified values.
175 * The path segment indexing starts from 1.
176 */
177 public PackageNameConstraint(int pathSegment, String... values) {
178 this.values = ImmutableSet.copyOf(values);
179 this.pathSegment = pathSegment;
180 }
181
182 @Override
183 public boolean apply(Rule input) {
184 PathFragment path = input.getLabel().getPackageFragment();
185 if (pathSegment == ANY_SEGMENT) {
186 return path.getFirstSegment(values) != PathFragment.INVALID_SEGMENT;
187 } else {
188 return path.segmentCount() >= pathSegment
189 && values.contains(path.getSegment(pathSegment - 1));
190 }
191 }
192
193 @Override
194 public String getErrorReason(Rule param) {
195 if (pathSegment == ANY_SEGMENT) {
Francois-Rene Rideaucbebd632015-02-11 16:56:37 +0000196 return param.getRuleClass() + " rules have to be under a "
197 + StringUtil.joinEnglishList(values, "or", "'") + " directory";
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100198 } else if (pathSegment == 1) {
199 return param.getRuleClass() + " rules are only allowed in "
200 + StringUtil.joinEnglishList(StringUtil.append(values, "//", ""), "or");
201 } else {
Francois-Rene Rideaucbebd632015-02-11 16:56:37 +0000202 return param.getRuleClass() + " rules are only allowed in packages which "
203 + StringUtil.ordinal(pathSegment) + " is " + StringUtil.joinEnglishList(values, "or");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100204 }
205 }
206
207 @VisibleForTesting
208 public int getPathSegment() {
209 return pathSegment;
210 }
211
212 @VisibleForTesting
213 public Collection<String> getValues() {
214 return values;
215 }
216 }
217
cparsonse2d200f2018-03-06 16:15:11 -0800218 /** A factory or builder class for rule implementations. */
219 public interface ConfiguredTargetFactory<
220 TConfiguredTarget, TContext, TActionConflictException extends Throwable> {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100221 /**
222 * Returns a fully initialized configured target instance using the given context.
Chris Parsons4dfb22c2016-05-23 17:39:42 +0000223 *
224 * @throws RuleErrorException if configured target creation could not be completed due to rule
cparsonse2d200f2018-03-06 16:15:11 -0800225 * errors
226 * @throws TActionConflictException if there were conflicts during action registration
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100227 */
cparsonse2d200f2018-03-06 16:15:11 -0800228 TConfiguredTarget create(TContext ruleContext)
229 throws InterruptedException, RuleErrorException, TActionConflictException;
Chris Parsons4dfb22c2016-05-23 17:39:42 +0000230
231 /**
cparsonse2d200f2018-03-06 16:15:11 -0800232 * Exception indicating that configured target creation could not be completed. General error
233 * messaging should be done via {@link RuleErrorConsumer}; this exception only interrupts
234 * configured target creation in cases where it can no longer continue.
Chris Parsons4dfb22c2016-05-23 17:39:42 +0000235 */
janakr525ba252020-02-19 11:27:05 -0800236 final class RuleErrorException extends Exception {
adonovanec1cdc92020-08-07 08:15:51 -0700237 public RuleErrorException() {
Benjamin Petersonaf53a112019-06-05 10:47:11 -0700238 super();
239 }
240
adonovanec1cdc92020-08-07 08:15:51 -0700241 public RuleErrorException(String message) {
Benjamin Petersonaf53a112019-06-05 10:47:11 -0700242 super(message);
243 }
janakr525ba252020-02-19 11:27:05 -0800244
adonovanec1cdc92020-08-07 08:15:51 -0700245 public RuleErrorException(Throwable cause) {
janakr525ba252020-02-19 11:27:05 -0800246 super(cause);
247 }
248
adonovanec1cdc92020-08-07 08:15:51 -0700249 public RuleErrorException(String message, Throwable cause) {
janakr525ba252020-02-19 11:27:05 -0800250 super(message, cause);
251 }
Benjamin Petersonaf53a112019-06-05 10:47:11 -0700252 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100253 }
254
255 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100256 * For Bazel's constraint system: the attribute that declares the set of environments a rule
257 * supports, overriding the defaults for their respective groups.
258 */
259 public static final String RESTRICTED_ENVIRONMENT_ATTR = "restricted_to";
260
261 /**
262 * For Bazel's constraint system: the attribute that declares the set of environments a rule
263 * supports, appending them to the defaults for their respective groups.
264 */
265 public static final String COMPATIBLE_ENVIRONMENT_ATTR = "compatible_with";
266
267 /**
268 * For Bazel's constraint system: the implicit attribute used to store rule class restriction
269 * defaults as specified by {@link Builder#restrictedTo}.
270 */
271 public static final String DEFAULT_RESTRICTED_ENVIRONMENT_ATTR =
272 "$" + RESTRICTED_ENVIRONMENT_ATTR;
273
274 /**
275 * For Bazel's constraint system: the implicit attribute used to store rule class compatibility
276 * defaults as specified by {@link Builder#compatibleWith}.
277 */
278 public static final String DEFAULT_COMPATIBLE_ENVIRONMENT_ATTR =
279 "$" + COMPATIBLE_ENVIRONMENT_ATTR;
280
281 /**
gregce749962a2019-03-08 12:47:34 -0800282 * Name of the attribute that stores all {@link
283 * com.google.devtools.build.lib.rules.config.ConfigRuleClasses} labels this rule references (i.e.
284 * select() keys). This is specially populated in {@link #populateRuleAttributeValues}.
285 *
286 * <p>This isn't technically necessary for builds: select() keys are evaluated in {@link
287 * com.google.devtools.build.lib.skyframe.ConfiguredTargetFunction#getConfigConditions} instead of
288 * normal dependency resolution because they're needed to determine other dependencies. So there's
289 * no intrinsic reason why we need an extra attribute to store them.
290 *
291 * <p>There are three reasons why we still create this attribute:
292 *
293 * <ol>
294 * <li>Collecting them once in {@link #populateRuleAttributeValues} instead of multiple times in
295 * ConfiguredTargetFunction saves extra looping over the rule's attributes.
296 * <li>Query's dependency resolution has no equivalent of {@link
297 * com.google.devtools.build.lib.skyframe.ConfiguredTargetFunction#getConfigConditions} and
298 * we need to make sure its coverage remains complete.
299 * <li>Manual configuration trimming uses the normal dependency resolution process to work
300 * correctly and config_setting keys are subject to this trimming.
301 * </ol>
302 *
303 * <p>It should be possible to clean up these issues if we decide we don't want an artificial
304 * attribute dependency. But care has to be taken to do that safely.
305 */
306 public static final String CONFIG_SETTING_DEPS_ATTRIBUTE = "$config_dependencies";
307
308 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100309 * A support class to make it easier to create {@code RuleClass} instances.
310 * This class follows the 'fluent builder' pattern.
311 *
312 * <p>The {@link #addAttribute} method will throw an exception if an attribute
313 * of that name already exists. Use {@link #overrideAttribute} in that case.
314 */
315 public static final class Builder {
Laurent Le Brun6ce51e12015-07-07 11:54:41 +0000316 private static final Pattern RULE_NAME_PATTERN = Pattern.compile("[A-Za-z_][A-Za-z0-9_]*");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100317
318 /**
319 * The type of the rule class, which determines valid names and required
320 * attributes.
321 */
322 public enum RuleClassType {
323 /**
324 * Abstract rules are intended for rule classes that are just used to
325 * factor out common attributes, and for rule classes that are used only
326 * internally. These rules cannot be instantiated by a BUILD file.
327 *
328 * <p>The rule name must contain a '$' and {@link
329 * TargetUtils#isTestRuleName} must return false for the name.
330 */
331 ABSTRACT {
332 @Override
333 public void checkName(String name) {
334 Preconditions.checkArgument(
Ulf Adams07dba942015-03-05 14:47:37 +0000335 (name.contains("$") && !TargetUtils.isTestRuleName(name)) || name.isEmpty());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100336 }
337
338 @Override
339 public void checkAttributes(Map<String, Attribute> attributes) {
340 // No required attributes.
341 }
342 },
343
344 /**
345 * Invisible rule classes should contain a dollar sign so that they cannot be instantiated
346 * by the user. They are different from abstract rules in that they can be instantiated
347 * at will.
348 */
349 INVISIBLE {
350 @Override
351 public void checkName(String name) {
352 Preconditions.checkArgument(name.contains("$"));
353 }
354
355 @Override
356 public void checkAttributes(Map<String, Attribute> attributes) {
357 // No required attributes.
358 }
359 },
360
361 /**
362 * Normal rules are instantiable by BUILD files. Their names must therefore
363 * obey the rules for identifiers in the BUILD language. In addition,
364 * {@link TargetUtils#isTestRuleName} must return false for the name.
365 */
366 NORMAL {
367 @Override
368 public void checkName(String name) {
Ulf Adams07dba942015-03-05 14:47:37 +0000369 Preconditions.checkArgument(
370 !TargetUtils.isTestRuleName(name) && RULE_NAME_PATTERN.matcher(name).matches(),
371 "Invalid rule name: %s", name);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100372 }
373
374 @Override
375 public void checkAttributes(Map<String, Attribute> attributes) {
376 for (Attribute attribute : REQUIRED_ATTRIBUTES_FOR_NORMAL_RULES) {
377 Attribute presentAttribute = attributes.get(attribute.getName());
378 Preconditions.checkState(presentAttribute != null,
379 "Missing mandatory '%s' attribute in normal rule class.", attribute.getName());
380 Preconditions.checkState(presentAttribute.getType().equals(attribute.getType()),
Francois-Rene Rideaucbebd632015-02-11 16:56:37 +0000381 "Mandatory attribute '%s' in normal rule class has incorrect type (expected"
382 + " %s).", attribute.getName(), attribute.getType());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100383 }
384 }
385 },
386
387 /**
388 * Workspace rules can only be instantiated from a WORKSPACE file. Their names obey the
389 * rule for identifiers.
390 */
391 WORKSPACE {
392 @Override
393 public void checkName(String name) {
394 Preconditions.checkArgument(RULE_NAME_PATTERN.matcher(name).matches());
395 }
396
397 @Override
398 public void checkAttributes(Map<String, Attribute> attributes) {
399 // No required attributes.
400 }
401 },
402
403 /**
404 * Test rules are instantiable by BUILD files and are handled specially
405 * when run with the 'test' command. Their names must obey the rules
406 * for identifiers in the BUILD language and {@link
407 * TargetUtils#isTestRuleName} must return true for the name.
408 *
409 * <p>In addition, test rules must contain certain attributes. See {@link
410 * Builder#REQUIRED_ATTRIBUTES_FOR_TESTS}.
411 */
412 TEST {
413 @Override
414 public void checkName(String name) {
415 Preconditions.checkArgument(TargetUtils.isTestRuleName(name)
416 && RULE_NAME_PATTERN.matcher(name).matches());
417 }
418
419 @Override
420 public void checkAttributes(Map<String, Attribute> attributes) {
421 for (Attribute attribute : REQUIRED_ATTRIBUTES_FOR_TESTS) {
422 Attribute presentAttribute = attributes.get(attribute.getName());
423 Preconditions.checkState(presentAttribute != null,
424 "Missing mandatory '%s' attribute in test rule class.", attribute.getName());
425 Preconditions.checkState(presentAttribute.getType().equals(attribute.getType()),
Googleraa437e02017-09-14 09:52:47 +0200426 "Mandatory attribute '%s' in test rule class has incorrect type (expected %s).",
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100427 attribute.getName(), attribute.getType());
428 }
429 }
Mark Schaller4fa83ac2015-07-10 16:59:37 +0000430 },
431
432 /**
433 * Placeholder rules are only instantiated when packages which refer to non-native rule
434 * classes are deserialized. At this time, non-native rule classes can't be serialized. To
435 * prevent crashes on deserialization, when a package containing a rule with a non-native rule
436 * class is deserialized, the rule is assigned a placeholder rule class. This is compatible
437 * with our limited set of package serialization use cases.
438 *
439 * Placeholder rule class names obey the rule for identifiers.
440 */
441 PLACEHOLDER {
442 @Override
443 public void checkName(String name) {
444 Preconditions.checkArgument(RULE_NAME_PATTERN.matcher(name).matches(), name);
445 }
446
447 @Override
448 public void checkAttributes(Map<String, Attribute> attributes) {
449 // No required attributes; this rule class cannot have the wrong set of attributes now
450 // because, if it did, the rule class would have failed to build before the package
451 // referring to it was serialized.
452 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100453 };
454
455 /**
456 * Checks whether the given name is valid for the current rule class type.
457 *
458 * @throws IllegalArgumentException if the name is not valid
459 */
460 public abstract void checkName(String name);
461
462 /**
463 * Checks whether the given set of attributes contains all the required
464 * attributes for the current rule class type.
465 *
466 * @throws IllegalArgumentException if a required attribute is missing
467 */
468 public abstract void checkAttributes(Map<String, Attribute> attributes);
469 }
470
Googler72f3a102017-12-01 16:28:28 -0800471 /** A predicate that filters rule classes based on their names. */
mjhalupka49581922018-02-28 11:04:31 -0800472 @AutoCodec
Googler72f3a102017-12-01 16:28:28 -0800473 public static class RuleClassNamePredicate {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100474
mjhalupka49581922018-02-28 11:04:31 -0800475 private static final RuleClassNamePredicate UNSPECIFIED_INSTANCE =
476 new RuleClassNamePredicate(ImmutableSet.of(), PredicateType.UNSPECIFIED, null);
477
478 private final ImmutableSet<String> ruleClassNames;
479
480 private final PredicateType predicateType;
481
Googler72f3a102017-12-01 16:28:28 -0800482 private final Predicate<String> ruleClassNamePredicate;
483 private final Predicate<RuleClass> ruleClassPredicate;
484 // if non-null, used ONLY for checking overlap
485 @Nullable private final Set<?> overlappable;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100486
mjhalupka49581922018-02-28 11:04:31 -0800487 @VisibleForSerialization
488 enum PredicateType {
489 ONLY,
490 All_EXCEPT,
491 UNSPECIFIED
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100492 }
493
mjhalupka49581922018-02-28 11:04:31 -0800494 @VisibleForSerialization
495 RuleClassNamePredicate(
496 ImmutableSet<String> ruleClassNames, PredicateType predicateType, Set<?> overlappable) {
497 this.ruleClassNames = ruleClassNames;
498 this.predicateType = predicateType;
Googler72f3a102017-12-01 16:28:28 -0800499 this.overlappable = overlappable;
mjhalupka49581922018-02-28 11:04:31 -0800500
501 switch (predicateType) {
502 case All_EXCEPT:
503 Predicate<String> containing = only(ruleClassNames).asPredicateOfRuleClassName();
504 ruleClassNamePredicate =
505 new DescribedPredicate<>(
506 Predicates.not(containing), "all but " + containing.toString());
507 ruleClassPredicate =
508 new DescribedPredicate<>(
509 Predicates.compose(ruleClassNamePredicate, RuleClass::getName),
510 ruleClassNamePredicate.toString());
511 break;
512 case ONLY:
513 ruleClassNamePredicate =
514 new DescribedPredicate<>(
515 Predicates.in(ruleClassNames), StringUtil.joinEnglishList(ruleClassNames));
516 ruleClassPredicate =
517 new DescribedPredicate<>(
518 Predicates.compose(ruleClassNamePredicate, RuleClass::getName),
519 ruleClassNamePredicate.toString());
520 break;
521 case UNSPECIFIED:
522 ruleClassNamePredicate = Predicates.alwaysTrue();
523 ruleClassPredicate = Predicates.alwaysTrue();
524 break;
525 default:
526 // This shouldn't happen normally since the constructor is private and within this file.
527 throw new IllegalArgumentException(
528 "Predicate type was not specified when constructing a RuleClassNamePredicate.");
529 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100530 }
531
Googler72f3a102017-12-01 16:28:28 -0800532 public static RuleClassNamePredicate only(Iterable<String> ruleClassNamesAsIterable) {
533 ImmutableSet<String> ruleClassNames = ImmutableSet.copyOf(ruleClassNamesAsIterable);
mjhalupka49581922018-02-28 11:04:31 -0800534 return new RuleClassNamePredicate(ruleClassNames, PredicateType.ONLY, ruleClassNames);
Googler72f3a102017-12-01 16:28:28 -0800535 }
536
537 public static RuleClassNamePredicate only(String... ruleClasses) {
538 return only(Arrays.asList(ruleClasses));
539 }
540
541 public static RuleClassNamePredicate allExcept(String... ruleClasses) {
542 ImmutableSet<String> ruleClassNames = ImmutableSet.copyOf(ruleClasses);
543 Preconditions.checkState(!ruleClassNames.isEmpty(), "Use unspecified() instead");
mjhalupka49581922018-02-28 11:04:31 -0800544 return new RuleClassNamePredicate(ruleClassNames, PredicateType.All_EXCEPT, null);
Googler72f3a102017-12-01 16:28:28 -0800545 }
546
547 /**
548 * This is a special sentinel value which represents a "default" {@link
549 * RuleClassNamePredicate} which is unspecified. Note that a call to its {@link
550 * RuleClassNamePredicate#asPredicateOfRuleClass} produces {@code
551 * Predicates.<RuleClass>alwaysTrue()}, which is a sentinel value for other parts of bazel.
552 */
553 public static RuleClassNamePredicate unspecified() {
mjhalupka49581922018-02-28 11:04:31 -0800554 return UNSPECIFIED_INSTANCE;
Googler72f3a102017-12-01 16:28:28 -0800555 }
556
557 public final Predicate<String> asPredicateOfRuleClassName() {
558 return ruleClassNamePredicate;
559 }
560
561 public final Predicate<RuleClass> asPredicateOfRuleClass() {
562 return ruleClassPredicate;
563 }
564
565 /**
566 * Determines whether two {@code RuleClassNamePredicate}s should be considered incompatible as
567 * rule class predicate and rule class warning predicate.
568 *
569 * <p>Specifically, if both list sets of explicit rule class names to permit, those two sets
570 * must be disjoint, so the restriction only applies when both predicates have been created by
571 * {@link #only}.
572 */
573 boolean consideredOverlapping(RuleClassNamePredicate that) {
574 return this.overlappable != null
575 && that.overlappable != null
576 && !Collections.disjoint(this.overlappable, that.overlappable);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100577 }
578
579 @Override
580 public int hashCode() {
mjhalupka49581922018-02-28 11:04:31 -0800581 return Objects.hash(ruleClassNames, predicateType);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100582 }
583
584 @Override
Googler72f3a102017-12-01 16:28:28 -0800585 public boolean equals(Object obj) {
586 // NOTE: Specifically not checking equality of ruleClassPredicate.
587 // By construction, if the name predicates are equals, the rule class predicates are, too.
588 return obj instanceof RuleClassNamePredicate
mjhalupka49581922018-02-28 11:04:31 -0800589 && ruleClassNames.equals(((RuleClassNamePredicate) obj).ruleClassNames)
590 && predicateType.equals(((RuleClassNamePredicate) obj).predicateType);
gregceda4c9592017-07-27 22:09:34 +0200591 }
592
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100593 @Override
594 public String toString() {
Googler72f3a102017-12-01 16:28:28 -0800595 return ruleClassNamePredicate.toString();
596 }
597
598 /** A pass-through predicate, except that an explicit {@link #toString()} is provided. */
599 private static class DescribedPredicate<T> implements Predicate<T> {
600 private final Predicate<T> delegate; // the actual predicate
601 private final String description;
602
603 private DescribedPredicate(Predicate<T> delegate, String description) {
604 this.delegate = delegate;
605 this.description = description;
606 }
607
608 @Override
609 public boolean apply(T input) {
610 return delegate.apply(input);
611 }
612
613 @Override
614 public int hashCode() {
615 return delegate.hashCode();
616 }
617
618 @Override
619 public boolean equals(Object obj) {
620 return obj instanceof DescribedPredicate
621 && delegate.equals(((DescribedPredicate<?>) obj).delegate);
622 }
623
624 @Override
625 public String toString() {
626 return description;
627 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100628 }
629 }
630
juliexxia1f332e02018-10-31 14:20:55 -0700631 /**
gregcead752cc2020-04-10 10:32:59 -0700632 * Name of default attribute implicitly added to all Starlark RuleClasses that are {@code
juliexxia1f332e02018-10-31 14:20:55 -0700633 * build_setting}s.
634 */
gregce74d84d42020-04-17 10:02:03 -0700635 public static final String STARLARK_BUILD_SETTING_DEFAULT_ATTR_NAME = "build_setting_default";
juliexxia1f332e02018-10-31 14:20:55 -0700636
juliexxia44cd3a62018-12-19 11:57:16 -0800637 public static final String BUILD_SETTING_DEFAULT_NONCONFIGURABLE =
638 "Build setting defaults are referenced during analysis.";
639
Googler7807b6c2017-03-14 10:57:43 +0000640 /** List of required attributes for normal rules, name and type. */
641 public static final ImmutableList<Attribute> REQUIRED_ATTRIBUTES_FOR_NORMAL_RULES =
642 ImmutableList.of(attr("tags", Type.STRING_LIST).build());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100643
Googler7807b6c2017-03-14 10:57:43 +0000644 /** List of required attributes for test rules, name and type. */
645 public static final ImmutableList<Attribute> REQUIRED_ATTRIBUTES_FOR_TESTS =
646 ImmutableList.of(
647 attr("tags", Type.STRING_LIST).build(),
648 attr("size", Type.STRING).build(),
649 attr("timeout", Type.STRING).build(),
650 attr("flaky", Type.BOOLEAN).build(),
651 attr("shard_count", Type.INTEGER).build(),
652 attr("local", Type.BOOLEAN).build());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100653
654 private String name;
adonovanebb86fc2020-03-20 14:57:54 -0700655 private ImmutableList<StarlarkThread.CallStackEntry> callstack = ImmutableList.of();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100656 private final RuleClassType type;
gregce74d84d42020-04-17 10:02:03 -0700657 private final boolean starlark;
658 private boolean starlarkTestable = false;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100659 private boolean documented;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100660 private boolean binaryOutput = true;
661 private boolean workspaceOnly = false;
gregce74d84d42020-04-17 10:02:03 -0700662 private boolean isExecutableStarlark = false;
cparsons55781c92018-10-17 12:03:08 -0700663 private boolean isAnalysisTest = false;
cparsons9d40c6b2019-02-25 12:24:40 -0800664 private boolean hasAnalysisTestTransition = false;
aiuto50226ac2020-06-14 21:28:27 -0700665 private boolean hasFunctionTransitionAllowlist = false;
juliexxia30976d82019-03-12 10:59:26 -0700666 private boolean hasStarlarkRuleTransition = false;
gregce1d8d6dd2019-04-10 09:27:34 -0700667 private boolean ignoreLicenses = false;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100668 private ImplicitOutputsFunction implicitOutputsFunction = ImplicitOutputsFunction.NONE;
John Caterb3b3e8b2019-04-03 09:18:42 -0700669 private TransitionFactory<Rule> transitionFactory;
cparsonse2d200f2018-03-06 16:15:11 -0800670 private ConfiguredTargetFactory<?, ?, ?> configuredTargetFactory = null;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100671 private PredicateWithMessage<Rule> validityPredicate =
672 PredicatesWithMessage.<Rule>alwaysTrue();
673 private Predicate<String> preferredDependencyPredicate = Predicates.alwaysFalse();
Dmitry Lomovb91d3922017-01-09 20:12:57 +0000674 private AdvertisedProviderSet.Builder advertisedProviders = AdvertisedProviderSet.builder();
adonovanc568d842020-04-14 09:20:01 -0700675 private StarlarkCallable configuredTargetFunction = null;
juliexxia1f332e02018-10-31 14:20:55 -0700676 private BuildSetting buildSetting = null;
Lukacs Berki0e1a9942015-06-18 08:53:18 +0000677 private Function<? super Rule, Map<String, Label>> externalBindingsFunction =
678 NO_EXTERNAL_BINDINGS;
John Cater39401a92020-07-09 10:12:55 -0700679 private Function<? super Rule, ? extends List<String>> toolchainsToRegisterFunction =
680 NO_TOOLCHAINS_TO_REGISTER;
mstaibe5538ad2017-04-04 18:32:23 +0000681 private Function<? super Rule, ? extends Set<String>> optionReferenceFunction =
682 NO_OPTION_REFERENCE;
janakrd3fe5e72018-03-30 12:49:12 -0700683 /** This field and the next are null iff the rule is native. */
684 @Nullable private Label ruleDefinitionEnvironmentLabel;
685
adonovan1d93d262020-05-07 14:50:42 -0700686 @Nullable private byte[] ruleDefinitionEnvironmentDigest = null;
Michael Staibb51251e2015-09-29 23:31:51 +0000687 private ConfigurationFragmentPolicy.Builder configurationFragmentPolicy =
688 new ConfigurationFragmentPolicy.Builder();
Florian Weikert3f53fbb2015-08-07 22:25:50 +0000689
Greg Estrenc04c88f2015-03-06 19:45:50 +0000690 private boolean supportsConstraintChecking = true;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100691
gregce4aa059a2019-02-26 13:20:47 -0800692 /**
693 * The policy on whether Bazel should enforce that third_party rules declare <code>licenses().
694 * </code>. This is only intended for the migration of <a
695 * href="https://github.com/bazelbuild/bazel/issues/7444">GitHub #7444</a>. Our final end state
696 * is to have no license-related logic whatsoever. But that's going to take some time.
697 */
698 public enum ThirdPartyLicenseExistencePolicy {
699 /**
700 * Always do this check, overriding whatever {@link
gregce3f6da0a2019-04-04 09:40:07 -0700701 * StarlarkSemanticsOptions#incompatibleDisableThirdPartyLicenseChecking} says.
gregce4aa059a2019-02-26 13:20:47 -0800702 */
703 ALWAYS_CHECK,
704
705 /**
706 * Never do this check, overriding whatever {@link
gregce3f6da0a2019-04-04 09:40:07 -0700707 * StarlarkSemanticsOptions#incompatibleDisableThirdPartyLicenseChecking} says.
gregce4aa059a2019-02-26 13:20:47 -0800708 */
709 NEVER_CHECK,
710
gregce3f6da0a2019-04-04 09:40:07 -0700711 /**
712 * Do whatever {@link StarlarkSemanticsOptions#incompatibleDisableThirdPartyLicenseChecking}
713 * says.
714 */
gregce4aa059a2019-02-26 13:20:47 -0800715 USER_CONTROLLABLE
716 }
717
718 private ThirdPartyLicenseExistencePolicy thirdPartyLicenseExistencePolicy;
719
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100720 private final Map<String, Attribute> attributes = new LinkedHashMap<>();
cpeyserfb829992017-09-07 17:17:03 +0200721 private final Set<Label> requiredToolchains = new HashSet<>();
jcater01bb1f92019-06-17 12:09:11 -0700722 private boolean useToolchainResolution = true;
John Cater099cf2f2020-06-11 12:58:36 -0700723 private boolean useToolchainTransition = false;
John Cateree45c662018-06-05 11:09:01 -0700724 private Set<Label> executionPlatformConstraints = new HashSet<>();
Dmitry Lomov5b1ce4d2018-05-30 04:34:08 -0700725 private OutputFile.Kind outputFileKind = OutputFile.Kind.FILE;
juliexxia693048d2020-04-01 06:41:42 -0700726 private final Map<String, ExecGroup> execGroups = new HashMap<>();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100727
728 /**
gregce74d84d42020-04-17 10:02:03 -0700729 * Constructs a new {@code RuleClassBuilder} using all attributes from all parent rule classes.
730 * An attribute cannot exist in more than one parent.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100731 *
gregce74d84d42020-04-17 10:02:03 -0700732 * <p>The rule type affects the allowed names and the required attributes (see {@link
733 * RuleClassType}).
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100734 *
gregce74d84d42020-04-17 10:02:03 -0700735 * @throws IllegalArgumentException if an attribute with the same name exists in more than one
736 * parent
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100737 */
gregce74d84d42020-04-17 10:02:03 -0700738 public Builder(String name, RuleClassType type, boolean starlark, RuleClass... parents) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100739 this.name = name;
gregce74d84d42020-04-17 10:02:03 -0700740 this.starlark = starlark;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100741 this.type = type;
gregce74d84d42020-04-17 10:02:03 -0700742 Preconditions.checkState(starlark || type != RuleClassType.PLACEHOLDER, name);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100743 this.documented = type != RuleClassType.ABSTRACT;
744 for (RuleClass parent : parents) {
745 if (parent.getValidityPredicate() != PredicatesWithMessage.<Rule>alwaysTrue()) {
746 setValidityPredicate(parent.getValidityPredicate());
747 }
748 if (parent.preferredDependencyPredicate != Predicates.<String>alwaysFalse()) {
749 setPreferredDependencyPredicate(parent.preferredDependencyPredicate);
750 }
Michael Staibff66c192016-01-14 22:40:37 +0000751 configurationFragmentPolicy
752 .includeConfigurationFragmentsFrom(parent.getConfigurationFragmentPolicy());
Michael Staibb51251e2015-09-29 23:31:51 +0000753 configurationFragmentPolicy.setMissingFragmentPolicy(
754 parent.getConfigurationFragmentPolicy().getMissingFragmentPolicy());
Greg Estrenc04c88f2015-03-06 19:45:50 +0000755 supportsConstraintChecking = parent.supportsConstraintChecking;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100756
cpeyserd78b3742017-08-04 19:48:53 +0200757 addRequiredToolchains(parent.getRequiredToolchains());
jcater01bb1f92019-06-17 12:09:11 -0700758 useToolchainResolution = parent.useToolchainResolution;
John Cater099cf2f2020-06-11 12:58:36 -0700759 useToolchainTransition = parent.useToolchainTransition;
John Cateree45c662018-06-05 11:09:01 -0700760 addExecutionPlatformConstraints(parent.getExecutionPlatformConstraints());
juliexxia693048d2020-04-01 06:41:42 -0700761 try {
762 addExecGroups(parent.getExecGroups());
763 } catch (DuplicateExecGroupError e) {
764 throw new IllegalArgumentException(
765 String.format(
juliexxia5aab7502020-06-12 12:09:25 -0700766 "An execution group named '%s' is inherited multiple times with different"
767 + " requirements in %s ruleclass",
juliexxia693048d2020-04-01 06:41:42 -0700768 e.getDuplicateGroup(), name));
769 }
cpeyserd78b3742017-08-04 19:48:53 +0200770
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100771 for (Attribute attribute : parent.getAttributes()) {
772 String attrName = attribute.getName();
773 Preconditions.checkArgument(
dannarke64a8162018-06-13 13:48:20 -0700774 !attributes.containsKey(attrName) || attributes.get(attrName).equals(attribute),
Googler2935d672015-03-12 01:25:11 +0000775 "Attribute %s is inherited multiple times in %s ruleclass",
776 attrName,
777 name);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100778 attributes.put(attrName, attribute);
779 }
Lukacs Berkiac4f9422015-05-29 10:06:30 +0000780
Dmitry Lomovb91d3922017-01-09 20:12:57 +0000781 advertisedProviders.addParent(parent.getAdvertisedProviders());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100782 }
783 // TODO(bazel-team): move this testonly attribute setting to somewhere else
784 // preferably to some base RuleClass implementation.
785 if (this.type.equals(RuleClassType.TEST)) {
786 Attribute.Builder<Boolean> testOnlyAttr = attr("testonly", BOOLEAN).value(true)
787 .nonconfigurable("policy decision: this shouldn't depend on the configuration");
788 if (attributes.containsKey("testonly")) {
789 override(testOnlyAttr);
790 } else {
791 add(testOnlyAttr);
792 }
793 }
794 }
795
796 /**
797 * Checks that required attributes for test rules are present, creates the
798 * {@link RuleClass} object and returns it.
799 *
800 * @throws IllegalStateException if any of the required attributes is missing
801 */
802 public RuleClass build() {
tomlu72642a22017-10-18 06:23:14 +0200803 // For built-ins, name == key
804 return build(name, name);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100805 }
806
tomlu72642a22017-10-18 06:23:14 +0200807 /** Same as {@link #build} except with setting the name and key parameters. */
808 public RuleClass build(String name, String key) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100809 Preconditions.checkArgument(this.name.isEmpty() || this.name.equals(name));
810 type.checkName(name);
michajlob839a512020-03-11 10:04:23 -0700811
michajlo0a89cef2020-04-06 12:04:12 -0700812 checkAttributes(name, type, attributes);
michajlob839a512020-03-11 10:04:23 -0700813
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100814 Preconditions.checkState(
815 (type == RuleClassType.ABSTRACT)
janakr6ff110e2018-03-21 21:44:27 -0700816 == (configuredTargetFactory == null && configuredTargetFunction == null),
817 "Bad combo for %s: %s %s %s",
818 name,
819 type,
820 configuredTargetFactory,
821 configuredTargetFunction);
Damien Martin-Guillerez653df882016-02-17 21:46:22 +0000822 if (!workspaceOnly) {
gregce74d84d42020-04-17 10:02:03 -0700823 if (starlark) {
824 assertStarlarkRuleClassHasImplementationFunction();
825 assertStarlarkRuleClassHasEnvironmentLabel();
janakrd3fe5e72018-03-30 12:49:12 -0700826 }
Damien Martin-Guillerez653df882016-02-17 21:46:22 +0000827 Preconditions.checkState(externalBindingsFunction == NO_EXTERNAL_BINDINGS);
John Cater39401a92020-07-09 10:12:55 -0700828 Preconditions.checkState(toolchainsToRegisterFunction == NO_TOOLCHAINS_TO_REGISTER);
Damien Martin-Guillerez653df882016-02-17 21:46:22 +0000829 }
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +0000830 if (type == RuleClassType.PLACEHOLDER) {
adonovan1d93d262020-05-07 14:50:42 -0700831 Preconditions.checkNotNull(ruleDefinitionEnvironmentDigest, this.name);
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +0000832 }
John Cater04be3f82019-11-07 12:20:25 -0800833
juliexxia1f332e02018-10-31 14:20:55 -0700834 if (buildSetting != null) {
835 Type<?> type = buildSetting.getType();
836 Attribute.Builder<?> attrBuilder =
gregce74d84d42020-04-17 10:02:03 -0700837 attr(STARLARK_BUILD_SETTING_DEFAULT_ATTR_NAME, type)
juliexxia44cd3a62018-12-19 11:57:16 -0800838 .nonconfigurable(BUILD_SETTING_DEFAULT_NONCONFIGURABLE)
juliexxia1f332e02018-10-31 14:20:55 -0700839 .mandatory();
840 if (BuildType.isLabelType(type)) {
841 attrBuilder.allowedFileTypes(FileTypeSet.ANY_FILE);
juliexxia44cd3a62018-12-19 11:57:16 -0800842 attrBuilder.allowedRuleClasses(ANY_RULE);
juliexxia1f332e02018-10-31 14:20:55 -0700843 }
844 this.add(attrBuilder);
John Catera6e3e872019-08-07 13:24:34 -0700845
846 // Build setting rules should opt out of toolchain resolution, since they form part of the
847 // configuration.
848 this.useToolchainResolution(false);
John Cater099cf2f2020-06-11 12:58:36 -0700849 this.useToolchainTransition(false);
juliexxia1f332e02018-10-31 14:20:55 -0700850 }
John Cateree45c662018-06-05 11:09:01 -0700851
juliexxiaadd1ddb2020-06-19 09:34:09 -0700852 // Any exec groups that have entirely empty toolchains and constraints inherit the rule's
853 // toolchains and constraints. Note that this isn't the same as a target's constraints which
854 // also read from attributes and configuration.
855 Map<String, ExecGroup> execGroupsWithInheritance = new HashMap<>();
856 ExecGroup inherited = null;
857 for (Map.Entry<String, ExecGroup> groupEntry : execGroups.entrySet()) {
858 ExecGroup group = groupEntry.getValue();
859 if (group.equals(EMPTY_EXEC_GROUP)) {
860 if (inherited == null) {
861 inherited = ExecGroup.create(requiredToolchains, executionPlatformConstraints);
862 }
863 execGroupsWithInheritance.put(groupEntry.getKey(), inherited);
864 } else {
865 execGroupsWithInheritance.put(groupEntry.getKey(), group);
866 }
867 }
868
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +0000869 return new RuleClass(
870 name,
adonovanebb86fc2020-03-20 14:57:54 -0700871 callstack,
tomlu72642a22017-10-18 06:23:14 +0200872 key,
janakr6ff110e2018-03-21 21:44:27 -0700873 type,
gregce74d84d42020-04-17 10:02:03 -0700874 starlark,
875 starlarkTestable,
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +0000876 documented,
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +0000877 binaryOutput,
878 workspaceOnly,
gregce74d84d42020-04-17 10:02:03 -0700879 isExecutableStarlark,
cparsons55781c92018-10-17 12:03:08 -0700880 isAnalysisTest,
cparsons9d40c6b2019-02-25 12:24:40 -0800881 hasAnalysisTestTransition,
aiuto50226ac2020-06-14 21:28:27 -0700882 hasFunctionTransitionAllowlist,
gregce1d8d6dd2019-04-10 09:27:34 -0700883 ignoreLicenses,
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +0000884 implicitOutputsFunction,
Michael Staib2a675202017-03-20 18:06:48 +0000885 transitionFactory,
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +0000886 configuredTargetFactory,
887 validityPredicate,
888 preferredDependencyPredicate,
Dmitry Lomovb91d3922017-01-09 20:12:57 +0000889 advertisedProviders.build(),
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +0000890 configuredTargetFunction,
891 externalBindingsFunction,
John Cater39401a92020-07-09 10:12:55 -0700892 toolchainsToRegisterFunction,
mstaibe5538ad2017-04-04 18:32:23 +0000893 optionReferenceFunction,
janakrd3fe5e72018-03-30 12:49:12 -0700894 ruleDefinitionEnvironmentLabel,
adonovan1d93d262020-05-07 14:50:42 -0700895 ruleDefinitionEnvironmentDigest,
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +0000896 configurationFragmentPolicy.build(),
897 supportsConstraintChecking,
gregce4aa059a2019-02-26 13:20:47 -0800898 thirdPartyLicenseExistencePolicy,
John Catereca28402017-05-17 21:44:12 +0200899 requiredToolchains,
jcater01bb1f92019-06-17 12:09:11 -0700900 useToolchainResolution,
John Cater099cf2f2020-06-11 12:58:36 -0700901 useToolchainTransition,
John Cateree45c662018-06-05 11:09:01 -0700902 executionPlatformConstraints,
juliexxiaadd1ddb2020-06-19 09:34:09 -0700903 execGroupsWithInheritance,
Dmitry Lomov5b1ce4d2018-05-30 04:34:08 -0700904 outputFileKind,
juliexxia1f332e02018-10-31 14:20:55 -0700905 attributes.values(),
906 buildSetting);
janakrd3fe5e72018-03-30 12:49:12 -0700907 }
908
michajlo0a89cef2020-04-06 12:04:12 -0700909 private static void checkAttributes(
910 String ruleClassName, RuleClassType ruleClassType, Map<String, Attribute> attributes) {
911 Preconditions.checkArgument(
912 attributes.size() <= MAX_ATTRIBUTES,
913 "Rule class %s declared too many attributes (%s > %s)",
914 ruleClassName,
915 attributes.size(),
916 MAX_ATTRIBUTES);
917
918 for (String attributeName : attributes.keySet()) {
919 // TODO(b/151171037): This check would make more sense at Attribute creation time, but the
920 // use of unchecked exceptions in these APIs makes it brittle.
921 Preconditions.checkArgument(
922 attributeName.length() <= MAX_ATTRIBUTE_NAME_LENGTH,
923 "Attribute %s.%s's name is too long (%s > %s)",
924 ruleClassName,
925 attributeName,
926 attributeName.length(),
927 MAX_ATTRIBUTE_NAME_LENGTH);
928 }
929
930 ruleClassType.checkAttributes(attributes);
931 }
932
gregce74d84d42020-04-17 10:02:03 -0700933 private void assertStarlarkRuleClassHasImplementationFunction() {
janakrd3fe5e72018-03-30 12:49:12 -0700934 Preconditions.checkState(
935 (type == RuleClassType.NORMAL || type == RuleClassType.TEST)
936 == (configuredTargetFunction != null),
937 "%s %s",
938 type,
939 configuredTargetFunction);
940 }
941
gregce74d84d42020-04-17 10:02:03 -0700942 private void assertStarlarkRuleClassHasEnvironmentLabel() {
janakrd3fe5e72018-03-30 12:49:12 -0700943 Preconditions.checkState(
944 (type == RuleClassType.NORMAL
945 || type == RuleClassType.TEST
946 || type == RuleClassType.PLACEHOLDER)
947 == (ruleDefinitionEnvironmentLabel != null),
laurentlb7dcad732018-10-25 05:17:20 -0700948 "Concrete Starlark rule classes can't have null labels: %s %s",
janakrd3fe5e72018-03-30 12:49:12 -0700949 ruleDefinitionEnvironmentLabel,
950 type);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100951 }
952
jcater6e132862019-07-16 08:50:04 -0700953 /**
954 * Declares that the implementation of the associated rule class requires the given fragments to
955 * be present in this rule's host and target configurations.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100956 *
Greg Estren693f17f2015-11-06 16:45:45 +0000957 * <p>The value is inherited by subclasses.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100958 */
Michael Staibb51251e2015-09-29 23:31:51 +0000959 public Builder requiresConfigurationFragments(Class<?>... configurationFragments) {
Michael Staibff66c192016-01-14 22:40:37 +0000960 configurationFragmentPolicy.requiresConfigurationFragments(
961 ImmutableSet.<Class<?>>copyOf(configurationFragments));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100962 return this;
963 }
964
Ulf Adams71423eb2015-08-06 11:51:17 +0000965 /**
Greg Estren693f17f2015-11-06 16:45:45 +0000966 * Declares that the implementation of the associated rule class requires the given
gregce614dc502017-12-20 17:24:46 -0800967 * fragments to be present in the given configuration that isn't the rule's configuration but
968 * is also readable by the rule.
969 *
970 * <p>You probably don't want to use this, because rules generally shouldn't read configurations
971 * other than their own. If you want to declare host config fragments, see
972 * {@link com.google.devtools.build.lib.analysis.config.ConfigAwareRuleClassBuilder}.
Greg Estren693f17f2015-11-06 16:45:45 +0000973 *
974 * <p>The value is inherited by subclasses.
975 */
gregcebe55e112018-01-30 11:04:53 -0800976 public Builder requiresConfigurationFragments(ConfigurationTransition transition,
gregce614dc502017-12-20 17:24:46 -0800977 Class<?>... configurationFragments) {
978 configurationFragmentPolicy.requiresConfigurationFragments(
979 transition,
Michael Staibff66c192016-01-14 22:40:37 +0000980 ImmutableSet.<Class<?>>copyOf(configurationFragments));
Greg Estren693f17f2015-11-06 16:45:45 +0000981 return this;
982 }
983
984 /**
Michael Staibff66c192016-01-14 22:40:37 +0000985 * Declares the configuration fragments that are required by this rule for the target
986 * configuration.
Greg Estren693f17f2015-11-06 16:45:45 +0000987 *
988 * <p>In contrast to {@link #requiresConfigurationFragments(Class...)}, this method takes the
gregcead752cc2020-04-10 10:32:59 -0700989 * Starlark module names of fragments instead of their classes.
Greg Estren693f17f2015-11-06 16:45:45 +0000990 */
gregce74d84d42020-04-17 10:02:03 -0700991 public Builder requiresConfigurationFragmentsByStarlarkModuleName(
Michael Staibff66c192016-01-14 22:40:37 +0000992 Collection<String> configurationFragmentNames) {
gregce220a1c82020-05-01 10:19:52 -0700993 configurationFragmentPolicy.requiresConfigurationFragmentsByStarlarkBuiltinName(
994 configurationFragmentNames);
Michael Staibff66c192016-01-14 22:40:37 +0000995 return this;
996 }
997
998 /**
999 * Declares the configuration fragments that are required by this rule for the host
1000 * configuration.
Michael Staibff66c192016-01-14 22:40:37 +00001001 */
gregce614dc502017-12-20 17:24:46 -08001002 /**
gregcead752cc2020-04-10 10:32:59 -07001003 * Declares that the implementation of the associated rule class requires the given fragments to
1004 * be present in the given configuration that isn't the rule's configuration but is also
1005 * readable by the rule.
gregce614dc502017-12-20 17:24:46 -08001006 *
gregcebe55e112018-01-30 11:04:53 -08001007 * <p>In contrast to {@link #requiresConfigurationFragments(ConfigurationTransition, Class...)},
gregcead752cc2020-04-10 10:32:59 -07001008 * this method takes Starlark module names of fragments instead of their classes. *
1009 *
gregce614dc502017-12-20 17:24:46 -08001010 * <p>You probably don't want to use this, because rules generally shouldn't read configurations
gregcead752cc2020-04-10 10:32:59 -07001011 * other than their own. If you want to declare host config fragments, see {@link
1012 * com.google.devtools.build.lib.analysis.config.ConfigAwareRuleClassBuilder}.
gregce614dc502017-12-20 17:24:46 -08001013 *
1014 * <p>The value is inherited by subclasses.
1015 */
gregce74d84d42020-04-17 10:02:03 -07001016 public Builder requiresConfigurationFragmentsByStarlarkModuleName(
gregcebe55e112018-01-30 11:04:53 -08001017 ConfigurationTransition transition, Collection<String> configurationFragmentNames) {
gregce220a1c82020-05-01 10:19:52 -07001018 configurationFragmentPolicy.requiresConfigurationFragmentsByStarlarkBuiltinName(
1019 transition, configurationFragmentNames);
Greg Estren693f17f2015-11-06 16:45:45 +00001020 return this;
1021 }
1022
adonovanebb86fc2020-03-20 14:57:54 -07001023 /** Sets the Starlark call stack associated with this rule class's creation. */
1024 public Builder setCallStack(ImmutableList<StarlarkThread.CallStackEntry> callstack) {
1025 this.callstack = callstack;
1026 return this;
1027 }
1028
gregce74d84d42020-04-17 10:02:03 -07001029 public Builder setStarlarkTestable() {
1030 Preconditions.checkState(starlark, "Cannot set starlarkTestable on a non-Starlark rule");
1031 starlarkTestable = true;
Jon Brandveinead58ae2016-09-29 18:41:10 +00001032 return this;
1033 }
1034
Greg Estren693f17f2015-11-06 16:45:45 +00001035 /**
Ulf Adams71423eb2015-08-06 11:51:17 +00001036 * Sets the policy for the case where the configuration is missing required fragments (see
1037 * {@link #requiresConfigurationFragments}).
1038 */
1039 public Builder setMissingFragmentPolicy(MissingFragmentPolicy missingFragmentPolicy) {
Michael Staibb51251e2015-09-29 23:31:51 +00001040 configurationFragmentPolicy.setMissingFragmentPolicy(missingFragmentPolicy);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001041 return this;
1042 }
Florian Weikert3f8aac92015-09-07 12:06:02 +00001043
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001044 public Builder setUndocumented() {
1045 documented = false;
1046 return this;
1047 }
1048
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001049 public Builder setWorkspaceOnly() {
1050 workspaceOnly = true;
1051 return this;
1052 }
1053
1054 /**
1055 * Determines the outputs of this rule to be created beneath the {@code
1056 * genfiles} directory. By default, files are created beneath the {@code bin}
1057 * directory.
1058 *
1059 * <p>This property is not inherited and this method should not be called by
1060 * builder of {@link RuleClassType#ABSTRACT} rule class.
1061 *
1062 * @throws IllegalStateException if called for abstract rule class builder
1063 */
1064 public Builder setOutputToGenfiles() {
1065 Preconditions.checkState(type != RuleClassType.ABSTRACT,
1066 "Setting not inherited property (output to genrules) of abstract rule class '%s'", name);
1067 this.binaryOutput = false;
1068 return this;
1069 }
1070
1071 /**
1072 * Sets the implicit outputs function of the rule class. The default implicit
1073 * outputs function is {@link ImplicitOutputsFunction#NONE}.
1074 *
1075 * <p>This property is not inherited and this method should not be called by
1076 * builder of {@link RuleClassType#ABSTRACT} rule class.
1077 *
1078 * @throws IllegalStateException if called for abstract rule class builder
1079 */
1080 public Builder setImplicitOutputsFunction(
1081 ImplicitOutputsFunction implicitOutputsFunction) {
1082 Preconditions.checkState(type != RuleClassType.ABSTRACT,
1083 "Setting not inherited property (implicit output function) of abstract rule class '%s'",
1084 name);
1085 this.implicitOutputsFunction = implicitOutputsFunction;
1086 return this;
1087 }
1088
Cal Peyser19dda252017-01-11 23:37:05 +00001089 /**
gregce64c36e12017-07-26 23:48:56 +02001090 * Applies the given transition to all incoming edges for this rule class.
Cal Peyser19dda252017-01-11 23:37:05 +00001091 *
gregce74a895d2018-05-29 11:26:03 -07001092 * <p>This cannot be a {@link SplitTransition} because that requires coordination with the
John Caterb3b3e8b2019-04-03 09:18:42 -07001093 * rule's parent: use {@link Attribute.Builder#cfg(TransitionFactory)} on the parent to declare
1094 * splits.
gregce74a895d2018-05-29 11:26:03 -07001095 *
jcater98a09b62019-04-02 13:06:19 -07001096 * <p>If you need the transition to depend on the rule it's being applied to, use {@link
John Caterb3b3e8b2019-04-03 09:18:42 -07001097 * #cfg(TransitionFactory)}.
Cal Peyser19dda252017-01-11 23:37:05 +00001098 */
mstaib860975a2018-04-26 15:00:52 -07001099 public Builder cfg(PatchTransition transition) {
John Caterb3b3e8b2019-04-03 09:18:42 -07001100 return cfg((TransitionFactory<Rule>) (unused) -> (transition));
Michael Staib2a675202017-03-20 18:06:48 +00001101 }
1102
gregce64c36e12017-07-26 23:48:56 +02001103 /**
1104 * Applies the given transition factory to all incoming edges for this rule class.
1105 *
John Cateree45c662018-06-05 11:09:01 -07001106 * <p>Unlike {@link #cfg(PatchTransition)}, the factory can examine the rule when deciding what
1107 * transition to use.
gregce64c36e12017-07-26 23:48:56 +02001108 */
John Caterb3b3e8b2019-04-03 09:18:42 -07001109 public Builder cfg(TransitionFactory<Rule> transitionFactory) {
Michael Staib2a675202017-03-20 18:06:48 +00001110 Preconditions.checkState(type != RuleClassType.ABSTRACT,
1111 "Setting not inherited property (cfg) of abstract rule class '%s'", name);
gregcef19fcfe2017-06-02 16:04:07 -04001112 Preconditions.checkState(this.transitionFactory == null,
Michael Staib2a675202017-03-20 18:06:48 +00001113 "Property cfg has already been set");
1114 Preconditions.checkNotNull(transitionFactory);
John Caterb3b3e8b2019-04-03 09:18:42 -07001115 Preconditions.checkArgument(!transitionFactory.isSplit());
Michael Staib2a675202017-03-20 18:06:48 +00001116 this.transitionFactory = transitionFactory;
Cal Peyser19dda252017-01-11 23:37:05 +00001117 return this;
1118 }
1119
juliexxia30976d82019-03-12 10:59:26 -07001120 public void setHasStarlarkRuleTransition() {
1121 hasStarlarkRuleTransition = true;
1122 }
1123
1124 public boolean hasStarlarkRuleTransition() {
1125 return hasStarlarkRuleTransition;
1126 }
1127
cparsonse2d200f2018-03-06 16:15:11 -08001128 public Builder factory(ConfiguredTargetFactory<?, ?, ?> factory) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001129 this.configuredTargetFactory = factory;
1130 return this;
1131 }
1132
gregce4aa059a2019-02-26 13:20:47 -08001133 public Builder setThirdPartyLicenseExistencePolicy(ThirdPartyLicenseExistencePolicy policy) {
1134 this.thirdPartyLicenseExistencePolicy = policy;
1135 return this;
1136 }
1137
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001138 public Builder setValidityPredicate(PredicateWithMessage<Rule> predicate) {
1139 this.validityPredicate = predicate;
1140 return this;
1141 }
1142
1143 public Builder setPreferredDependencyPredicate(Predicate<String> predicate) {
1144 this.preferredDependencyPredicate = predicate;
1145 return this;
1146 }
1147
1148 /**
1149 * State that the rule class being built possibly supplies the specified provider to its direct
1150 * dependencies.
1151 *
1152 * <p>When computing the set of aspects required for a rule, only the providers listed here are
1153 * considered. The presence of a provider here does not mean that the rule <b>must</b> implement
1154 * said provider, merely that it <b>can</b>. After the configured target is constructed from
1155 * this rule, aspects will be filtered according to the set of actual providers.
1156 *
1157 * <p>This is here so that we can do the loading phase overestimation required for
1158 * "blaze query", which does not have the configured targets available.
1159 *
1160 * <p>It's okay for the rule class eventually not to supply it (possibly based on analysis phase
1161 * logic), but if a provider is not advertised but is supplied, aspects that require the it will
1162 * not be evaluated for the rule.
1163 */
1164 public Builder advertiseProvider(Class<?>... providers) {
Dmitry Lomovb91d3922017-01-09 20:12:57 +00001165 for (Class<?> provider : providers) {
1166 advertisedProviders.addNative(provider);
1167 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001168 return this;
1169 }
1170
gregce74d84d42020-04-17 10:02:03 -07001171 public Builder advertiseStarlarkProvider(StarlarkProviderIdentifier... starlarkProviders) {
1172 for (StarlarkProviderIdentifier starlarkProviderIdentifier : starlarkProviders) {
gregced7c1cef2020-05-12 07:51:48 -07001173 advertisedProviders.addStarlark(starlarkProviderIdentifier);
elenairinaaeb21bc2017-09-27 12:13:52 -04001174 }
1175 return this;
1176 }
1177
Lukacs Berki549bfce2016-04-22 15:29:12 +00001178 /**
1179 * Set if the rule can have any provider. This is true for "alias" rules like
1180 * <code>bind</code> .
1181 */
1182 public Builder canHaveAnyProvider() {
Dmitry Lomovb91d3922017-01-09 20:12:57 +00001183 advertisedProviders.canHaveAnyProvider();
Lukacs Berki549bfce2016-04-22 15:29:12 +00001184 return this;
1185 }
1186
Jakob Buchgraber4f499822020-04-14 10:29:34 -07001187 /**
1188 * Adds an attribute to the builder.
1189 *
1190 * <p>Throws an IllegalStateException if an attribute of that name already exists.
1191 *
1192 * <p>TODO(bazel-team): stop using unchecked exceptions in this way.
1193 */
dbabkina2823422018-05-02 02:42:53 -07001194 public Builder addAttribute(Attribute attribute) {
Jakob Buchgraber4f499822020-04-14 10:29:34 -07001195 Attribute prevVal = attributes.putIfAbsent(attribute.getName(), attribute);
1196 if (prevVal != null) {
1197 throw new IllegalStateException(
1198 String.format(
1199 "There is already a built-in attribute '%s' which cannot be overridden.",
1200 attribute.getName()));
1201 }
dbabkina2823422018-05-02 02:42:53 -07001202 return this;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001203 }
1204
1205 private void overrideAttribute(Attribute attribute) {
1206 String attrName = attribute.getName();
1207 Preconditions.checkState(attributes.containsKey(attrName),
1208 "No such attribute '%s' to override in ruleclass '%s'.", attrName, name);
1209 Type<?> origType = attributes.get(attrName).getType();
1210 Type<?> newType = attribute.getType();
1211 Preconditions.checkState(origType.equals(newType),
1212 "The type of the new attribute '%s' is different from the original one '%s'.",
1213 newType, origType);
1214 attributes.put(attrName, attribute);
1215 }
1216
1217 /**
michajlob839a512020-03-11 10:04:23 -07001218 * Builds provided attribute and attaches it to this rule class.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001219 *
michajlob839a512020-03-11 10:04:23 -07001220 * <p>Typically rule classes should only declare a handful of attributes - this expectation is
1221 * enforced when the instance is built.
michajlo0a89cef2020-04-06 12:04:12 -07001222 *
1223 * <p>Attribute names should be meaningful but short; overly long names are rejected at
1224 * instantiation.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001225 */
1226 public <TYPE> Builder add(Attribute.Builder<TYPE> attr) {
1227 addAttribute(attr.build());
1228 return this;
1229 }
1230
1231 /**
1232 * Builds attribute from the attribute builder and overrides the attribute
1233 * with the same name.
1234 *
1235 * @throws IllegalArgumentException if the attribute does not override one of the same name
1236 */
1237 public <TYPE> Builder override(Attribute.Builder<TYPE> attr) {
1238 overrideAttribute(attr.build());
1239 return this;
1240 }
1241
1242 /**
gregcead752cc2020-04-10 10:32:59 -07001243 * Adds or overrides the attribute in the rule class. Meant for Starlark usage.
Florian Weikerte96b0b82015-09-25 11:35:11 +00001244 *
1245 * @throws IllegalArgumentException if the attribute overrides an existing attribute (will be
gregcead752cc2020-04-10 10:32:59 -07001246 * legal in the future).
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001247 */
1248 public void addOrOverrideAttribute(Attribute attribute) {
Florian Weikerte96b0b82015-09-25 11:35:11 +00001249 String name = attribute.getName();
1250 // Attributes may be overridden in the future.
1251 Preconditions.checkArgument(!attributes.containsKey(name),
1252 "There is already a built-in attribute '%s' which cannot be overridden", name);
1253 addAttribute(attribute);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001254 }
1255
Mark Schaller4fa83ac2015-07-10 16:59:37 +00001256 /** True if the rule class contains an attribute named {@code name}. */
1257 public boolean contains(String name) {
1258 return attributes.containsKey(name);
1259 }
1260
gregcead752cc2020-04-10 10:32:59 -07001261 /** Sets the rule implementation function. Meant for Starlark usage. */
adonovanc568d842020-04-14 09:20:01 -07001262 public Builder setConfiguredTargetFunction(StarlarkCallable func) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001263 this.configuredTargetFunction = func;
1264 return this;
1265 }
1266
juliexxia1f332e02018-10-31 14:20:55 -07001267 public Builder setBuildSetting(BuildSetting buildSetting) {
1268 this.buildSetting = buildSetting;
1269 return this;
1270 }
1271
Lukacs Berki0e1a9942015-06-18 08:53:18 +00001272 public Builder setExternalBindingsFunction(Function<? super Rule, Map<String, Label>> func) {
1273 this.externalBindingsFunction = func;
1274 return this;
1275 }
1276
John Cater39401a92020-07-09 10:12:55 -07001277 public Builder setToolchainsToRegisterFunction(
1278 Function<? super Rule, ? extends List<String>> func) {
1279 this.toolchainsToRegisterFunction = func;
1280 return this;
1281 }
1282
adonovan1d93d262020-05-07 14:50:42 -07001283 /**
1284 * Sets the rule definition environment label and transitive digest. Meant for Starlark usage.
1285 */
1286 public Builder setRuleDefinitionEnvironmentLabelAndDigest(Label label, byte[] digest) {
janakrd3fe5e72018-03-30 12:49:12 -07001287 this.ruleDefinitionEnvironmentLabel = Preconditions.checkNotNull(label, this.name);
adonovan1d93d262020-05-07 14:50:42 -07001288 this.ruleDefinitionEnvironmentDigest = Preconditions.checkNotNull(digest, this.name);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001289 return this;
1290 }
1291
juliexxia84d1a662018-12-26 14:07:04 -08001292 public Label getRuleDefinitionEnvironmentLabel() {
1293 return this.ruleDefinitionEnvironmentLabel;
1294 }
1295
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001296 /**
1297 * Removes an attribute with the same name from this rule class.
1298 *
1299 * @throws IllegalArgumentException if the attribute with this name does
1300 * not exist
1301 */
1302 public <TYPE> Builder removeAttribute(String name) {
1303 Preconditions.checkState(attributes.containsKey(name), "No such attribute '%s' to remove.",
1304 name);
1305 attributes.remove(name);
1306 return this;
1307 }
1308
1309 /**
gregcead752cc2020-04-10 10:32:59 -07001310 * This rule class outputs a default executable for every rule with the same name as the
1311 * rules's. Only works for Starlark.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001312 */
gregce74d84d42020-04-17 10:02:03 -07001313 public <TYPE> Builder setExecutableStarlark() {
1314 this.isExecutableStarlark = true;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001315 return this;
1316 }
1317
cparsons55781c92018-10-17 12:03:08 -07001318 /** This rule class is marked as an analysis test. */
1319 public Builder setIsAnalysisTest() {
1320 this.isAnalysisTest = true;
1321 return this;
1322 }
1323
juliexxia84d1a662018-12-26 14:07:04 -08001324 public boolean isAnalysisTest() {
1325 return this.isAnalysisTest;
1326 }
1327
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001328 /**
cparsons9d40c6b2019-02-25 12:24:40 -08001329 * This rule class has at least one attribute with an analysis test transition. (A
1330 * starlark-defined transition using analysis_test_transition()).
1331 */
1332 public Builder setHasAnalysisTestTransition() {
1333 this.hasAnalysisTestTransition = true;
1334 return this;
1335 }
1336
cparsons9d40c6b2019-02-25 12:24:40 -08001337 /**
aiuto50226ac2020-06-14 21:28:27 -07001338 * This rule class has the _allowlist_function_transition attribute. Intended only for Starlark
Googlerc2200fd2018-09-14 17:35:59 -07001339 * rules.
1340 */
aiuto50226ac2020-06-14 21:28:27 -07001341 public <TypeT> Builder setHasFunctionTransitionAllowlist() {
1342 this.hasFunctionTransitionAllowlist = true;
Googlerc2200fd2018-09-14 17:35:59 -07001343 return this;
1344 }
1345
gregce1d8d6dd2019-04-10 09:27:34 -07001346 /**
1347 * This rule class never declares a license regardless of what the rule's or package's <code>
1348 * licenses</code> attribute says.
1349 */
1350 // TODO(b/130286108): remove the licenses attribute completely from such rules.
1351 public Builder setIgnoreLicenses() {
1352 this.ignoreLicenses = true;
Googlerfdb17eb2019-01-28 15:14:32 -08001353 return this;
1354 }
1355
juliexxia84d1a662018-12-26 14:07:04 -08001356 public RuleClassType getType() {
1357 return this.type;
1358 }
1359
Googlerc2200fd2018-09-14 17:35:59 -07001360 /**
Dmitry Lomov5b1ce4d2018-05-30 04:34:08 -07001361 * Sets the kind of output files this rule creates.
1362 * DO NOT USE! This only exists to support the non-open-sourced {@code fileset} rule.
1363 * {@see OutputFile.Kind}.
1364 */
1365 public Builder setOutputFileKind(OutputFile.Kind outputFileKind) {
nharmata0d493ba2019-01-07 11:06:44 -08001366 this.outputFileKind = Preconditions.checkNotNull(outputFileKind);
Dmitry Lomov5b1ce4d2018-05-30 04:34:08 -07001367 return this;
1368 }
1369
1370
1371
1372 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001373 * Declares that instances of this rule are compatible with the specified environments,
1374 * in addition to the defaults declared by their environment groups. This can be overridden
1375 * by rule-specific declarations. See
1376 * {@link com.google.devtools.build.lib.analysis.constraints.ConstraintSemantics} for details.
1377 */
1378 public <TYPE> Builder compatibleWith(Label... environments) {
gregce614dc502017-12-20 17:24:46 -08001379 add(
1380 attr(DEFAULT_COMPATIBLE_ENVIRONMENT_ATTR, LABEL_LIST)
1381 .value(ImmutableList.copyOf(environments)));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001382 return this;
1383 }
1384
1385 /**
1386 * Declares that instances of this rule are restricted to the specified environments, i.e.
1387 * these override the defaults declared by their environment groups. This can be overridden
1388 * by rule-specific declarations. See
1389 * {@link com.google.devtools.build.lib.analysis.constraints.ConstraintSemantics} for details.
1390 *
1391 * <p>The input list cannot be empty.
1392 */
1393 public <TYPE> Builder restrictedTo(Label firstEnvironment, Label... otherEnvironments) {
1394 ImmutableList<Label> environments = ImmutableList.<Label>builder().add(firstEnvironment)
1395 .add(otherEnvironments).build();
gregce614dc502017-12-20 17:24:46 -08001396 add(
1397 attr(DEFAULT_RESTRICTED_ENVIRONMENT_ATTR, LABEL_LIST)
1398 .value(environments));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001399 return this;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001400 }
1401
1402 /**
Greg Estrenc04c88f2015-03-06 19:45:50 +00001403 * Exempts rules of this type from the constraint enforcement system. This should only be
1404 * applied to rules that are intrinsically incompatible with constraint checking (any
1405 * application of this method weakens the reach and strength of the system).
1406 *
1407 * @param reason user-informative message explaining the reason for exemption (not used)
1408 */
1409 public <TYPE> Builder exemptFromConstraintChecking(String reason) {
1410 Preconditions.checkState(this.supportsConstraintChecking);
1411 this.supportsConstraintChecking = false;
Greg Estren2ffc4fe2015-06-02 19:40:41 +00001412 attributes.remove(RuleClass.COMPATIBLE_ENVIRONMENT_ATTR);
1413 attributes.remove(RuleClass.RESTRICTED_ENVIRONMENT_ATTR);
Greg Estrenc04c88f2015-03-06 19:45:50 +00001414 return this;
1415 }
1416
1417 /**
mstaibe5538ad2017-04-04 18:32:23 +00001418 * Causes rules of this type to implicitly reference the configuration fragments associated with
1419 * the options its attributes reference.
1420 *
1421 * <p>This is only intended for use by {@code config_setting} - other rules should not use this!
1422 */
1423 public Builder setOptionReferenceFunctionForConfigSettingOnly(
1424 Function<? super Rule, ? extends Set<String>> optionReferenceFunction) {
1425 this.optionReferenceFunction = Preconditions.checkNotNull(optionReferenceFunction);
1426 return this;
1427 }
1428
John Cateree45c662018-06-05 11:09:01 -07001429 /**
1430 * Causes rules of this type to require the specified toolchains be available via toolchain
1431 * resolution when a target is configured.
1432 */
John Cater9a8d16e2017-07-05 16:12:07 -04001433 public Builder addRequiredToolchains(Iterable<Label> toolchainLabels) {
1434 Iterables.addAll(this.requiredToolchains, toolchainLabels);
John Catereca28402017-05-17 21:44:12 +02001435 return this;
1436 }
1437
John Cateree45c662018-06-05 11:09:01 -07001438 /**
1439 * Causes rules of this type to require the specified toolchains be available via toolchain
1440 * resolution when a target is configured.
1441 */
cpeyserd852e482017-09-07 22:16:06 +02001442 public Builder addRequiredToolchains(Label... toolchainLabels) {
John Cateree45c662018-06-05 11:09:01 -07001443 return this.addRequiredToolchains(Lists.newArrayList(toolchainLabels));
1444 }
1445
1446 /**
juliexxia5aab7502020-06-12 12:09:25 -07001447 * Adds execution groups to this rule class. Errors out if multiple different groups with the
1448 * same name are added.
juliexxia693048d2020-04-01 06:41:42 -07001449 */
juliexxiaadd1ddb2020-06-19 09:34:09 -07001450 public Builder addExecGroups(Map<String, ExecGroup> execGroups) {
juliexxia693048d2020-04-01 06:41:42 -07001451 for (Map.Entry<String, ExecGroup> group : execGroups.entrySet()) {
1452 String name = group.getKey();
juliexxia5aab7502020-06-12 12:09:25 -07001453 if (this.execGroups.containsKey(name)) {
1454 // If trying to add a new execution group with the same name as a execution group that
1455 // already exists, check if they are equivalent and error out if not.
1456 ExecGroup existingGroup = this.execGroups.get(name);
1457 ExecGroup newGroup = group.getValue();
1458 if (!existingGroup.equals(newGroup)) {
1459 throw new DuplicateExecGroupError(name);
1460 }
1461 } else {
1462 this.execGroups.put(name, group.getValue());
juliexxia693048d2020-04-01 06:41:42 -07001463 }
1464 }
1465 return this;
1466 }
1467
juliexxiaadd1ddb2020-06-19 09:34:09 -07001468 /**
1469 * Adds an exec group that is empty. During {@code build()} this will be replaced by an exec
1470 * group that inherits its toolchains and constraints from the rule.
1471 */
1472 public Builder addExecGroup(String name) {
1473 return addExecGroups(ImmutableMap.of(name, EMPTY_EXEC_GROUP));
1474 }
1475
juliexxia693048d2020-04-01 06:41:42 -07001476 /** An error to help report {@link ExecGroup}s with the same name */
juliexxiaadd1ddb2020-06-19 09:34:09 -07001477 static class DuplicateExecGroupError extends RuntimeException {
juliexxia693048d2020-04-01 06:41:42 -07001478 private final String duplicateGroup;
1479
1480 DuplicateExecGroupError(String duplicateGroup) {
juliexxiaadd1ddb2020-06-19 09:34:09 -07001481 super(String.format("Multiple execution groups with the same name: '%s'.", duplicateGroup));
juliexxia693048d2020-04-01 06:41:42 -07001482 this.duplicateGroup = duplicateGroup;
1483 }
1484
1485 String getDuplicateGroup() {
1486 return duplicateGroup;
1487 }
1488 }
1489
1490 /**
jcater01bb1f92019-06-17 12:09:11 -07001491 * Causes rules to use toolchain resolution to determine the execution platform and toolchains.
1492 * Rules that are part of configuring toolchains and platforms should set this to {@code false}.
John Cateree45c662018-06-05 11:09:01 -07001493 */
jcater01bb1f92019-06-17 12:09:11 -07001494 public Builder useToolchainResolution(boolean flag) {
1495 this.useToolchainResolution = flag;
cpeyserd852e482017-09-07 22:16:06 +02001496 return this;
1497 }
1498
John Cater099cf2f2020-06-11 12:58:36 -07001499 public Builder useToolchainTransition(boolean flag) {
1500 this.useToolchainTransition = flag;
1501 return this;
1502 }
1503
John Cateree45c662018-06-05 11:09:01 -07001504 /**
John Cateree45c662018-06-05 11:09:01 -07001505 * Adds additional execution platform constraints that apply for all targets from this rule.
1506 *
1507 * <p>Please note that this value is inherited by child rules.
1508 */
1509 public Builder addExecutionPlatformConstraints(Label... constraints) {
1510 return this.addExecutionPlatformConstraints(Lists.newArrayList(constraints));
1511 }
1512
1513 /**
1514 * Adds additional execution platform constraints that apply for all targets from this rule.
1515 *
1516 * <p>Please note that this value is inherited by child rules.
1517 */
1518 public Builder addExecutionPlatformConstraints(Iterable<Label> constraints) {
1519 Iterables.addAll(this.executionPlatformConstraints, constraints);
John Cater856b4dd2017-11-21 08:06:16 -08001520 return this;
1521 }
1522
mstaibe5538ad2017-04-04 18:32:23 +00001523 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001524 * Returns an Attribute.Builder object which contains a replica of the
1525 * same attribute in the parent rule if exists.
1526 *
1527 * @param name the name of the attribute
1528 */
1529 public Attribute.Builder<?> copy(String name) {
1530 Preconditions.checkArgument(attributes.containsKey(name),
1531 "Attribute %s does not exist in parent rule class.", name);
1532 return attributes.get(name).cloneBuilder();
1533 }
1534 }
1535
1536 private final String name; // e.g. "cc_library"
adonovanebb86fc2020-03-20 14:57:54 -07001537 private final ImmutableList<StarlarkThread.CallStackEntry> callstack; // of call to 'rule'
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001538
gregcead752cc2020-04-10 10:32:59 -07001539 private final String key; // Just the name for native, label + name for Starlark
tomlu72642a22017-10-18 06:23:14 +02001540
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001541 /**
1542 * The kind of target represented by this RuleClass (e.g. "cc_library rule").
1543 * Note: Even though there is partial duplication with the {@link RuleClass#name} field,
1544 * we want to store this as a separate field instead of generating it on demand in order to
1545 * avoid string duplication.
1546 */
1547 private final String targetKind;
1548
janakr6ff110e2018-03-21 21:44:27 -07001549 private final RuleClassType type;
gregce74d84d42020-04-17 10:02:03 -07001550 private final boolean isStarlark;
1551 private final boolean starlarkTestable;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001552 private final boolean documented;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001553 private final boolean binaryOutput;
1554 private final boolean workspaceOnly;
gregce74d84d42020-04-17 10:02:03 -07001555 private final boolean isExecutableStarlark;
cparsons55781c92018-10-17 12:03:08 -07001556 private final boolean isAnalysisTest;
cparsons9d40c6b2019-02-25 12:24:40 -08001557 private final boolean hasAnalysisTestTransition;
aiuto50226ac2020-06-14 21:28:27 -07001558 private final boolean hasFunctionTransitionAllowlist;
gregce1d8d6dd2019-04-10 09:27:34 -07001559 private final boolean ignoreLicenses;
ulfjack5756b352020-01-23 04:53:22 -08001560 private final boolean hasAspects;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001561
1562 /**
1563 * A (unordered) mapping from attribute names to small integers indexing into
1564 * the {@code attributes} array.
1565 */
Miguel Alcon Pintod7795f42015-10-23 21:55:52 +00001566 private final Map<String, Integer> attributeIndex;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001567
1568 /**
1569 * All attributes of this rule class (including inherited ones) ordered by
1570 * attributeIndex value.
1571 */
Eric Fellheimera954fae2015-08-27 19:37:52 +00001572 private final ImmutableList<Attribute> attributes;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001573
Michajlo Matijkiwcdd5b0e2015-12-09 18:17:44 +00001574 /** Names of the non-configurable attributes of this rule class. */
1575 private final ImmutableList<String> nonConfigurableAttributes;
1576
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001577 /**
1578 * The set of implicit outputs generated by a rule, expressed as a function
1579 * of that rule.
1580 */
1581 private final ImplicitOutputsFunction implicitOutputsFunction;
1582
1583 /**
Michael Staib2a675202017-03-20 18:06:48 +00001584 * A factory which will produce a configuration transition that should be applied on any edge of
1585 * the configured target graph that leads into a target of this rule class.
Cal Peyser19dda252017-01-11 23:37:05 +00001586 */
John Caterb3b3e8b2019-04-03 09:18:42 -07001587 private final TransitionFactory<Rule> transitionFactory;
Cal Peyser19dda252017-01-11 23:37:05 +00001588
cparsonse2d200f2018-03-06 16:15:11 -08001589 /** The factory that creates configured targets from this rule. */
1590 private final ConfiguredTargetFactory<?, ?, ?> configuredTargetFactory;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001591
1592 /**
1593 * The constraint the package name of the rule instance must fulfill
1594 */
1595 private final PredicateWithMessage<Rule> validityPredicate;
1596
1597 /**
1598 * See {@link #isPreferredDependency}.
1599 */
1600 private final Predicate<String> preferredDependencyPredicate;
1601
1602 /**
1603 * The list of transitive info providers this class advertises to aspects.
1604 */
Dmitry Lomovb91d3922017-01-09 20:12:57 +00001605 private final AdvertisedProviderSet advertisedProviders;
Lukacs Berki549bfce2016-04-22 15:29:12 +00001606
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001607 /**
gregcead752cc2020-04-10 10:32:59 -07001608 * The Starlark rule implementation of this RuleClass. Null for non Starlark executable
1609 * RuleClasses.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001610 */
adonovanc568d842020-04-14 09:20:01 -07001611 @Nullable private final StarlarkCallable configuredTargetFunction;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001612
1613 /**
gregcead752cc2020-04-10 10:32:59 -07001614 * The BuildSetting associated with this rule. Null for all RuleClasses except Starlark-defined
juliexxia1f332e02018-10-31 14:20:55 -07001615 * rules that pass {@code build_setting} to their {@code rule()} declaration.
1616 */
1617 @Nullable private final BuildSetting buildSetting;
1618
1619 /**
Lukacs Berki0e1a9942015-06-18 08:53:18 +00001620 * Returns the extra bindings a workspace function adds to the WORKSPACE file.
1621 */
1622 private final Function<? super Rule, Map<String, Label>> externalBindingsFunction;
1623
John Cater39401a92020-07-09 10:12:55 -07001624 /** Returns the toolchains a workspace function wants to have registered in the WORKSPACE file. */
1625 private final Function<? super Rule, ? extends List<String>> toolchainsToRegisterFunction;
1626
Lukacs Berki0e1a9942015-06-18 08:53:18 +00001627 /**
mstaibe5538ad2017-04-04 18:32:23 +00001628 * Returns the options referenced by this rule's attributes.
1629 */
1630 private final Function<? super Rule, ? extends Set<String>> optionReferenceFunction;
1631
1632 /**
gregcead752cc2020-04-10 10:32:59 -07001633 * The Starlark rule definition environment's label and hash code of this RuleClass. Null for non
1634 * Starlark executable RuleClasses.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001635 */
janakrd3fe5e72018-03-30 12:49:12 -07001636 @Nullable private final Label ruleDefinitionEnvironmentLabel;
1637
adonovan1d93d262020-05-07 14:50:42 -07001638 @Nullable private final byte[] ruleDefinitionEnvironmentDigest;
Dmitry Lomov5b1ce4d2018-05-30 04:34:08 -07001639 private final OutputFile.Kind outputFileKind;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001640
1641 /**
Michael Staibb51251e2015-09-29 23:31:51 +00001642 * The set of configuration fragments which are legal for this rule's implementation to access.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001643 */
Michael Staibb51251e2015-09-29 23:31:51 +00001644 private final ConfigurationFragmentPolicy configurationFragmentPolicy;
Greg Estrenc04c88f2015-03-06 19:45:50 +00001645
1646 /**
1647 * Determines whether instances of this rule should be checked for constraint compatibility
1648 * with their dependencies and the rules that depend on them. This should be true for
1649 * everything except for rules that are intrinsically incompatible with the constraint system.
1650 */
1651 private final boolean supportsConstraintChecking;
1652
gregce4aa059a2019-02-26 13:20:47 -08001653 private final ThirdPartyLicenseExistencePolicy thirdPartyLicenseExistencePolicy;
1654
cpeyserfb829992017-09-07 17:17:03 +02001655 private final ImmutableSet<Label> requiredToolchains;
jcater01bb1f92019-06-17 12:09:11 -07001656 private final boolean useToolchainResolution;
John Cater099cf2f2020-06-11 12:58:36 -07001657 private final boolean useToolchainTransition;
John Cateree45c662018-06-05 11:09:01 -07001658 private final ImmutableSet<Label> executionPlatformConstraints;
juliexxia693048d2020-04-01 06:41:42 -07001659 private final ImmutableMap<String, ExecGroup> execGroups;
John Catereca28402017-05-17 21:44:12 +02001660
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001661 /**
John Catereca28402017-05-17 21:44:12 +02001662 * Constructs an instance of RuleClass whose name is 'name', attributes are 'attributes'. The
1663 * {@code srcsAllowedFiles} determines which types of files are allowed as parameters to the
1664 * "srcs" attribute; rules are always allowed. For the "deps" attribute, there are four cases:
1665 *
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001666 * <ul>
John Catereca28402017-05-17 21:44:12 +02001667 * <li>if the parameter is a file, it is allowed if its file type is given in {@code
1668 * depsAllowedFiles},
1669 * <li>if the parameter is a rule and the rule class is accepted by {@code depsAllowedRules},
1670 * then it is allowed,
1671 * <li>if the parameter is a rule and the rule class is not accepted by {@code
1672 * depsAllowedRules}, but accepted by {@code depsAllowedRulesWithWarning}, then it is
1673 * allowed, but triggers a warning;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001674 * <li>all other parameters trigger an error.
1675 * </ul>
1676 *
John Catereca28402017-05-17 21:44:12 +02001677 * <p>The {@code depsAllowedRules} predicate should have a {@code toString} method which returns a
1678 * plain English enumeration of the allowed rule class names, if it does not allow all rule
1679 * classes.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001680 */
1681 @VisibleForTesting
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +00001682 RuleClass(
1683 String name,
adonovanebb86fc2020-03-20 14:57:54 -07001684 ImmutableList<StarlarkThread.CallStackEntry> callstack,
tomlu72642a22017-10-18 06:23:14 +02001685 String key,
janakr6ff110e2018-03-21 21:44:27 -07001686 RuleClassType type,
gregce74d84d42020-04-17 10:02:03 -07001687 boolean isStarlark,
1688 boolean starlarkTestable,
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +00001689 boolean documented,
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +00001690 boolean binaryOutput,
1691 boolean workspaceOnly,
gregce74d84d42020-04-17 10:02:03 -07001692 boolean isExecutableStarlark,
cparsons55781c92018-10-17 12:03:08 -07001693 boolean isAnalysisTest,
cparsons9d40c6b2019-02-25 12:24:40 -08001694 boolean hasAnalysisTestTransition,
aiuto50226ac2020-06-14 21:28:27 -07001695 boolean hasFunctionTransitionAllowlist,
gregce1d8d6dd2019-04-10 09:27:34 -07001696 boolean ignoreLicenses,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001697 ImplicitOutputsFunction implicitOutputsFunction,
John Caterb3b3e8b2019-04-03 09:18:42 -07001698 TransitionFactory<Rule> transitionFactory,
cparsonse2d200f2018-03-06 16:15:11 -08001699 ConfiguredTargetFactory<?, ?, ?> configuredTargetFactory,
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +00001700 PredicateWithMessage<Rule> validityPredicate,
1701 Predicate<String> preferredDependencyPredicate,
Dmitry Lomovb91d3922017-01-09 20:12:57 +00001702 AdvertisedProviderSet advertisedProviders,
adonovanc568d842020-04-14 09:20:01 -07001703 @Nullable StarlarkCallable configuredTargetFunction,
Lukacs Berki0e1a9942015-06-18 08:53:18 +00001704 Function<? super Rule, Map<String, Label>> externalBindingsFunction,
John Cater39401a92020-07-09 10:12:55 -07001705 Function<? super Rule, ? extends List<String>> toolchainsToRegisterFunction,
mstaibe5538ad2017-04-04 18:32:23 +00001706 Function<? super Rule, ? extends Set<String>> optionReferenceFunction,
janakrd3fe5e72018-03-30 12:49:12 -07001707 @Nullable Label ruleDefinitionEnvironmentLabel,
adonovan1d93d262020-05-07 14:50:42 -07001708 @Nullable byte[] ruleDefinitionEnvironmentDigest,
Michael Staibb51251e2015-09-29 23:31:51 +00001709 ConfigurationFragmentPolicy configurationFragmentPolicy,
Greg Estrenc04c88f2015-03-06 19:45:50 +00001710 boolean supportsConstraintChecking,
gregce4aa059a2019-02-26 13:20:47 -08001711 ThirdPartyLicenseExistencePolicy thirdPartyLicenseExistencePolicy,
cpeyserfb829992017-09-07 17:17:03 +02001712 Set<Label> requiredToolchains,
jcater01bb1f92019-06-17 12:09:11 -07001713 boolean useToolchainResolution,
John Cater099cf2f2020-06-11 12:58:36 -07001714 boolean useToolchainTransition,
John Cateree45c662018-06-05 11:09:01 -07001715 Set<Label> executionPlatformConstraints,
juliexxia693048d2020-04-01 06:41:42 -07001716 Map<String, ExecGroup> execGroups,
cparsons55781c92018-10-17 12:03:08 -07001717 OutputFile.Kind outputFileKind,
juliexxia1f332e02018-10-31 14:20:55 -07001718 Collection<Attribute> attributes,
1719 @Nullable BuildSetting buildSetting) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001720 this.name = name;
adonovanebb86fc2020-03-20 14:57:54 -07001721 this.callstack = callstack;
tomlu72642a22017-10-18 06:23:14 +02001722 this.key = key;
janakr6ff110e2018-03-21 21:44:27 -07001723 this.type = type;
gregce74d84d42020-04-17 10:02:03 -07001724 this.isStarlark = isStarlark;
Googlerb448eef2017-05-02 21:50:24 +02001725 this.targetKind = name + Rule.targetKindSuffix();
gregce74d84d42020-04-17 10:02:03 -07001726 this.starlarkTestable = starlarkTestable;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001727 this.documented = documented;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001728 this.binaryOutput = binaryOutput;
1729 this.implicitOutputsFunction = implicitOutputsFunction;
Michael Staib2a675202017-03-20 18:06:48 +00001730 this.transitionFactory = transitionFactory;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001731 this.configuredTargetFactory = configuredTargetFactory;
1732 this.validityPredicate = validityPredicate;
1733 this.preferredDependencyPredicate = preferredDependencyPredicate;
1734 this.advertisedProviders = advertisedProviders;
1735 this.configuredTargetFunction = configuredTargetFunction;
Lukacs Berki0e1a9942015-06-18 08:53:18 +00001736 this.externalBindingsFunction = externalBindingsFunction;
John Cater39401a92020-07-09 10:12:55 -07001737 this.toolchainsToRegisterFunction = toolchainsToRegisterFunction;
mstaibe5538ad2017-04-04 18:32:23 +00001738 this.optionReferenceFunction = optionReferenceFunction;
janakrd3fe5e72018-03-30 12:49:12 -07001739 this.ruleDefinitionEnvironmentLabel = ruleDefinitionEnvironmentLabel;
adonovan1d93d262020-05-07 14:50:42 -07001740 this.ruleDefinitionEnvironmentDigest = ruleDefinitionEnvironmentDigest;
Dmitry Lomov5b1ce4d2018-05-30 04:34:08 -07001741 this.outputFileKind = outputFileKind;
Dmitry Lomov94387c22015-12-08 16:30:06 +00001742 validateNoClashInPublicNames(attributes);
Eric Fellheimera954fae2015-08-27 19:37:52 +00001743 this.attributes = ImmutableList.copyOf(attributes);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001744 this.workspaceOnly = workspaceOnly;
gregce74d84d42020-04-17 10:02:03 -07001745 this.isExecutableStarlark = isExecutableStarlark;
cparsons55781c92018-10-17 12:03:08 -07001746 this.isAnalysisTest = isAnalysisTest;
cparsons9d40c6b2019-02-25 12:24:40 -08001747 this.hasAnalysisTestTransition = hasAnalysisTestTransition;
aiuto50226ac2020-06-14 21:28:27 -07001748 this.hasFunctionTransitionAllowlist = hasFunctionTransitionAllowlist;
gregce1d8d6dd2019-04-10 09:27:34 -07001749 this.ignoreLicenses = ignoreLicenses;
Michael Staibb51251e2015-09-29 23:31:51 +00001750 this.configurationFragmentPolicy = configurationFragmentPolicy;
Greg Estrenc04c88f2015-03-06 19:45:50 +00001751 this.supportsConstraintChecking = supportsConstraintChecking;
gregce4aa059a2019-02-26 13:20:47 -08001752 this.thirdPartyLicenseExistencePolicy = thirdPartyLicenseExistencePolicy;
cpeyserfb829992017-09-07 17:17:03 +02001753 this.requiredToolchains = ImmutableSet.copyOf(requiredToolchains);
jcater01bb1f92019-06-17 12:09:11 -07001754 this.useToolchainResolution = useToolchainResolution;
John Cater099cf2f2020-06-11 12:58:36 -07001755 this.useToolchainTransition = useToolchainTransition;
John Cateree45c662018-06-05 11:09:01 -07001756 this.executionPlatformConstraints = ImmutableSet.copyOf(executionPlatformConstraints);
juliexxia693048d2020-04-01 06:41:42 -07001757 this.execGroups = ImmutableMap.copyOf(execGroups);
juliexxia1f332e02018-10-31 14:20:55 -07001758 this.buildSetting = buildSetting;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001759
Michajlo Matijkiwcdd5b0e2015-12-09 18:17:44 +00001760 // Create the index and collect non-configurable attributes.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001761 int index = 0;
ulfjack5756b352020-01-23 04:53:22 -08001762 attributeIndex = Maps.newHashMapWithExpectedSize(attributes.size());
1763 boolean computedHasAspects = false;
Michajlo Matijkiwcdd5b0e2015-12-09 18:17:44 +00001764 ImmutableList.Builder<String> nonConfigurableAttributesBuilder = ImmutableList.builder();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001765 for (Attribute attribute : attributes) {
ulfjack5756b352020-01-23 04:53:22 -08001766 computedHasAspects |= attribute.hasAspects();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001767 attributeIndex.put(attribute.getName(), index++);
Michajlo Matijkiwcdd5b0e2015-12-09 18:17:44 +00001768 if (!attribute.isConfigurable()) {
1769 nonConfigurableAttributesBuilder.add(attribute.getName());
1770 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001771 }
ulfjack5756b352020-01-23 04:53:22 -08001772 this.hasAspects = computedHasAspects;
Michajlo Matijkiwcdd5b0e2015-12-09 18:17:44 +00001773 this.nonConfigurableAttributes = nonConfigurableAttributesBuilder.build();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001774 }
1775
janakrd3fe5e72018-03-30 12:49:12 -07001776 private void validateNoClashInPublicNames(Iterable<Attribute> attributes) {
Dmitry Lomov94387c22015-12-08 16:30:06 +00001777 Map<String, Attribute> publicToPrivateNames = new HashMap<>();
1778 for (Attribute attribute : attributes) {
1779 String publicName = attribute.getPublicName();
1780 if (publicToPrivateNames.containsKey(publicName)) {
1781 throw new IllegalStateException(
1782 String.format(
1783 "Rule %s: Attributes %s and %s have an identical public name: %s",
1784 name,
1785 attribute.getName(),
1786 publicToPrivateNames.get(publicName).getName(),
1787 publicName));
1788 }
1789 publicToPrivateNames.put(publicName, attribute);
1790 }
1791 }
1792
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001793 /**
Michajlo Matijkiw6d471412016-08-09 20:35:45 +00001794 * Returns the default function for determining the set of implicit outputs generated by a given
adonovan920b0932020-06-29 10:26:36 -07001795 * rule. If not otherwise specified, this will be the implementation used by {@link Rule}s created
1796 * with this {@link RuleClass}.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001797 *
adonovan920b0932020-06-29 10:26:36 -07001798 * <p>Do not use this value to calculate implicit outputs for a rule, instead use {@link
1799 * Rule#getImplicitOutputsFunction()}.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001800 *
Michajlo Matijkiw6d471412016-08-09 20:35:45 +00001801 * <p>An implicit output is an OutputFile that automatically comes into existence when a rule of
1802 * this class is declared, and whose name is derived from the name of the rule.
1803 *
1804 * <p>Implicit outputs are a widely-relied upon. All ".so", and "_deploy.jar" targets referenced
1805 * in BUILD files are examples.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001806 */
adonovan920b0932020-06-29 10:26:36 -07001807 // (public for serialization)
Michajlo Matijkiw6d471412016-08-09 20:35:45 +00001808 public ImplicitOutputsFunction getDefaultImplicitOutputsFunction() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001809 return implicitOutputsFunction;
1810 }
1811
John Caterb3b3e8b2019-04-03 09:18:42 -07001812 public TransitionFactory<Rule> getTransitionFactory() {
Michael Staib2a675202017-03-20 18:06:48 +00001813 return transitionFactory;
Cal Peyser19dda252017-01-11 23:37:05 +00001814 }
1815
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001816 @SuppressWarnings("unchecked")
cparsonse2d200f2018-03-06 16:15:11 -08001817 public <CT, RC, ACE extends Throwable>
1818 ConfiguredTargetFactory<CT, RC, ACE> getConfiguredTargetFactory() {
1819 return (ConfiguredTargetFactory<CT, RC, ACE>) configuredTargetFactory;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001820 }
1821
1822 /**
1823 * Returns the class of rule that this RuleClass represents (e.g. "cc_library").
1824 */
1825 public String getName() {
1826 return name;
1827 }
1828
adonovanebb86fc2020-03-20 14:57:54 -07001829 /**
1830 * Returns the stack of Starlark active function calls at the moment this rule class was created.
1831 * Entries appear outermost first, and exclude the built-in itself ('rule' or 'repository_rule').
1832 * Empty for non-Starlark rules.
1833 */
1834 public ImmutableList<StarlarkThread.CallStackEntry> getCallStack() {
1835 return callstack;
1836 }
1837
janakr6ff110e2018-03-21 21:44:27 -07001838 /** Returns the type of rule that this RuleClass represents. Only for use during serialization. */
1839 public RuleClassType getRuleClassType() {
1840 return type;
1841 }
1842
tomlu72642a22017-10-18 06:23:14 +02001843 /** Returns a unique key. Used for profiling purposes. */
1844 public String getKey() {
1845 return key;
1846 }
1847
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001848 /**
1849 * Returns the target kind of this class of rule (e.g. "cc_library rule").
1850 */
1851 String getTargetKind() {
1852 return targetKind;
1853 }
1854
1855 public boolean getWorkspaceOnly() {
1856 return workspaceOnly;
1857 }
1858
1859 /**
1860 * Returns true iff the attribute 'attrName' is defined for this rule class,
1861 * and has type 'type'.
1862 */
1863 public boolean hasAttr(String attrName, Type<?> type) {
1864 Integer index = getAttributeIndex(attrName);
1865 return index != null && getAttribute(index).getType() == type;
1866 }
1867
1868 /**
1869 * Returns the index of the specified attribute name. Use of indices allows
1870 * space-efficient storage of attribute values in rules, since hashtables are
1871 * not required. (The index mapping is specific to each RuleClass and an
1872 * attribute may have a different index in the parent RuleClass.)
1873 *
1874 * <p>Returns null if the named attribute is not defined for this class of Rule.
1875 */
1876 Integer getAttributeIndex(String attrName) {
1877 return attributeIndex.get(attrName);
1878 }
1879
1880 /**
1881 * Returns the attribute whose index is 'attrIndex'. Fails if attrIndex is
1882 * not in range.
1883 */
1884 Attribute getAttribute(int attrIndex) {
Eric Fellheimera954fae2015-08-27 19:37:52 +00001885 return attributes.get(attrIndex);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001886 }
1887
1888 /**
Michajlo Matijkiw0446c952015-10-28 19:59:00 +00001889 * Returns the attribute whose name is 'attrName'; fails with NullPointerException if not found.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001890 */
1891 public Attribute getAttributeByName(String attrName) {
Michajlo Matijkiw0446c952015-10-28 19:59:00 +00001892 Integer attrIndex = Preconditions.checkNotNull(getAttributeIndex(attrName),
1893 "Attribute %s does not exist", attrName);
1894 return attributes.get(attrIndex);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001895 }
1896
1897 /**
1898 * Returns the attribute whose name is {@code attrName}, or null if not
1899 * found.
1900 */
1901 Attribute getAttributeByNameMaybe(String attrName) {
1902 Integer i = getAttributeIndex(attrName);
Eric Fellheimera954fae2015-08-27 19:37:52 +00001903 return i == null ? null : attributes.get(i);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001904 }
1905
1906 /**
1907 * Returns the number of attributes defined for this rule class.
1908 */
1909 public int getAttributeCount() {
1910 return attributeIndex.size();
1911 }
1912
1913 /**
1914 * Returns an (immutable) list of all Attributes defined for this class of
1915 * rule, ordered by increasing index.
1916 */
1917 public List<Attribute> getAttributes() {
Eric Fellheimera954fae2015-08-27 19:37:52 +00001918 return attributes;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001919 }
1920
Michajlo Matijkiwcdd5b0e2015-12-09 18:17:44 +00001921 /** Returns set of non-configurable attribute names defined for this class of rule. */
1922 public List<String> getNonConfigurableAttributes() {
1923 return nonConfigurableAttributes;
1924 }
1925
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001926 public PredicateWithMessage<Rule> getValidityPredicate() {
1927 return validityPredicate;
1928 }
1929
1930 /**
1931 * Returns the set of advertised transitive info providers.
1932 *
1933 * <p>When computing the set of aspects required for a rule, only the providers listed here are
1934 * considered. The presence of a provider here does not mean that the rule <b>must</b> implement
1935 * said provider, merely that it <b>can</b>. After the configured target is constructed from this
1936 * rule, aspects will be filtered according to the set of actual providers.
1937 *
1938 * <p>This is here so that we can do the loading phase overestimation required for "blaze query",
1939 * which does not have the configured targets available.
Dmitry Lomovb91d3922017-01-09 20:12:57 +00001940 **/
1941 public AdvertisedProviderSet getAdvertisedProviders() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001942 return advertisedProviders;
1943 }
Lukacs Berki549bfce2016-04-22 15:29:12 +00001944 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001945 * For --compile_one_dependency: if multiple rules consume the specified target,
1946 * should we choose this one over the "unpreferred" options?
1947 */
1948 public boolean isPreferredDependency(String filename) {
1949 return preferredDependencyPredicate.apply(filename);
1950 }
1951
1952 /**
Michael Staibb51251e2015-09-29 23:31:51 +00001953 * Returns this rule's policy for configuration fragment access.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001954 */
Michael Staibb51251e2015-09-29 23:31:51 +00001955 public ConfigurationFragmentPolicy getConfigurationFragmentPolicy() {
1956 return configurationFragmentPolicy;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001957 }
1958
1959 /**
Greg Estrenc04c88f2015-03-06 19:45:50 +00001960 * Returns true if rules of this type can be used with the constraint enforcement system.
1961 */
1962 public boolean supportsConstraintChecking() {
1963 return supportsConstraintChecking;
1964 }
1965
ulfjack5756b352020-01-23 04:53:22 -08001966 public boolean hasAspects() {
1967 return hasAspects;
1968 }
1969
Greg Estrenc04c88f2015-03-06 19:45:50 +00001970 /**
Mark Schalleree624452016-01-13 18:41:24 +00001971 * Creates a new {@link Rule} {@code r} where {@code r.getPackage()} is the {@link Package}
1972 * associated with {@code pkgBuilder}.
1973 *
1974 * <p>The created {@link Rule} will be populated with attribute values from {@code
1975 * attributeValues} or the default attribute values associated with this {@link RuleClass} and
1976 * {@code pkgBuilder}.
1977 *
Florian Weikertea6c82d2016-09-05 12:15:31 +00001978 * <p>The created {@link Rule} will also be populated with output files. These output files will
1979 * have been collected from the explicitly provided values of type {@link BuildType#OUTPUT} and
1980 * {@link BuildType#OUTPUT_LIST} as well as from the implicit outputs determined by this {@link
1981 * RuleClass} and the values in {@code attributeValues}.
Mark Schalleree624452016-01-13 18:41:24 +00001982 *
1983 * <p>This performs several validity checks. Invalid output file labels result in a thrown {@link
Florian Weikertea6c82d2016-09-05 12:15:31 +00001984 * LabelSyntaxException}. Computed default attributes that fail during precomputation result in a
1985 * {@link CannotPrecomputeDefaultsException}. All other errors are reported on {@code
1986 * eventHandler}.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001987 */
nharmata65a173a2017-08-07 16:11:04 +02001988 <T> Rule createRule(
Mark Schalleree624452016-01-13 18:41:24 +00001989 Package.Builder pkgBuilder,
1990 Label ruleLabel,
nharmata65a173a2017-08-07 16:11:04 +02001991 AttributeValues<T> attributeValues,
Mark Schalleree624452016-01-13 18:41:24 +00001992 EventHandler eventHandler,
Mark Schalleree624452016-01-13 18:41:24 +00001993 Location location,
adonovan40a737c2020-03-11 14:32:19 -07001994 List<StarlarkThread.CallStackEntry> callstack,
Greg Estren37cd5c42019-01-30 12:25:50 -08001995 boolean checkThirdPartyRulesHaveLicenses)
Florian Weikertea6c82d2016-09-05 12:15:31 +00001996 throws LabelSyntaxException, InterruptedException, CannotPrecomputeDefaultsException {
adonovan920b0932020-06-29 10:26:36 -07001997 Rule rule =
1998 pkgBuilder.createRule(ruleLabel, this, location, callstack, new AttributeContainer(this));
twerth54a4e082020-04-28 01:39:48 -07001999 populateRuleAttributeValues(rule, pkgBuilder, attributeValues, eventHandler);
Michajlo Matijkiw581f2c22016-07-25 20:12:16 +00002000 checkAspectAllowedValues(rule, eventHandler);
2001 rule.populateOutputFiles(eventHandler, pkgBuilder);
Michajlo Matijkiw581f2c22016-07-25 20:12:16 +00002002 checkForDuplicateLabels(rule, eventHandler);
gregce4aa059a2019-02-26 13:20:47 -08002003
2004 boolean actuallyCheckLicense;
2005 if (thirdPartyLicenseExistencePolicy == ThirdPartyLicenseExistencePolicy.ALWAYS_CHECK) {
2006 actuallyCheckLicense = true;
2007 } else if (thirdPartyLicenseExistencePolicy == ThirdPartyLicenseExistencePolicy.NEVER_CHECK) {
2008 actuallyCheckLicense = false;
2009 } else {
2010 actuallyCheckLicense = checkThirdPartyRulesHaveLicenses;
2011 }
2012
2013 if (actuallyCheckLicense) {
Greg Estren37cd5c42019-01-30 12:25:50 -08002014 checkThirdPartyRuleHasLicense(rule, pkgBuilder, eventHandler);
2015 }
Michajlo Matijkiw581f2c22016-07-25 20:12:16 +00002016 checkForValidSizeAndTimeoutValues(rule, eventHandler);
2017 rule.checkValidityPredicate(eventHandler);
Nathan Harmatacf738442016-06-28 14:52:21 +00002018 rule.checkForNullLabels();
2019 return rule;
2020 }
2021
2022 /**
2023 * Same as {@link #createRule}, except without some internal sanity checks.
2024 *
2025 * <p>Don't call this function unless you know what you're doing.
2026 */
nharmata65a173a2017-08-07 16:11:04 +02002027 <T> Rule createRuleUnchecked(
Nathan Harmatacf738442016-06-28 14:52:21 +00002028 Package.Builder pkgBuilder,
2029 Label ruleLabel,
nharmata65a173a2017-08-07 16:11:04 +02002030 AttributeValues<T> attributeValues,
Nathan Harmatacf738442016-06-28 14:52:21 +00002031 Location location,
adonovan40a737c2020-03-11 14:32:19 -07002032 List<StarlarkThread.CallStackEntry> callstack,
Michajlo Matijkiw6d471412016-08-09 20:35:45 +00002033 ImplicitOutputsFunction implicitOutputsFunction)
nharmata59c16f62017-08-07 19:49:09 +02002034 throws InterruptedException, CannotPrecomputeDefaultsException {
adonovan40a737c2020-03-11 14:32:19 -07002035 Rule rule =
adonovan920b0932020-06-29 10:26:36 -07002036 pkgBuilder.createRule(ruleLabel, this, location, callstack, implicitOutputsFunction);
twerth54a4e082020-04-28 01:39:48 -07002037 populateRuleAttributeValues(rule, pkgBuilder, attributeValues, NullEventHandler.INSTANCE);
nharmata59c16f62017-08-07 19:49:09 +02002038 rule.populateOutputFilesUnchecked(NullEventHandler.INSTANCE, pkgBuilder);
Mark Schalleree624452016-01-13 18:41:24 +00002039 return rule;
2040 }
2041
2042 /**
2043 * Populates the attributes table of the new {@link Rule} with the values in the {@code
2044 * attributeValues} map and with default values provided by this {@link RuleClass} and the {@code
2045 * pkgBuilder}.
2046 *
2047 * <p>Errors are reported on {@code eventHandler}.
2048 */
nharmata65a173a2017-08-07 16:11:04 +02002049 private <T> void populateRuleAttributeValues(
Mark Schalleree624452016-01-13 18:41:24 +00002050 Rule rule,
twerth54a4e082020-04-28 01:39:48 -07002051 Package.Builder pkgBuilder,
nharmata65a173a2017-08-07 16:11:04 +02002052 AttributeValues<T> attributeValues,
Florian Weikertea6c82d2016-09-05 12:15:31 +00002053 EventHandler eventHandler)
2054 throws InterruptedException, CannotPrecomputeDefaultsException {
adonovan920b0932020-06-29 10:26:36 -07002055
2056 // TODO(b/157751486): opt: optimize attribute representation.
2057 //
2058 // Conceptually, the attribute values of a rule instance are a mapping
2059 // from each attribute name to its value plus a boolean indicating
2060 // whether it was set explicitly, equivalent to a table of triples:
2061 //
2062 // (Attribute attr, Object value, bool explicit)
2063 //
2064 // (Attributes may be represented by name, Attribute reference, or by
2065 // a small integer, because the RuleClass provides constant-time
2066 // conversions between all three.)
2067 //
2068 // Empirically, about half of all rule attribute values are equal to
2069 // the default value trivially provided by the RuleClass.
2070 // To save space, don't record these values; instead, record only the
2071 // explicitly provided ones, plus those whose defaults were non-trivially
2072 // computed. (Because of the latter category, we must record the
2073 // 'explicit' boolean.)
2074 //
2075 // One possible representation would be an Object[] array of length
2076 // n, for the values sorted by ascending index, and a byte[] of length
2077 // n bytes + n bits, the bytes being the indices and the bits being
2078 // the 'explicit' flags. Lookup would require binary search over
2079 // the bytes.
2080 //
2081 // Currently, the attributes are queried even as they are under
2082 // construction (see checkAllowedValues), but that check could be moved after table
2083 // construction, like
2084 // checkForDuplicateLabels.
2085
Mark Schalleree624452016-01-13 18:41:24 +00002086 BitSet definedAttrIndices =
dannarkf24479d2018-06-21 11:55:44 -07002087 populateDefinedRuleAttributeValues(
twerth54a4e082020-04-28 01:39:48 -07002088 rule,
2089 pkgBuilder.getRepositoryMapping(),
2090 attributeValues,
2091 pkgBuilder.getListInterner(),
2092 eventHandler);
2093 populateDefaultRuleAttributeValues(rule, pkgBuilder, definedAttrIndices, eventHandler);
Mark Schalleree624452016-01-13 18:41:24 +00002094 // Now that all attributes are bound to values, collect and store configurable attribute keys.
2095 populateConfigDependenciesAttribute(rule);
2096 }
2097
2098 /**
2099 * Populates the attributes table of the new {@link Rule} with the values in the {@code
2100 * attributeValues} map.
2101 *
2102 * <p>Handles the special cases of the attribute named {@code "name"} and attributes with value
Googler641bdf72019-11-12 10:32:26 -08002103 * {@link Starlark#NONE}.
Mark Schalleree624452016-01-13 18:41:24 +00002104 *
dannarkf24479d2018-06-21 11:55:44 -07002105 * <p>Returns a bitset {@code b} where {@code b.get(i)} is {@code true} if this method set a value
2106 * for the attribute with index {@code i} in this {@link RuleClass}. Errors are reported on {@code
2107 * eventHandler}.
Mark Schalleree624452016-01-13 18:41:24 +00002108 */
nharmata65a173a2017-08-07 16:11:04 +02002109 private <T> BitSet populateDefinedRuleAttributeValues(
dannarkf24479d2018-06-21 11:55:44 -07002110 Rule rule,
2111 ImmutableMap<RepositoryName, RepositoryName> repositoryMapping,
2112 AttributeValues<T> attributeValues,
nharmataf3e99412019-01-28 10:06:29 -08002113 Interner<ImmutableList<?>> listInterner,
dannarkf24479d2018-06-21 11:55:44 -07002114 EventHandler eventHandler) {
Mark Schalleree624452016-01-13 18:41:24 +00002115 BitSet definedAttrIndices = new BitSet();
nharmata65a173a2017-08-07 16:11:04 +02002116 for (T attributeAccessor : attributeValues.getAttributeAccessors()) {
2117 String attributeName = attributeValues.getName(attributeAccessor);
2118 Object attributeValue = attributeValues.getValue(attributeAccessor);
Mark Schalleree624452016-01-13 18:41:24 +00002119 // Ignore all None values.
Googler641bdf72019-11-12 10:32:26 -08002120 if (attributeValue == Starlark.NONE) {
Mark Schalleree624452016-01-13 18:41:24 +00002121 continue;
2122 }
2123
2124 // Check that the attribute's name belongs to a valid attribute for this rule class.
2125 Integer attrIndex = getAttributeIndex(attributeName);
2126 if (attrIndex == null) {
2127 rule.reportError(
2128 String.format(
2129 "%s: no such attribute '%s' in '%s' rule", rule.getLabel(), attributeName, name),
2130 eventHandler);
2131 continue;
2132 }
2133 Attribute attr = getAttribute(attrIndex);
2134
gregce1d8d6dd2019-04-10 09:27:34 -07002135 if (attributeName.equals("licenses") && ignoreLicenses) {
adonovan920b0932020-06-29 10:26:36 -07002136 rule.setAttributeValue(attr, License.NO_LICENSE, /*explicit=*/ false);
gregce1d8d6dd2019-04-10 09:27:34 -07002137 definedAttrIndices.set(attrIndex);
2138 continue;
2139 }
2140
Mark Schalleree624452016-01-13 18:41:24 +00002141 // Convert the build-lang value to a native value, if necessary.
2142 Object nativeAttributeValue;
2143 if (attributeValues.valuesAreBuildLanguageTyped()) {
2144 try {
dannarkf24479d2018-06-21 11:55:44 -07002145 nativeAttributeValue =
nharmataf3e99412019-01-28 10:06:29 -08002146 convertFromBuildLangType(rule, attr, attributeValue, repositoryMapping, listInterner);
Mark Schalleree624452016-01-13 18:41:24 +00002147 } catch (ConversionException e) {
2148 rule.reportError(String.format("%s: %s", rule.getLabel(), e.getMessage()), eventHandler);
2149 continue;
2150 }
2151 } else {
2152 nativeAttributeValue = attributeValue;
2153 }
2154
adonovan920b0932020-06-29 10:26:36 -07002155 // visibility is additionally recorded by rule.setVisibility.
2156 if (attr.getName().equals("visibility")) {
2157 @SuppressWarnings("unchecked")
2158 List<Label> vis = (List<Label>) nativeAttributeValue;
2159 if (!vis.isEmpty() && vis.get(0).equals(ConstantRuleVisibility.LEGACY_PUBLIC_LABEL)) {
2160 rule.reportError(
2161 rule.getLabel() + ": //visibility:legacy_public only allowed in package declaration",
2162 eventHandler);
2163 }
2164 try {
2165 rule.setVisibility(PackageUtils.getVisibility(rule.getLabel(), vis));
2166 } catch (EvalException e) {
2167 rule.reportError(rule.getLabel() + " " + e.getMessage(), eventHandler);
2168 }
2169 }
2170
nharmata65a173a2017-08-07 16:11:04 +02002171 boolean explicit = attributeValues.isExplicitlySpecified(attributeAccessor);
adonovan920b0932020-06-29 10:26:36 -07002172 rule.setAttributeValue(attr, nativeAttributeValue, explicit);
2173 checkAllowedValues(rule, attr, eventHandler);
Mark Schalleree624452016-01-13 18:41:24 +00002174 definedAttrIndices.set(attrIndex);
Mark Schalleree624452016-01-13 18:41:24 +00002175 }
2176 return definedAttrIndices;
2177 }
2178
Mark Schalleree624452016-01-13 18:41:24 +00002179 /**
2180 * Populates the attributes table of the new {@link Rule} with default values provided by this
Florian Weikertea6c82d2016-09-05 12:15:31 +00002181 * {@link RuleClass} and the {@code pkgBuilder}. This will only provide values for attributes that
2182 * haven't already been populated, using {@code definedAttrIndices} to determine whether an
Mark Schalleree624452016-01-13 18:41:24 +00002183 * attribute was populated.
2184 *
2185 * <p>Errors are reported on {@code eventHandler}.
2186 */
2187 private void populateDefaultRuleAttributeValues(
twerth54a4e082020-04-28 01:39:48 -07002188 Rule rule, Package.Builder pkgBuilder, BitSet definedAttrIndices, EventHandler eventHandler)
Florian Weikertea6c82d2016-09-05 12:15:31 +00002189 throws InterruptedException, CannotPrecomputeDefaultsException {
Mark Schalleree624452016-01-13 18:41:24 +00002190 // Set defaults; ensure that every mandatory attribute has a value. Use the default if none
2191 // is specified.
2192 List<Attribute> attrsWithComputedDefaults = new ArrayList<>();
2193 int numAttributes = getAttributeCount();
2194 for (int attrIndex = 0; attrIndex < numAttributes; ++attrIndex) {
2195 if (definedAttrIndices.get(attrIndex)) {
2196 continue;
2197 }
2198 Attribute attr = getAttribute(attrIndex);
2199 if (attr.isMandatory()) {
2200 rule.reportError(
2201 String.format(
2202 "%s: missing value for mandatory attribute '%s' in '%s' rule",
2203 rule.getLabel(),
2204 attr.getName(),
2205 name),
2206 eventHandler);
2207 }
2208
adonovan920b0932020-06-29 10:26:36 -07002209 // We must check both the name and the type of each attribute below in case a Starlark rule
2210 // defines a licenses or distributions attribute of another type.
2211
2212 if (attr.hasComputedDefault()) {
Mark Schalleree624452016-01-13 18:41:24 +00002213 // Note that it is necessary to set all non-computed default values before calling
2214 // Attribute#getDefaultValue for computed default attributes. Computed default attributes
2215 // may have a condition predicate (i.e. the predicate returned by Attribute#getCondition)
2216 // that depends on non-computed default attribute values, and that condition predicate is
2217 // evaluated by the call to Attribute#getDefaultValue.
2218 attrsWithComputedDefaults.add(attr);
adonovan920b0932020-06-29 10:26:36 -07002219
cparsonscaceacd2017-11-04 01:00:59 +01002220 } else if (attr.isLateBound()) {
2221 rule.setAttributeValue(attr, attr.getLateBoundDefault(), /*explicit=*/ false);
adonovan920b0932020-06-29 10:26:36 -07002222
2223 } else if (attr.getName().equals("applicable_licenses")
2224 && attr.getType() == BuildType.LICENSE) {
2225 // TODO(b/149505729): Determine the right semantics for someone trying to define their own
2226 // attribute named applicable_licenses.
2227 rule.setAttributeValue(
2228 attr, pkgBuilder.getDefaultApplicableLicenses(), /*explicit=*/ false);
2229
2230 } else if (attr.getName().equals("licenses") && attr.getType() == BuildType.LICENSE) {
2231 rule.setAttributeValue(
2232 attr,
2233 ignoreLicenses ? License.NO_LICENSE : pkgBuilder.getDefaultLicense(),
2234 /*explicit=*/ false);
2235
2236 } else if (attr.getName().equals("distribs") && attr.getType() == BuildType.DISTRIBUTIONS) {
2237 rule.setAttributeValue(attr, pkgBuilder.getDefaultDistribs(), /*explicit=*/ false);
2238
Mark Schalleree624452016-01-13 18:41:24 +00002239 } else {
adonovan920b0932020-06-29 10:26:36 -07002240 Object defaultValue = attr.getDefaultValue(/*rule=*/ null);
Mark Schalleree624452016-01-13 18:41:24 +00002241 rule.setAttributeValue(attr, defaultValue, /*explicit=*/ false);
2242 checkAllowedValues(rule, attr, eventHandler);
2243 }
2244 }
2245
nharmata40252c92020-07-07 19:38:40 -07002246 // An instance of the built-in 'test_suite' rule with an undefined or empty 'tests' attribute
2247 // attribute gets an '$implicit_tests' attribute, whose value is a shared per-package list of
2248 // all test labels, populated later.
adonovana46ad6e2020-06-29 14:33:24 -07002249 if (this.name.equals("test_suite")) {
2250 Attribute implicitTests = this.getAttributeByName("$implicit_tests");
nharmata40252c92020-07-07 19:38:40 -07002251 if (implicitTests != null
2252 && NonconfigurableAttributeMapper.of(rule).get("tests", BuildType.LABEL_LIST).isEmpty()) {
adonovana46ad6e2020-06-29 14:33:24 -07002253 boolean explicit = true; // so that it appears in query output
2254 rule.setAttributeValue(implicitTests, pkgBuilder.testSuiteImplicitTests, explicit);
2255 }
2256 }
2257
Mark Schalleree624452016-01-13 18:41:24 +00002258 // Set computed default attribute values now that all other (i.e. non-computed) default values
2259 // have been set.
2260 for (Attribute attr : attrsWithComputedDefaults) {
Florian Weikertea6c82d2016-09-05 12:15:31 +00002261 // If Attribute#hasComputedDefault was true above, Attribute#getDefaultValue returns the
gregcead752cc2020-04-10 10:32:59 -07002262 // computed default function object or a Starlark computed default template. Note that we
Florian Weikertea6c82d2016-09-05 12:15:31 +00002263 // cannot determine the exact value of the computed default function here because it may
2264 // depend on other attribute values that are configurable (i.e. they came from select({..})
2265 // expressions in the build language, and they require configuration data from the analysis
2266 // phase to be resolved). Instead, we're setting the attribute value to a reference to the
gregcead752cc2020-04-10 10:32:59 -07002267 // computed default function, or if #getDefaultValue is a Starlark computed default
gregceb100b1d2020-05-20 10:22:17 -07002268 // template, setting the attribute value to a reference to the StarlarkComputedDefault
2269 // returned from StarlarkComputedDefaultTemplate#computePossibleValues.
Florian Weikertea6c82d2016-09-05 12:15:31 +00002270 //
gregceb100b1d2020-05-20 10:22:17 -07002271 // StarlarkComputedDefaultTemplate#computePossibleValues pre-computes all possible values the
Florian Weikertea6c82d2016-09-05 12:15:31 +00002272 // function may evaluate to, and records them in a lookup table. By calling it here, with an
2273 // EventHandler, any errors that might occur during the function's evaluation can
2274 // be discovered and propagated here.
2275 Object valueToSet;
2276 Object defaultValue = attr.getDefaultValue(rule);
gregce18694cd2020-05-12 15:40:05 -07002277 if (defaultValue instanceof StarlarkComputedDefaultTemplate) {
2278 StarlarkComputedDefaultTemplate template = (StarlarkComputedDefaultTemplate) defaultValue;
Florian Weikertea6c82d2016-09-05 12:15:31 +00002279 valueToSet = template.computePossibleValues(attr, rule, eventHandler);
schmitta4080da92019-05-20 13:12:46 -07002280 } else if (defaultValue instanceof ComputedDefault) {
2281 // Compute all possible values to verify that the ComputedDefault is well-defined. This was
2282 // previously done implicitly as part of visiting all labels to check for null-ness in
2283 // Rule.checkForNullLabels, but that was changed to skip non-label attributes to improve
2284 // performance.
2285 ((ComputedDefault) defaultValue).getPossibleValues(attr.getType(), rule);
2286 valueToSet = defaultValue;
Florian Weikertea6c82d2016-09-05 12:15:31 +00002287 } else {
2288 valueToSet = defaultValue;
2289 }
2290 rule.setAttributeValue(attr, valueToSet, /*explicit=*/ false);
Mark Schalleree624452016-01-13 18:41:24 +00002291 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002292 }
2293
2294 /**
2295 * Collects all labels used as keys for configurable attributes and places them into
2296 * the special implicit attribute that tracks them.
2297 */
2298 private static void populateConfigDependenciesAttribute(Rule rule) {
2299 RawAttributeMapper attributes = RawAttributeMapper.of(rule);
gregce749962a2019-03-08 12:47:34 -08002300 Attribute configDepsAttribute =
2301 attributes.getAttributeDefinition(CONFIG_SETTING_DEPS_ATTRIBUTE);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002302 if (configDepsAttribute == null) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002303 return;
2304 }
2305
felly7615e1a2019-05-16 03:45:26 -07002306 LinkedHashSet<Label> configLabels = new LinkedHashSet<>();
2307 for (Attribute attr : rule.getAttributes()) {
2308 SelectorList<?> selectorList = attributes.getSelectorList(attr.getName(), attr.getType());
2309 if (selectorList != null) {
2310 configLabels.addAll(selectorList.getKeyLabels());
2311 }
2312 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002313
2314 rule.setAttributeValue(configDepsAttribute, ImmutableList.copyOf(configLabels),
2315 /*explicit=*/false);
2316 }
2317
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002318 /**
2319 * Report an error for each label that appears more than once in a LABEL_LIST attribute
2320 * of the given rule.
2321 *
2322 * @param rule The rule.
2323 * @param eventHandler The eventHandler to use to report the duplicated deps.
2324 */
2325 private static void checkForDuplicateLabels(Rule rule, EventHandler eventHandler) {
2326 for (Attribute attribute : rule.getAttributes()) {
Lukacs Berkiffa73ad2015-09-18 11:40:12 +00002327 if (attribute.getType() == BuildType.LABEL_LIST) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002328 checkForDuplicateLabels(rule, attribute, eventHandler);
2329 }
2330 }
2331 }
2332
2333 /**
2334 * Reports an error against the specified rule if it's beneath third_party
2335 * but does not have a declared license.
2336 */
2337 private static void checkThirdPartyRuleHasLicense(Rule rule,
Han-Wen Nienhuys086e5f22015-04-21 11:39:59 +00002338 Package.Builder pkgBuilder, EventHandler eventHandler) {
gregce1d8d6dd2019-04-10 09:27:34 -07002339 if (rule.getRuleClassObject().ignoreLicenses()) {
Googlerfdb17eb2019-01-28 15:14:32 -08002340 // A package license is sufficient; ignore rules that don't include it.
2341 return;
2342 }
Brian Silvermand7d6d622016-03-17 09:53:39 +00002343 if (isThirdPartyPackage(rule.getLabel().getPackageIdentifier())) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002344 License license = rule.getLicense();
2345 if (license == null) {
2346 license = pkgBuilder.getDefaultLicense();
2347 }
lberki0d8d4cf2017-09-05 16:01:44 +02002348 if (!license.isSpecified()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002349 rule.reportError("third-party rule '" + rule.getLabel() + "' lacks a license declaration "
2350 + "with one of the following types: notice, reciprocal, permissive, "
2351 + "restricted, unencumbered, by_exception_only",
2352 eventHandler);
2353 }
2354 }
2355 }
2356
2357 /**
2358 * Report an error for each label that appears more than once in the given attribute
2359 * of the given rule.
2360 *
2361 * @param rule The rule.
2362 * @param attribute The attribute to check. Must exist in rule and be of type LABEL_LIST.
2363 * @param eventHandler The eventHandler to use to report the duplicated deps.
2364 */
2365 private static void checkForDuplicateLabels(Rule rule, Attribute attribute,
2366 EventHandler eventHandler) {
Greg Estren14348c02015-04-16 16:26:19 +00002367 Set<Label> duplicates = AggregatingAttributeMapper.of(rule).checkForDuplicateLabels(attribute);
2368 for (Label label : duplicates) {
2369 rule.reportError(
2370 String.format("Label '%s' is duplicated in the '%s' attribute of rule '%s'",
2371 label, attribute.getName(), rule.getName()), eventHandler);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002372 }
2373 }
2374
2375 /**
2376 * Report an error if the rule has a timeout or size attribute that is not a
2377 * legal value. These attributes appear on all tests.
2378 *
2379 * @param rule the rule to check
2380 * @param eventHandler the eventHandler to use to report the duplicated deps
2381 */
2382 private static void checkForValidSizeAndTimeoutValues(Rule rule, EventHandler eventHandler) {
2383 if (rule.getRuleClassObject().hasAttr("size", Type.STRING)) {
2384 String size = NonconfigurableAttributeMapper.of(rule).get("size", Type.STRING);
2385 if (TestSize.getTestSize(size) == null) {
2386 rule.reportError(
2387 String.format("In rule '%s', size '%s' is not a valid size.", rule.getName(), size),
2388 eventHandler);
2389 }
2390 }
2391 if (rule.getRuleClassObject().hasAttr("timeout", Type.STRING)) {
2392 String timeout = NonconfigurableAttributeMapper.of(rule).get("timeout", Type.STRING);
2393 if (TestTimeout.getTestTimeout(timeout) == null) {
2394 rule.reportError(
2395 String.format(
2396 "In rule '%s', timeout '%s' is not a valid timeout.", rule.getName(), timeout),
2397 eventHandler);
2398 }
2399 }
2400 }
2401
2402 /**
Mark Schalleree624452016-01-13 18:41:24 +00002403 * Converts the build-language-typed {@code buildLangValue} to a native value via {@link
laurentlb1d273cd2018-05-16 12:12:26 -07002404 * BuildType#selectableConvert}. Canonicalizes the value's order if it is a {@link List} type and
2405 * {@code attr.isOrderIndependent()} returns {@code true}.
Mark Schalleree624452016-01-13 18:41:24 +00002406 *
laurentlb1d273cd2018-05-16 12:12:26 -07002407 * <p>Throws {@link ConversionException} if the conversion fails, or if {@code buildLangValue} is
2408 * a selector expression but {@code attr.isConfigurable()} is {@code false}.
Mark Schalleree624452016-01-13 18:41:24 +00002409 */
dannarkf24479d2018-06-21 11:55:44 -07002410 private static Object convertFromBuildLangType(
2411 Rule rule,
2412 Attribute attr,
2413 Object buildLangValue,
nharmataf3e99412019-01-28 10:06:29 -08002414 ImmutableMap<RepositoryName, RepositoryName> repositoryMapping,
2415 Interner<ImmutableList<?>> listInterner)
Mark Schalleree624452016-01-13 18:41:24 +00002416 throws ConversionException {
dannarkf24479d2018-06-21 11:55:44 -07002417 LabelConversionContext context = new LabelConversionContext(rule.getLabel(), repositoryMapping);
2418 Object converted =
2419 BuildType.selectableConvert(
2420 attr.getType(),
2421 buildLangValue,
2422 new AttributeConversionContext(attr.getName(), rule.getRuleClass()),
2423 context);
Mark Schalleree624452016-01-13 18:41:24 +00002424
2425 if ((converted instanceof SelectorList<?>) && !attr.isConfigurable()) {
2426 throw new ConversionException(
2427 String.format("attribute \"%s\" is not configurable", attr.getName()));
2428 }
2429
laurentlb1d273cd2018-05-16 12:12:26 -07002430 if (converted instanceof List<?>) {
Mark Schalleree624452016-01-13 18:41:24 +00002431 if (attr.isOrderIndependent()) {
2432 @SuppressWarnings("unchecked")
2433 List<? extends Comparable<?>> list = (List<? extends Comparable<?>>) converted;
2434 converted = Ordering.natural().sortedCopy(list);
2435 }
nharmataf3e99412019-01-28 10:06:29 -08002436 // It's common for multiple rule instances in the same package to have the same value for some
2437 // attributes. As a concrete example, consider a package having several 'java_test' instances,
2438 // each with the same exact 'tags' attribute value.
2439 converted = listInterner.intern(ImmutableList.copyOf((List<?>) converted));
Mark Schalleree624452016-01-13 18:41:24 +00002440 }
2441
2442 return converted;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002443 }
2444
Michael Staibff938b32015-08-27 19:22:59 +00002445 /**
Michajlo Matijkiw7b7fce12016-09-20 19:52:07 +00002446 * Provides a {@link #toString()} description of the attribute being converted for
2447 * {@link BuildType#selectableConvert}. This is preferred over a raw string to avoid uselessly
2448 * constructing strings which are never used. A separate class instead of inline to avoid
2449 * accidental memory leaks.
2450 */
2451 private static class AttributeConversionContext {
2452 private final String attrName;
2453 private final String ruleClass;
2454
2455 AttributeConversionContext(String attrName, String ruleClass) {
2456 this.attrName = attrName;
2457 this.ruleClass = ruleClass;
2458 }
2459
2460 @Override
2461 public String toString() {
2462 return "attribute '" + attrName + "' in '" + ruleClass + "' rule";
2463 }
2464 }
2465
Michajlo Matijkiw7b7fce12016-09-20 19:52:07 +00002466 /**
Michael Staibff938b32015-08-27 19:22:59 +00002467 * Verifies that the rule has a valid value for the attribute according to its allowed values.
2468 *
2469 * <p>If the value for the given attribute on the given rule is invalid, an error will be recorded
2470 * in the given EventHandler.
2471 *
2472 * <p>If the rule is configurable, all of its potential values are evaluated, and errors for each
2473 * of the invalid values are reported.
2474 */
Mark Schalleree624452016-01-13 18:41:24 +00002475 private static void checkAllowedValues(
2476 Rule rule, Attribute attribute, EventHandler eventHandler) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002477 if (attribute.checkAllowedValues()) {
2478 PredicateWithMessage<Object> allowedValues = attribute.getAllowedValues();
Michael Staibff938b32015-08-27 19:22:59 +00002479 Iterable<?> values =
2480 AggregatingAttributeMapper.of(rule).visitAttribute(
2481 attribute.getName(), attribute.getType());
2482 for (Object value : values) {
2483 if (!allowedValues.apply(value)) {
Mark Schalleree624452016-01-13 18:41:24 +00002484 rule.reportError(
2485 String.format(
2486 "%s: invalid value in '%s' attribute: %s",
2487 rule.getLabel(),
2488 attribute.getName(),
2489 allowedValues.getErrorReason(value)),
2490 eventHandler);
Michael Staibff938b32015-08-27 19:22:59 +00002491 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002492 }
2493 }
2494 }
2495
Googler74558fc2016-05-06 21:47:42 +00002496 private static void checkAspectAllowedValues(
2497 Rule rule, EventHandler eventHandler) {
ulfjack5756b352020-01-23 04:53:22 -08002498 if (rule.hasAspects()) {
2499 for (Attribute attrOfRule : rule.getAttributes()) {
2500 for (Aspect aspect : attrOfRule.getAspects(rule)) {
2501 for (Attribute attrOfAspect : aspect.getDefinition().getAttributes().values()) {
2502 // By this point the AspectDefinition has been created and values assigned.
2503 if (attrOfAspect.checkAllowedValues()) {
2504 PredicateWithMessage<Object> allowedValues = attrOfAspect.getAllowedValues();
2505 Object value = attrOfAspect.getDefaultValue(rule);
2506 if (!allowedValues.apply(value)) {
2507 if (RawAttributeMapper.of(rule).isConfigurable(attrOfAspect.getName())) {
2508 rule.reportError(
2509 String.format(
2510 "%s: attribute '%s' has a select() and aspect %s also declares "
2511 + "'%s'. Aspect attributes don't currently support select().",
2512 rule.getLabel(),
2513 attrOfAspect.getName(),
2514 aspect.getDefinition().getName(),
2515 rule.getLabel()),
2516 eventHandler);
2517 } else {
2518 rule.reportError(
2519 String.format(
2520 "%s: invalid value in '%s' attribute: %s",
2521 rule.getLabel(),
2522 attrOfAspect.getName(),
2523 allowedValues.getErrorReason(value)),
2524 eventHandler);
2525 }
gregce7deab0a2019-03-11 12:20:05 -07002526 }
Googler74558fc2016-05-06 21:47:42 +00002527 }
2528 }
2529 }
2530 }
2531 }
2532 }
2533
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002534 @Override
2535 public String toString() {
2536 return name;
2537 }
2538
2539 public boolean isDocumented() {
2540 return documented;
2541 }
2542
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002543 /**
2544 * Returns true iff the outputs of this rule should be created beneath the
2545 * <i>bin</i> directory, false if beneath <i>genfiles</i>. For most rule
2546 * classes, this is a constant, but for genrule, it is a property of the
2547 * individual rule instance, derived from the 'output_to_bindir' attribute;
2548 * see Rule.hasBinaryOutput().
2549 */
Laurent Le Brunc2efe452015-04-08 16:27:21 +00002550 @VisibleForTesting
2551 public boolean hasBinaryOutput() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002552 return binaryOutput;
2553 }
2554
gregcead752cc2020-04-10 10:32:59 -07002555 /** Returns this RuleClass's custom Starlark rule implementation. */
adonovanf3a344e82019-12-11 11:10:11 -08002556 @Nullable
adonovanc568d842020-04-14 09:20:01 -07002557 public StarlarkCallable getConfiguredTargetFunction() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002558 return configuredTargetFunction;
2559 }
2560
juliexxia1f332e02018-10-31 14:20:55 -07002561 @Nullable
2562 public BuildSetting getBuildSetting() {
2563 return buildSetting;
2564 }
2565
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002566 /**
Lukacs Berki0e1a9942015-06-18 08:53:18 +00002567 * Returns a function that computes the external bindings a repository function contributes to
2568 * the WORKSPACE file.
2569 */
2570 public Function<? super Rule, Map<String, Label>> getExternalBindingsFunction() {
2571 return externalBindingsFunction;
2572 }
2573
2574 /**
John Cater39401a92020-07-09 10:12:55 -07002575 * Returns a function that computes the toolchains that should be registered for a repository
2576 * function.
2577 *
2578 * @return
2579 */
2580 public Function<? super Rule, ? extends List<String>> getToolchainsToRegisterFunction() {
2581 return toolchainsToRegisterFunction;
2582 }
2583
2584 /**
mstaibe5538ad2017-04-04 18:32:23 +00002585 * Returns a function that computes the options referenced by a rule.
2586 */
2587 public Function<? super Rule, ? extends Set<String>> getOptionReferenceFunction() {
2588 return optionReferenceFunction;
2589 }
2590
2591 /**
gregcead752cc2020-04-10 10:32:59 -07002592 * For Starlark rule classes, returns this RuleClass's rule definition environment's label, which
janakrd3fe5e72018-03-30 12:49:12 -07002593 * is never null. Is null for native rules' RuleClass objects.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002594 */
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +00002595 @Nullable
janakrd3fe5e72018-03-30 12:49:12 -07002596 public Label getRuleDefinitionEnvironmentLabel() {
2597 return ruleDefinitionEnvironmentLabel;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002598 }
2599
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +00002600 /**
adonovan1d93d262020-05-07 14:50:42 -07002601 * Returns the digest for the RuleClass's rule definition environment, a hash of the .bzl file
2602 * defining the rule class and all the .bzl files it transitively loads. Null for native rules'
2603 * RuleClass objects.
ajurkowski77895612020-06-24 19:28:56 -07002604 *
2605 * <p>This digest is sensitive to any changes in the declaration of the RuleClass itself,
2606 * including changes in the .bzl files it transitively loads, but it is not unique: all
2607 * RuleClasses defined within in the same .bzl file have the same digest.
2608 *
2609 * <p>To uniquely identify a rule class, we need the triple: ({@link
2610 * #getRuleDefinitionEnvironmentLabel()}, {@link #getRuleDefinitionEnvironmentDigest()}, {@link
2611 * #getName()}) The first two components are collectively known as the "rule definition
2612 * environment". Dependency analysis may compare these triples to detect whether a change to a
2613 * rule definition might have consequences for a rule instance that has not otherwise changed.
2614 *
2615 * <p>Note: this concept of rule definition environment is not related to the {@link
2616 * com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment} interface.
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +00002617 */
2618 @Nullable
adonovan1d93d262020-05-07 14:50:42 -07002619 public byte[] getRuleDefinitionEnvironmentDigest() {
2620 return ruleDefinitionEnvironmentDigest;
Janak Ramakrishnan9b12f9c2016-05-20 16:33:02 +00002621 }
2622
gregcead752cc2020-04-10 10:32:59 -07002623 /** Returns true if this RuleClass is a Starlark-defined RuleClass. */
gregce74d84d42020-04-17 10:02:03 -07002624 public boolean isStarlark() {
2625 return isStarlark;
Michajlo Matijkiwbc042c62015-10-29 13:22:52 +00002626 }
2627
gregcead752cc2020-04-10 10:32:59 -07002628 /** Returns true if this RuleClass is Starlark-defined and is subject to analysis-time tests. */
gregce74d84d42020-04-17 10:02:03 -07002629 public boolean isStarlarkTestable() {
2630 return starlarkTestable;
Jon Brandveinead58ae2016-09-29 18:41:10 +00002631 }
2632
gregce74d84d42020-04-17 10:02:03 -07002633 /** Returns true if this rule class outputs a default executable for every rule. */
2634 public boolean isExecutableStarlark() {
2635 return isExecutableStarlark;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002636 }
Brian Silvermand7d6d622016-03-17 09:53:39 +00002637
cparsons55781c92018-10-17 12:03:08 -07002638 /** Returns true if this rule class is an analysis test (set by analysis_test = true). */
2639 public boolean isAnalysisTest() {
2640 return isAnalysisTest;
2641 }
2642
Googlerc2200fd2018-09-14 17:35:59 -07002643 /**
cparsons9d40c6b2019-02-25 12:24:40 -08002644 * Returns true if this rule class has at least one attribute with an analysis test transition. (A
2645 * starlark-defined transition using analysis_test_transition()).
2646 */
2647 public boolean hasAnalysisTestTransition() {
2648 return hasAnalysisTestTransition;
2649 }
2650
aiuto50226ac2020-06-14 21:28:27 -07002651 /** Returns true if this rule class has the _allowlist_function_transition attribute. */
2652 public boolean hasFunctionTransitionAllowlist() {
2653 return hasFunctionTransitionAllowlist;
Googlerc2200fd2018-09-14 17:35:59 -07002654 }
2655
gregce1d8d6dd2019-04-10 09:27:34 -07002656 /**
2657 * If true, no rule of this class ever declares a license regardless of what the rule's or
2658 * package's <code>licenses</code> attribute says.
2659 *
2660 * <p>This is useful for rule types that don't make sense for license checking.
2661 */
2662 public boolean ignoreLicenses() {
2663 return ignoreLicenses;
Googlerfdb17eb2019-01-28 15:14:32 -08002664 }
2665
cpeyserfb829992017-09-07 17:17:03 +02002666 public ImmutableSet<Label> getRequiredToolchains() {
John Catereca28402017-05-17 21:44:12 +02002667 return requiredToolchains;
2668 }
2669
jcater01bb1f92019-06-17 12:09:11 -07002670 public boolean useToolchainResolution() {
2671 return useToolchainResolution;
John Cater856b4dd2017-11-21 08:06:16 -08002672 }
2673
John Cater099cf2f2020-06-11 12:58:36 -07002674 public boolean useToolchainTransition() {
2675 return useToolchainTransition;
2676 }
2677
John Cateree45c662018-06-05 11:09:01 -07002678 public ImmutableSet<Label> getExecutionPlatformConstraints() {
2679 return executionPlatformConstraints;
2680 }
2681
juliexxia693048d2020-04-01 06:41:42 -07002682 public ImmutableMap<String, ExecGroup> getExecGroups() {
2683 return execGroups;
2684 }
2685
Dmitry Lomov5b1ce4d2018-05-30 04:34:08 -07002686 public OutputFile.Kind getOutputFileKind() {
2687 return outputFileKind;
2688 }
2689
Brian Silvermand7d6d622016-03-17 09:53:39 +00002690 public static boolean isThirdPartyPackage(PackageIdentifier packageIdentifier) {
2691 if (!packageIdentifier.getRepository().isMain()) {
2692 return false;
2693 }
2694
2695 if (!packageIdentifier.getPackageFragment().startsWith(THIRD_PARTY_PREFIX)) {
2696 return false;
2697 }
2698
2699 if (packageIdentifier.getPackageFragment().segmentCount() <= 1) {
2700 return false;
2701 }
2702
2703 return true;
2704 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002705}