aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/SkylarkRuleFunctionsApi.java
blob: 84abfe1bce75cf19c4abf5026d833c2069e42615 (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
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
// Copyright 2018 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.devtools.build.lib.skylarkbuildapi;

import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.skylarkinterface.Param;
import com.google.devtools.build.lib.skylarkinterface.ParamType;
import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
import com.google.devtools.build.lib.skylarkinterface.SkylarkConstructor;
import com.google.devtools.build.lib.skylarkinterface.SkylarkGlobalLibrary;
import com.google.devtools.build.lib.syntax.BaseFunction;
import com.google.devtools.build.lib.syntax.Environment;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.FuncallExpression;
import com.google.devtools.build.lib.syntax.SkylarkDict;
import com.google.devtools.build.lib.syntax.SkylarkList;

/**
 * Interface for a global Skylark library containing rule-related helper and registration functions.
 */
@SkylarkGlobalLibrary
public interface SkylarkRuleFunctionsApi<FileApiT extends FileApi> {

  @SkylarkCallable(
    name = "provider",
    doc =
        "Creates a declared provider 'constructor'. The return value of this "
            + "function can be used to create \"struct-like\" values. Example:<br>"
            + "<pre class=\"language-python\">data = provider()\n"
            + "d = data(x = 2, y = 3)\n"
            + "print(d.x + d.y) # prints 5</pre>",
    parameters = {
      @Param(
        name = "doc",
        type = String.class,
        legacyNamed = true,
        defaultValue = "''",
        doc =
            "A description of the provider that can be extracted by documentation generating tools."
      ),
      @Param(
        name = "fields",
        doc = "If specified, restricts the set of allowed fields. <br>"
            + "Possible values are:"
            + "<ul>"
            + "  <li> list of fields:<br>"
            + "       <pre class=\"language-python\">provider(fields = ['a', 'b'])</pre><p>"
            + "  <li> dictionary field name -> documentation:<br>"
            + "       <pre class=\"language-python\">provider(\n"
            + "       fields = { 'a' : 'Documentation for a', 'b' : 'Documentation for b' })</pre>"
            + "</ul>"
            + "All fields are optional.",
        allowedTypes = {
            @ParamType(type = SkylarkList.class, generic1 = String.class),
            @ParamType(type = SkylarkDict.class)
        },
        noneable = true,
        named = true,
        positional = false,
        defaultValue = "None"
      )
    },
    useLocation = true
  )
  public ProviderApi provider(String doc, Object fields, Location location) throws EvalException;

  @SkylarkCallable(
    name = "rule",
    doc =
        "Creates a new rule, which can be called from a BUILD file or a macro to create targets."
            + "<p>Rules must be assigned to global variables in a .bzl file; the name of the "
            + "global variable is the rule's name."
            + "<p>Test rules are required to have a name ending in <code>_test</code>, while all "
            + "other rules must not have this suffix. (This restriction applies only to rules, not "
            + "to their targets.)",
    parameters = {
      @Param(
        name = "implementation",
        type = BaseFunction.class,
        legacyNamed = true,
        doc =
            "the function implementing this rule, must have exactly one parameter: "
                + "<a href=\"ctx.html\">ctx</a>. The function is called during the analysis "
                + "phase for each instance of the rule. It can access the attributes "
                + "provided by the user. It must create actions to generate all the declared "
                + "outputs."
      ),
      @Param(
        name = "test",
        type = Boolean.class,
        legacyNamed = true,
        defaultValue = "False",
        doc =
            "Whether this rule is a test rule, that is, whether it may be the subject of a "
                + "<code>blaze test</code> command. All test rules are automatically considered "
                + "<a href='#rule.executable'>executable</a>; it is unnecessary (and discouraged) "
                + "to explicitly set <code>executable = True</code> for a test rule. See the "
                + "<a href='../rules.$DOC_EXT#executable-rules-and-test-rules'>Rules page</a> for "
                + "more information."
      ),
      @Param(
        name = "attrs",
        type = SkylarkDict.class,
        legacyNamed = true,
        noneable = true,
        defaultValue = "None",
        doc =
            "dictionary to declare all the attributes of the rule. It maps from an attribute "
                + "name to an attribute object (see <a href=\"attr.html\">attr</a> module). "
                + "Attributes starting with <code>_</code> are private, and can be used to "
                + "add an implicit dependency on a label. The attribute <code>name</code> is "
                + "implicitly added and must not be specified. Attributes "
                + "<code>visibility</code>, <code>deprecation</code>, <code>tags</code>, "
                + "<code>testonly</code>, and <code>features</code> are implicitly added and "
                + "cannot be overridden."
      ),
      // TODO(bazel-team): need to give the types of these builtin attributes
      @Param(
        name = "outputs",
        type = SkylarkDict.class,
        legacyNamed = true,
        callbackEnabled = true,
        noneable = true,
        defaultValue = "None",
        doc =
            "<b>Experimental:</b> This API is in the process of being redesigned."
                + "<p>A schema for defining predeclared outputs. Unlike <a href='attr.html#output'>"
                + "<code>output</code></a> and <a href='attr.html#output_list'><code>output_list"
                + "</code></a> attributes, the user does not specify the labels for these files. "
                + "See the <a href='../rules.$DOC_EXT#files'>Rules page</a> for more on "
                + "predeclared outputs."
                + "<p>The value of this argument is either a dictionary or a callback function "
                + "that produces a dictionary. The callback works similar to computed dependency "
                + "attributes: The function's parameter names are matched against the rule's "
                + "attributes, so for example if you pass <code>outputs = _my_func</code> with the "
                + "definition <code>def _my_func(srcs, deps): ...</code>, the function has access "
                + "to the attributes <code>srcs</code> and <code>deps</code>. Whether the "
                + "dictionary is specified directly or via a function, it is interpreted as "
                + "follows."
                + "<p>Each entry in the dictionary creates a predeclared output where the key is "
                + "an identifier and the value is a string template that determines the output's "
                + "label. In the rule's implementation function, the identifier becomes the field "
                + "name used to access the output's <a href='File.html'><code>File</code></a> in "
                + "<a href='ctx.html#outputs'><code>ctx.outputs</code></a>. The output's label has "
                + "the same package as the rule, and the part after the package is produced by "
                + "substituting each placeholder of the form <code>\"%{ATTR}\"</code> with a "
                + "string formed from the value of the attribute <code>ATTR</code>:"
                + "<ul>"
                + "<li>String-typed attributes are substituted verbatim."
                + "<li>Label-typed attributes become the part of the label after the package, "
                + "minus the file extension. For example, the label <code>\"//pkg:a/b.c\"</code> "
                + "becomes <code>\"a/b\"</code>."
                + "<li>Output-typed attributes become the part of the label after the package, "
                + "including the file extension (for the above example, <code>\"a/b.c\"</code>)."
                + "<li>All list-typed attributes (for example, <code>attr.label_list</code>) used "
                + "in placeholders are required to have <i>exactly one element</i>. Their "
                + "conversion is the same as their non-list version (<code>attr.label</code>)."
                + "<li>Other attribute types may not appear in placeholders."
                + "<li>The special non-attribute placeholders <code>%{dirname}</code> and <code>"
                + "%{basename}</code> expand to those parts of the rule's label, excluding its "
                + "package. For example, in <code>\"//pkg:a/b.c\"</code>, the dirname is <code>"
                + "a</code> and the basename is <code>b.c</code>."
                + "</ul>"
                + "<p>In practice, the most common substitution placeholder is "
                + "<code>\"%{name}\"</code>. For example, for a target named \"foo\", the outputs "
                + "dict <code>{\"bin\": \"%{name}.exe\"}</code> predeclares an output named "
                + "<code>foo.exe</code> that is accessible in the implementation function as "
                + "<code>ctx.outputs.bin</code>."
      ),
      @Param(
        name = "executable",
        type = Boolean.class,
        legacyNamed = true,
        defaultValue = "False",
        doc =
            "Whether this rule is considered executable, that is, whether it may be the subject of "
                + "a <code>blaze run</code> command. See the "
                + "<a href='../rules.$DOC_EXT#executable-rules-and-test-rules'>Rules page</a> for "
                + "more information."
      ),
      @Param(
        name = "output_to_genfiles",
        type = Boolean.class,
        legacyNamed = true,
        defaultValue = "False",
        doc =
            "If true, the files will be generated in the genfiles directory instead of the "
                + "bin directory. Unless you need it for compatibility with existing rules "
                + "(e.g. when generating header files for C++), do not set this flag."
      ),
      @Param(
        name = "fragments",
        type = SkylarkList.class,
        legacyNamed = true,
        generic1 = String.class,
        defaultValue = "[]",
        doc =
            "List of names of configuration fragments that the rule requires "
                + "in target configuration."
      ),
      @Param(
        name = "host_fragments",
        type = SkylarkList.class,
        legacyNamed = true,
        generic1 = String.class,
        defaultValue = "[]",
        doc =
            "List of names of configuration fragments that the rule requires "
                + "in host configuration."
      ),
      @Param(
        name = "_skylark_testable",
        type = Boolean.class,
        legacyNamed = true,
        defaultValue = "False",
        doc =
            "<i>(Experimental)</i><br/><br/>"
                + "If true, this rule will expose its actions for inspection by rules that "
                + "depend on it via an <a href=\"globals.html#Actions\">Actions</a> "
                + "provider. The provider is also available to the rule itself by calling "
                + "<a href=\"ctx.html#created_actions\">ctx.created_actions()</a>."
                + "<br/><br/>"
                + "This should only be used for testing the analysis-time behavior of "
                + "Skylark rules. This flag may be removed in the future."
      ),
      @Param(
        name = "toolchains",
        type = SkylarkList.class,
        legacyNamed = true,
        generic1 = String.class,
        defaultValue = "[]",
        doc =
            "<i>(Experimental)</i><br/><br/>"
                + "If set, the set of toolchains this rule requires. Toolchains will be "
                + "found by checking the current platform, and provided to the rule "
                + "implementation via <code>ctx.toolchain</code>."
      ),
      @Param(
        name = "doc",
        type = String.class,
        legacyNamed = true,
        defaultValue = "''",
        doc = "A description of the rule that can be extracted by documentation generating tools."
      ),
      @Param(
        name = "provides",
        type = SkylarkList.class,
        named = true,
        positional = false,
        defaultValue = "[]",
        doc =
            "A list of providers this rule is guaranteed to provide. "
                + "It is an error if a provider is listed here and the rule "
                + "implementation function does not return it."
      ),
      @Param(
        name = "execution_platform_constraints_allowed",
        type = Boolean.class,
        named = true,
        positional = false,
        defaultValue = "False",
        doc =
            "If true, a special attribute named <code>exec_compatible_with</code> of "
                + "label-list type is added, which must not already exist in "
                + "<code>attrs</code>. Targets may use this attribute to specify additional "
                + "constraints on the execution platform beyond those given in the "
                + "<code>exec_compatible_with</code> argument to <code>rule()</code>."
      ),
      @Param(
        name = "exec_compatible_with",
        type = SkylarkList.class,
        generic1 = String.class,
        named = true,
        positional = false,
        defaultValue = "[]",
        doc =
            "A list of constraints on the execution platform that apply to all targets of "
                + "this rule type."
      )
    },
    useAst = true,
    useEnvironment = true
  )
  public BaseFunction rule(
      BaseFunction implementation,
      Boolean test,
      Object attrs,
      Object implicitOutputs,
      Boolean executable,
      Boolean outputToGenfiles,
      SkylarkList<?> fragments,
      SkylarkList<?> hostFragments,
      Boolean skylarkTestable,
      SkylarkList<?> toolchains,
      String doc,
      SkylarkList<?> providesArg,
      Boolean executionPlatformConstraintsAllowed,
      SkylarkList<?> execCompatibleWith,
      FuncallExpression ast,
      Environment funcallEnv)
      throws EvalException;

  @SkylarkCallable(
      name = "aspect",
      doc =
          "Creates a new aspect. The result of this function must be stored in a global value. "
              + "Please see the <a href=\"../aspects.md\">introduction to Aspects</a> for more "
              + "details.",
      parameters = {
          @Param(
              name = "implementation",
              type = BaseFunction.class,
              legacyNamed = true,
              doc =
                  "the function implementing this aspect. Must have two parameters: "
                      + "<a href=\"Target.html\">Target</a> (the target to which the aspect is "
                      + "applied) and <a href=\"ctx.html\">ctx</a>. Attributes of the target are "
                      + "available via ctx.rule field. The function is called during the analysis "
                      + "phase for each application of an aspect to a target."
          ),
          @Param(
              name = "attr_aspects",
              type = SkylarkList.class,
              legacyNamed = true,
              generic1 = String.class,
              defaultValue = "[]",
              doc = "List of attribute names.  The aspect propagates along dependencies specified "
                  + "by attributes of a target with this name. The list can also contain a single "
                  + "string '*': in that case aspect propagates along all dependencies of a target."
          ),
          @Param(
              name = "attrs",
              type = SkylarkDict.class,
              legacyNamed = true,
              noneable = true,
              defaultValue = "None",
              doc = "dictionary to declare all the attributes of the aspect.  "
                  + "It maps from an attribute name to an attribute object "
                  + "(see <a href=\"attr.html\">attr</a> module). "
                  + "Aspect attributes are available to implementation function as fields of ctx "
                  + "parameter. Implicit attributes starting with <code>_</code> must have default "
                  + "values, and have type <code>label</code> or <code>label_list</code>. "
                  + "Explicit attributes must have type <code>string</code>, and must use the "
                  + "<code>values</code> restriction. If explicit attributes are present, the "
                  + "aspect can only be used with rules that have attributes of the same name and "
                  + "type, with valid values."
          ),
          @Param(
              name = "required_aspect_providers",
              type = SkylarkList.class,
              legacyNamed = true,
              defaultValue = "[]",
              doc = "Allow the aspect to inspect other aspects. If the aspect propagates along "
                  + "a dependency, and the underlying rule sends a different aspect along that "
                  + "dependency, and that aspect provides one of the providers listed here, this "
                  + "aspect will see the providers provided by that aspect. "
                  + "<p>The value should be either a list of providers, or a "
                  + "list of lists of providers. This aspect will 'see'  the underlying aspects "
                  + "that provide  ALL providers from at least ONE of these lists. A single list "
                  + "of providers will be automatically converted to a list containing one list of "
                  + "providers."
          ),
          @Param(
              name = "provides",
              type = SkylarkList.class,
              legacyNamed = true,
              defaultValue = "[]",
              doc =
                  "A list of providers this aspect is guaranteed to provide. "
                      + "It is an error if a provider is listed here and the aspect "
                      + "implementation function does not return it."
          ),
          @Param(
              name = "fragments",
              type = SkylarkList.class,
              legacyNamed = true,
              generic1 = String.class,
              defaultValue = "[]",
              doc =
                  "List of names of configuration fragments that the aspect requires "
                      + "in target configuration."
          ),
          @Param(
              name = "host_fragments",
              type = SkylarkList.class,
              legacyNamed = true,
              generic1 = String.class,
              defaultValue = "[]",
              doc =
                  "List of names of configuration fragments that the aspect requires "
                      + "in host configuration."
          ),
          @Param(
              name = "toolchains",
              type = SkylarkList.class,
              legacyNamed = true,
              generic1 = String.class,
              defaultValue = "[]",
              doc =
                  "<i>(Experimental)</i><br/><br/>"
                      + "If set, the set of toolchains this rule requires. Toolchains will be "
                      + "found by checking the current platform, and provided to the rule "
                      + "implementation via <code>ctx.toolchain</code>."
          ),
          @Param(
              name = "doc",
              type = String.class,
              legacyNamed = true,
              defaultValue = "''",
              doc = "A description of the aspect that can be extracted by documentation generating "
                  + "tools."
          )
      },
      useEnvironment = true,
      useAst = true
  )
  public SkylarkAspectApi aspect(
      BaseFunction implementation,
      SkylarkList<?> attributeAspects,
      Object attrs,
      SkylarkList<?> requiredAspectProvidersArg,
      SkylarkList<?> providesArg,
      SkylarkList<?> fragments,
      SkylarkList<?> hostFragments,
      SkylarkList<?> toolchains,
      String doc,
      FuncallExpression ast,
      Environment funcallEnv)
      throws EvalException;

  @SkylarkCallable(
      name = "Label",
      doc = "Creates a Label referring to a BUILD target. Use "
          + "this function only when you want to give a default value for the label attributes. "
          + "The argument must refer to an absolute label. "
          + "Example: <br><pre class=language-python>Label(\"//tools:default\")</pre>",
      parameters = {
          @Param(name = "label_string", type = String.class, legacyNamed = true,
              doc = "the label string."),
          @Param(
              name = "relative_to_caller_repository",
              type = Boolean.class,
              defaultValue = "False",
              named = true,
              positional = false,
              doc = "Deprecated. Do not use. "
                  + "When relative_to_caller_repository is True and the calling thread is a rule's "
                  + "implementation function, then a repo-relative label //foo:bar is resolved "
                  + "relative to the rule's repository.  For calls to Label from any other "
                  + "thread, or calls in which the relative_to_caller_repository flag is False, "
                  + "a repo-relative label is resolved relative to the file in which the "
                  + "Label() call appears."
          )
      },
      useLocation = true,
      useEnvironment = true
  )
  @SkylarkConstructor(objectType = Label.class)
  public Label label(
      String labelString, Boolean relativeToCallerRepository, Location loc, Environment env)
      throws EvalException;

  @SkylarkCallable(
      name = "FileType",
      doc =
          "Deprecated. Creates a file filter from a list of strings. For example, to match "
              + "files ending with .cc or .cpp, use: "
              + "<pre class=language-python>FileType([\".cc\", \".cpp\"])</pre>",
      parameters = {
          @Param(
              name = "types",
              type = SkylarkList.class,
              legacyNamed = true,
              generic1 = String.class,
              defaultValue = "[]",
              doc = "a list of the accepted file extensions."
          )
      },
      useLocation = true,
      useEnvironment = true
  )
  @SkylarkConstructor(objectType = FileTypeApi.class)
  public FileTypeApi<FileApiT> fileType(SkylarkList<?> types, Location loc, Environment env)
     throws EvalException;
}