Damien Martin-Guillerez | f88f4d8 | 2015-09-25 13:56:55 +0000 | [diff] [blame] | 1 | // Copyright 2014 The Bazel Authors. All rights reserved. |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 2 | // |
| 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 | |
| 15 | package com.google.devtools.build.lib.analysis; |
| 16 | |
| 17 | import static com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition.DATA; |
| 18 | import static com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition.HOST; |
| 19 | import static com.google.devtools.build.lib.packages.Attribute.attr; |
Lukacs Berki | ffa73ad | 2015-09-18 11:40:12 +0000 | [diff] [blame] | 20 | import static com.google.devtools.build.lib.packages.BuildType.DISTRIBUTIONS; |
| 21 | import static com.google.devtools.build.lib.packages.BuildType.LABEL; |
| 22 | import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST; |
| 23 | import static com.google.devtools.build.lib.packages.BuildType.LICENSE; |
| 24 | import static com.google.devtools.build.lib.packages.BuildType.NODEP_LABEL_LIST; |
| 25 | import static com.google.devtools.build.lib.syntax.Type.BOOLEAN; |
| 26 | import static com.google.devtools.build.lib.syntax.Type.INTEGER; |
| 27 | import static com.google.devtools.build.lib.syntax.Type.STRING; |
| 28 | import static com.google.devtools.build.lib.syntax.Type.STRING_LIST; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 29 | |
Carmi Grushko | eaaa9d0d | 2015-11-17 01:54:45 +0000 | [diff] [blame] | 30 | import com.google.common.annotations.VisibleForTesting; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 31 | import com.google.common.collect.ImmutableList; |
Ulf Adams | 37590dc | 2016-10-14 11:52:00 +0000 | [diff] [blame] | 32 | import com.google.common.collect.ImmutableSet; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 33 | import com.google.devtools.build.lib.analysis.config.BuildConfiguration; |
| 34 | import com.google.devtools.build.lib.analysis.config.RunUnder; |
| 35 | import com.google.devtools.build.lib.analysis.constraints.EnvironmentRule; |
Lukacs Berki | 6e91eb9 | 2015-09-21 09:12:37 +0000 | [diff] [blame] | 36 | import com.google.devtools.build.lib.cmdline.Label; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 37 | import com.google.devtools.build.lib.packages.Attribute; |
| 38 | import com.google.devtools.build.lib.packages.Attribute.LateBoundLabel; |
| 39 | import com.google.devtools.build.lib.packages.Attribute.LateBoundLabelList; |
| 40 | import com.google.devtools.build.lib.packages.AttributeMap; |
| 41 | import com.google.devtools.build.lib.packages.Rule; |
| 42 | import com.google.devtools.build.lib.packages.RuleClass; |
| 43 | import com.google.devtools.build.lib.packages.RuleClass.Builder; |
| 44 | import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType; |
| 45 | import com.google.devtools.build.lib.packages.TestSize; |
Lukacs Berki | ffa73ad | 2015-09-18 11:40:12 +0000 | [diff] [blame] | 46 | import com.google.devtools.build.lib.syntax.Type; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 47 | import com.google.devtools.build.lib.util.FileTypeSet; |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 48 | import java.util.List; |
| 49 | |
| 50 | /** |
| 51 | * Rule class definitions used by (almost) every rule. |
| 52 | */ |
| 53 | public class BaseRuleClasses { |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 54 | private static final Attribute.ComputedDefault testonlyDefault = |
| 55 | new Attribute.ComputedDefault() { |
| 56 | @Override |
| 57 | public Object getDefault(AttributeMap rule) { |
| 58 | return rule.getPackageDefaultTestOnly(); |
| 59 | } |
| 60 | }; |
| 61 | |
| 62 | private static final Attribute.ComputedDefault deprecationDefault = |
| 63 | new Attribute.ComputedDefault() { |
| 64 | @Override |
| 65 | public Object getDefault(AttributeMap rule) { |
| 66 | return rule.getPackageDefaultDeprecation(); |
| 67 | } |
| 68 | }; |
| 69 | |
| 70 | /** |
| 71 | * Implementation for the :action_listener attribute. |
| 72 | */ |
Carmi Grushko | eaaa9d0d | 2015-11-17 01:54:45 +0000 | [diff] [blame] | 73 | @VisibleForTesting |
| 74 | static final LateBoundLabelList<BuildConfiguration> ACTION_LISTENER = |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 75 | new LateBoundLabelList<BuildConfiguration>() { |
| 76 | @Override |
Lukacs Berki | 0dbe07f | 2016-04-19 10:22:08 +0000 | [diff] [blame] | 77 | public List<Label> resolve(Rule rule, AttributeMap attributes, |
Greg Estren | 33ec191 | 2016-02-10 15:57:58 +0000 | [diff] [blame] | 78 | BuildConfiguration configuration) { |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 79 | // action_listeners are special rules; they tell the build system to add extra_actions to |
| 80 | // existing rules. As such they need an edge to every ConfiguredTarget with the limitation |
| 81 | // that they only run on the target configuration and should not operate on action_listeners |
| 82 | // and extra_actions themselves (to avoid cycles). |
| 83 | return configuration.getActionListeners(); |
| 84 | } |
| 85 | }; |
| 86 | |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 87 | /** |
| 88 | * Implementation for the :run_under attribute. |
| 89 | */ |
Lukacs Berki | 8f460f3 | 2016-06-29 09:14:10 +0000 | [diff] [blame] | 90 | public static final LateBoundLabel<BuildConfiguration> RUN_UNDER = |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 91 | new LateBoundLabel<BuildConfiguration>() { |
| 92 | @Override |
Lukacs Berki | 0dbe07f | 2016-04-19 10:22:08 +0000 | [diff] [blame] | 93 | public Label resolve(Rule rule, AttributeMap attributes, |
Greg Estren | 33ec191 | 2016-02-10 15:57:58 +0000 | [diff] [blame] | 94 | BuildConfiguration configuration) { |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 95 | RunUnder runUnder = configuration.getRunUnder(); |
| 96 | return runUnder == null ? null : runUnder.getLabel(); |
| 97 | } |
| 98 | }; |
| 99 | |
| 100 | /** |
| 101 | * A base rule for all test rules. |
| 102 | */ |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 103 | public static final class TestBaseRule implements RuleDefinition { |
| 104 | @Override |
| 105 | public RuleClass build(Builder builder, RuleDefinitionEnvironment env) { |
| 106 | return builder |
| 107 | .add(attr("size", STRING).value("medium").taggable() |
| 108 | .nonconfigurable("policy decision: should be consistent across configurations")) |
| 109 | .add(attr("timeout", STRING).taggable() |
| 110 | .nonconfigurable("policy decision: should be consistent across configurations") |
| 111 | .value(new Attribute.ComputedDefault() { |
| 112 | @Override |
| 113 | public Object getDefault(AttributeMap rule) { |
| 114 | TestSize size = TestSize.getTestSize(rule.get("size", Type.STRING)); |
| 115 | if (size != null) { |
| 116 | String timeout = size.getDefaultTimeout().toString(); |
| 117 | if (timeout != null) { |
| 118 | return timeout; |
| 119 | } |
| 120 | } |
| 121 | return "illegal"; |
| 122 | } |
| 123 | })) |
| 124 | .add(attr("flaky", BOOLEAN).value(false).taggable() |
| 125 | .nonconfigurable("policy decision: should be consistent across configurations")) |
| 126 | .add(attr("shard_count", INTEGER).value(-1)) |
| 127 | .add(attr("local", BOOLEAN).value(false).taggable() |
| 128 | .nonconfigurable("policy decision: should be consistent across configurations")) |
Greg Estren | 547295a | 2016-08-18 22:01:29 +0000 | [diff] [blame] | 129 | .add(attr("args", STRING_LIST)) |
Lukacs Berki | 8f460f3 | 2016-06-29 09:14:10 +0000 | [diff] [blame] | 130 | // Input files for every test action |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 131 | .add(attr("$test_runtime", LABEL_LIST).cfg(HOST).value(ImmutableList.of( |
Luis Fernando Pino Duque | 18d1322 | 2016-02-08 14:55:28 +0000 | [diff] [blame] | 132 | env.getToolsLabel("//tools/test:runtime")))) |
Lukacs Berki | 8f460f3 | 2016-06-29 09:14:10 +0000 | [diff] [blame] | 133 | // Input files for test actions collecting code coverage |
| 134 | .add(attr("$coverage_support", LABEL) |
| 135 | .cfg(HOST) |
| 136 | .value(env.getLabel("//tools/defaults:coverage_support"))) |
| 137 | // Used in the one-per-build coverage report generation action. |
| 138 | .add(attr("$coverage_report_generator", LABEL) |
| 139 | .cfg(HOST) |
| 140 | .value(env.getLabel("//tools/defaults:coverage_report_generator")) |
| 141 | .singleArtifact()) |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 142 | |
| 143 | // The target itself and run_under both run on the same machine. We use the DATA config |
| 144 | // here because the run_under acts like a data dependency (e.g. no LIPO optimization). |
Ulf Adams | 0d815d65 | 2015-09-14 08:50:29 +0000 | [diff] [blame] | 145 | .add(attr(":run_under", LABEL).cfg(DATA).value(RUN_UNDER) |
Greg Estren | 875c7a7 | 2015-09-24 19:57:54 +0000 | [diff] [blame] | 146 | .skipPrereqValidatorCheck()) |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 147 | .build(); |
| 148 | } |
Googler | 5850503 | 2015-03-19 16:12:34 +0000 | [diff] [blame] | 149 | |
| 150 | @Override |
| 151 | public Metadata getMetadata() { |
| 152 | return RuleDefinition.Metadata.builder() |
| 153 | .name("$test_base_rule") |
| 154 | .type(RuleClassType.ABSTRACT) |
| 155 | .build(); |
| 156 | } |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 157 | } |
| 158 | |
| 159 | /** |
| 160 | * Share common attributes across both base and Skylark base rules. |
| 161 | */ |
| 162 | public static RuleClass.Builder commonCoreAndSkylarkAttributes(RuleClass.Builder builder) { |
| 163 | return builder |
Vladimir Moskva | da57492 | 2016-10-05 16:36:49 +0000 | [diff] [blame] | 164 | .add(attr("name", STRING) |
| 165 | .nonconfigurable("Rule name")) |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 166 | // The visibility attribute is special: it is a nodep label, and loading the |
| 167 | // necessary package groups is handled by {@link LabelVisitor#visitTargetVisibility}. |
| 168 | // Package groups always have the null configuration so that they are not duplicated |
| 169 | // needlessly. |
| 170 | .add(attr("visibility", NODEP_LABEL_LIST).orderIndependent().cfg(HOST) |
| 171 | .nonconfigurable("special attribute integrated more deeply into Bazel's core logic")) |
| 172 | .add(attr("deprecation", STRING).value(deprecationDefault) |
| 173 | .nonconfigurable("Used in core loading phase logic with no access to configs")) |
| 174 | .add(attr("tags", STRING_LIST).orderIndependent().taggable() |
| 175 | .nonconfigurable("low-level attribute, used in TargetUtils without configurations")) |
Greg Estren | ff47614 | 2016-02-08 21:03:33 +0000 | [diff] [blame] | 176 | .add(attr("generator_name", STRING).undocumented("internal") |
| 177 | .nonconfigurable("static structure of a rule")) |
| 178 | .add(attr("generator_function", STRING).undocumented("internal") |
| 179 | .nonconfigurable("static structure of a rule")) |
| 180 | .add(attr("generator_location", STRING).undocumented("internal") |
| 181 | .nonconfigurable("static structure of a rule")) |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 182 | .add(attr("testonly", BOOLEAN).value(testonlyDefault) |
| 183 | .nonconfigurable("policy decision: rules testability should be consistent")) |
Manuel Klimek | 6d9fb36 | 2015-04-30 12:50:55 +0000 | [diff] [blame] | 184 | .add(attr("features", STRING_LIST).orderIndependent()) |
Laurent Le Brun | d83e848 | 2015-07-13 14:34:44 +0000 | [diff] [blame] | 185 | .add(attr(":action_listener", LABEL_LIST).cfg(HOST).value(ACTION_LISTENER)) |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 186 | .add(attr(RuleClass.COMPATIBLE_ENVIRONMENT_ATTR, LABEL_LIST) |
| 187 | .allowedRuleClasses(EnvironmentRule.RULE_NAME) |
| 188 | .cfg(Attribute.ConfigurationTransition.HOST) |
Greg Estren | a765172 | 2016-05-02 18:54:18 +0000 | [diff] [blame] | 189 | .allowedFileTypes(FileTypeSet.NO_FILE) |
Greg Estren | 9d83784 | 2016-12-01 21:36:59 +0000 | [diff] [blame] | 190 | .dontCheckConstraints() |
Greg Estren | a765172 | 2016-05-02 18:54:18 +0000 | [diff] [blame] | 191 | .nonconfigurable("special logic for constraints and select: see ConstraintSemantics") |
| 192 | ) |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 193 | .add(attr(RuleClass.RESTRICTED_ENVIRONMENT_ATTR, LABEL_LIST) |
| 194 | .allowedRuleClasses(EnvironmentRule.RULE_NAME) |
| 195 | .cfg(Attribute.ConfigurationTransition.HOST) |
Greg Estren | a765172 | 2016-05-02 18:54:18 +0000 | [diff] [blame] | 196 | .allowedFileTypes(FileTypeSet.NO_FILE) |
Greg Estren | 9d83784 | 2016-12-01 21:36:59 +0000 | [diff] [blame] | 197 | .dontCheckConstraints() |
Greg Estren | a765172 | 2016-05-02 18:54:18 +0000 | [diff] [blame] | 198 | .nonconfigurable("special logic for constraints and select: see ConstraintSemantics") |
| 199 | ); |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 200 | } |
| 201 | |
| 202 | /** |
| 203 | * Common parts of rules. |
| 204 | */ |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 205 | public static final class BaseRule implements RuleDefinition { |
| 206 | @Override |
| 207 | public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment env) { |
| 208 | return commonCoreAndSkylarkAttributes(builder) |
| 209 | // The name attribute is handled specially, so it does not appear here. |
| 210 | // |
| 211 | // Aggregates the labels of all {@link ConfigRuleClasses} rules this rule uses (e.g. |
| 212 | // keys for configurable attributes). This is specially populated in |
| 213 | // {@RuleClass#populateRuleAttributeValues}. |
| 214 | // |
| 215 | // This attribute is not needed for actual builds. Its main purpose is so query's |
| 216 | // proto/XML output includes the labels of config dependencies, so, e.g., depserver |
| 217 | // reverse dependency lookups remain accurate. These can't just be added to the |
| 218 | // attribute definitions proto/XML queries already output because not all attributes |
| 219 | // contain labels. |
| 220 | // |
| 221 | // Builds and Blaze-interactive queries don't need this because they find dependencies |
| 222 | // through direct Rule label visitation, which already factors these in. |
| 223 | .add(attr("$config_dependencies", LABEL_LIST) |
| 224 | .nonconfigurable("not intended for actual builds")) |
| 225 | .add(attr("licenses", LICENSE) |
| 226 | .nonconfigurable("Used in core loading phase logic with no access to configs")) |
| 227 | .add(attr("distribs", DISTRIBUTIONS) |
| 228 | .nonconfigurable("Used in core loading phase logic with no access to configs")) |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 229 | .build(); |
| 230 | } |
Googler | 5850503 | 2015-03-19 16:12:34 +0000 | [diff] [blame] | 231 | |
| 232 | @Override |
| 233 | public Metadata getMetadata() { |
| 234 | return RuleDefinition.Metadata.builder() |
| 235 | .name("$base_rule") |
| 236 | .type(RuleClassType.ABSTRACT) |
| 237 | .build(); |
| 238 | } |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 239 | } |
| 240 | |
| 241 | /** |
| 242 | * Common ancestor class for all rules. |
| 243 | */ |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 244 | public static final class RuleBase implements RuleDefinition { |
| 245 | @Override |
| 246 | public RuleClass build(Builder builder, RuleDefinitionEnvironment env) { |
| 247 | return builder |
| 248 | .add(attr("deps", LABEL_LIST).legacyAllowAnyFileType()) |
Greg Estren | 9d83784 | 2016-12-01 21:36:59 +0000 | [diff] [blame] | 249 | .add(attr("data", LABEL_LIST).cfg(DATA) |
| 250 | .allowedFileTypes(FileTypeSet.ANY_FILE) |
| 251 | .dontCheckConstraints()) |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 252 | .build(); |
| 253 | } |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 254 | |
Googler | 5850503 | 2015-03-19 16:12:34 +0000 | [diff] [blame] | 255 | @Override |
| 256 | public Metadata getMetadata() { |
| 257 | return RuleDefinition.Metadata.builder() |
| 258 | .name("$rule") |
| 259 | .type(RuleClassType.ABSTRACT) |
| 260 | .ancestors(BaseRule.class) |
| 261 | .build(); |
| 262 | } |
| 263 | } |
Ulf Adams | 37590dc | 2016-10-14 11:52:00 +0000 | [diff] [blame] | 264 | |
| 265 | public static final ImmutableSet<String> ALLOWED_RULE_CLASSES = |
| 266 | ImmutableSet.of("filegroup", "genrule", "Fileset"); |
| 267 | |
| 268 | /** A base rule for all binary rules. */ |
| 269 | public static final class BinaryBaseRule implements RuleDefinition { |
| 270 | @Override |
| 271 | public RuleClass build(Builder builder, RuleDefinitionEnvironment env) { |
| 272 | return builder |
| 273 | .add(attr("args", STRING_LIST)) |
| 274 | .add(attr("output_licenses", LICENSE)) |
| 275 | .add( |
| 276 | attr("$is_executable", BOOLEAN) |
| 277 | .value(true) |
| 278 | .nonconfigurable("Called from RunCommand.isExecutable, which takes a Target")) |
| 279 | .build(); |
| 280 | } |
| 281 | |
| 282 | @Override |
| 283 | public Metadata getMetadata() { |
| 284 | return RuleDefinition.Metadata.builder() |
| 285 | .name("$binary_base_rule") |
| 286 | .type(RuleClassType.ABSTRACT) |
| 287 | .build(); |
| 288 | } |
| 289 | } |
| 290 | |
| 291 | /** Rule class for rules in error. */ |
| 292 | public static final class ErrorRule implements RuleDefinition { |
| 293 | @Override |
| 294 | public RuleClass build(Builder builder, RuleDefinitionEnvironment env) { |
| 295 | return builder.publicByDefault().build(); |
| 296 | } |
| 297 | |
| 298 | @Override |
| 299 | public Metadata getMetadata() { |
| 300 | return RuleDefinition.Metadata.builder() |
| 301 | .name("$error_rule") |
| 302 | .type(RuleClassType.ABSTRACT) |
| 303 | .ancestors(BaseRuleClasses.BaseRule.class) |
| 304 | .build(); |
| 305 | } |
| 306 | } |
Han-Wen Nienhuys | d08b27f | 2015-02-25 16:45:20 +0100 | [diff] [blame] | 307 | } |