aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigRuleClasses.java
blob: 2a291373097f17cc6d0704d14f80b14717919aa9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.devtools.build.lib.analysis.config;

import static com.google.devtools.build.lib.packages.Attribute.attr;
import static com.google.devtools.build.lib.syntax.Type.STRING_DICT;

import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.analysis.BaseRuleClasses;
import com.google.devtools.build.lib.analysis.RuleDefinition;
import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
import com.google.devtools.build.lib.packages.RuleClass;
import com.google.devtools.build.lib.syntax.Type;

/**
 * Definitions for rule classes that specify or manipulate configuration settings.
 *
 * <p>These are not "traditional" rule classes in that they can't be requested as top-level
 * targets and don't translate input artifacts into output artifacts. Instead, they affect
 * how *other* rules work. See individual class comments for details.
 */
public class ConfigRuleClasses {

  private static final String NONCONFIGURABLE_ATTRIBUTE_REASON =
      "part of a rule class that *triggers* configurable behavior";

  /**
   * Common settings for all configurability rules.
   */
  public static final class ConfigBaseRule implements RuleDefinition {
    @Override
    public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment env) {
      return builder
          .override(attr("tags", Type.STRING_LIST)
               // No need to show up in ":all", etc. target patterns.
              .value(ImmutableList.of("manual"))
              .nonconfigurable(NONCONFIGURABLE_ATTRIBUTE_REASON))
          .exemptFromConstraintChecking(
              "these rules don't include content that gets built into their dependers")
          .build();
    }

    @Override
    public Metadata getMetadata() {
      return RuleDefinition.Metadata.builder()
          .name("$config_base_rule")
          .type(RuleClass.Builder.RuleClassType.ABSTRACT)
          .ancestors(BaseRuleClasses.BaseRule.class)
          .build();
    }
  }

  /**
   * A named "partial configuration setting" that specifies a set of command-line
   * "flag=value" bindings.
   *
   * <p>For example:
   * <pre>
   *   config_setting(
   *       name = 'foo',
   *       values = {
   *           'flag1': 'aValue'
   *           'flag2': 'bValue'
   *       })
   * </pre>
   *
   * <p>declares a setting that binds command-line flag <pre>flag1</pre> to value
   * <pre>aValue</pre> and <pre>flag2</pre> to <pre>bValue</pre>.
   *
   * <p>This is used by configurable attributes to determine which branch to
   * follow based on which <pre>config_setting</pre> instance matches all its
   * flag values in the configurable attribute owner's configuration.
   *
   * <p>This rule isn't accessed through the standard {@link RuleContext#getPrerequisites}
   * interface. This is because Bazel constructs a rule's configured attribute map *before*
   * its {@link RuleContext} is created (in fact, the map is an input to the context's
   * constructor). And the config_settings referenced by the rule's configurable attributes are
   * themselves inputs to that map. So Bazel has special logic to read and properly apply
   * config_setting instances. See {@link ConfiguredTargetFunction#getConfigConditions} for details.
   */
  public static final class ConfigSettingRule implements RuleDefinition {
    /**
     * The name of the attribute that declares flag bindings.
     */
    public static final String SETTINGS_ATTRIBUTE = "values";

    @Override
    public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment env) {
      return builder
          /* <!-- #BLAZE_RULE(config_setting).ATTRIBUTE(values) -->
          The set of configuration values that match this rule (expressed as Blaze flags)
          ${SYNOPSIS}

          <i>(Dictionary mapping flags to expected values, both expressed as strings;
             mandatory)</i>

          <p>This rule inherits the configuration of the configured target that
            references it in a <code>select</code> statement. It is considered to
            "match" a Blaze invocation if, for every entry in the dictionary, its
            configuration matches the entry's expected value. For example
            <code>values = {"compilation_mode": "opt"}</code> matches the invocations
            <code>blaze build --compilation_mode=opt ...</code> and
            <code>blaze build -c opt ...</code> on target-configured rules.
          </p>

          <p>For convenience's sake, configuration values are specified as Blaze flags (without
            the preceding <code>"--"</code>). But keep in mind that the two are not the same. This
            is because targets can be built in multiple configurations within the same
            build. For example, a host configuration's "cpu" matches the value of
            <code>--host_cpu</code>, not <code>--cpu</code>. So different instances of the
            same <code>config_setting</code> may match the same invocation differently
            depending on the configuration of the rule using them.
          </p>

          <p>If a flag is not explicitly set at the command line, its default value is used.
             If a key appears multiple times in the dictionary, only the last instance is used.
             If a key references a flag that can be set multiple times on the command line (e.g.
             <code>blaze build --copt=foo --copt=bar --copt=baz ...</code>), a match occurs if
             <i>any</i> of those settings match.
          <p>

          <p>This attribute cannot be empty.
          </p>
          <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
          .add(attr(SETTINGS_ATTRIBUTE, STRING_DICT).mandatory()
              .nonconfigurable(NONCONFIGURABLE_ATTRIBUTE_REASON))
          .build();
    }

    @Override
    public Metadata getMetadata() {
      return RuleDefinition.Metadata.builder()
          .name("config_setting")
          .type(RuleClass.Builder.RuleClassType.NORMAL)
          .ancestors(ConfigBaseRule.class)
          .factoryClass(ConfigSetting.class)
          .build();
    }
  }

/*<!-- #BLAZE_RULE (NAME = config_setting, TYPE = OTHER, FAMILY = General)[GENERIC_RULE] -->

${ATTRIBUTE_SIGNATURE}

<p>
  Matches an expected configuration state (expressed as Blaze flags) for the purpose of triggering
  configurable attributes. See <a href="#select">select</a> for how to consume this rule and
  <a href="#configurable-attributes">Configurable attributes</a> for an overview of
  the general feature.

${ATTRIBUTE_DEFINITION}

<h4 id="config_setting_examples">Examples</h4>

<p>The following matches any Blaze invocation that specifies <code>--compilation_mode=opt</code>
   or <code>-c opt</code> (either explicitly at the command line or implicitly from .blazerc
   files, etc.), when applied to a target configuration rule:
</p>

<pre class="code">
config_setting(
    name = "simple",
    values = {"compilation_mode": "opt"}
)
</pre>

<p>The following matches any Blaze invocation that builds for ARM and applies a custom define
   (e.g. <code>blaze build --cpu=armeabi --define FOO=bar ...</code>), , when applied to a target
   configuration rule:
</p>

<pre class="code">
config_setting(
    name = "two_conditions",
    values = {
        "cpu": "armeabi",
        "define": "FOO=bar"
    }
)
</pre>

<h4 id="config_setting_notes">Notes</h4>

<p>See <a href="#select">select</a> for policies on what happens depending on how many rules match
   an invocation.
</p>

<p>For flags that support shorthand forms (e.g. <code>--compilation_mode</code> vs.
  <code>-c</code>), <code>values</code> definitions must use the full form. These automatically
  match invocations using either form.
</p>

<p>The currently endorsed method for creating custom conditions that can't be expressed through
  dedicated build flags is through the --define flag. Use this flag with caution: it's not ideal
  and only endorsed for lack of a currently better workaround. See the
  <a href="#configurable-attributes">Configurable attributes</a> section for more discussion.
</p>

<p>Try to consolidate <code>config_setting</code> definitions as much as possible. In other words,
  define <code>//common/conditions:foo</code> in one common package instead of repeating separate
  instances in <code>//project1:foo</code>, <code>//project2:foo</code>, etc. that all mean the
  same thing.
</p>

<!-- #END_BLAZE_RULE -->*/
}