Please's BUILD files typically contain a series of build rule declarations. These are
invocations of builtins like
java_binary which create new BUILD targets.
However, you can do much more with it; the syntax is actually a restricted Python subset so it's possible to script the creation of build targets in elaborate ways.
Formally, the grammar for the BUILD files is defined as for Python since we interpret
them as such (using PyPy, as it happens). The only exceptions
to this are that the
keywords are disallowed. This means you can cheerfully have loops, classes, exceptions etc
as you want.
The reason these are disallowed is in an effort to keep BUILD file parsing reliable and
efficient. Allowing import of arbitrary modules opens the door for all kinds of bad things
to be done at parse time (we know, we did this in build systems we've used in the past
and it did not have a happy ending). There are other solutions for these anyway (well not
exec, but you weren't going to use that anyway, right?); see
Similarly, a number of the standard builtins are not available; an incomplete list of these
Again, if BUILD files were able to open and read arbitrary files, it would be possible to do many bad things which would ultimately lead to builds being slow or unreliable.
Note that BUILD files are parsed in-order, so invocations of functions that affect global
package) will only
affect build rules declared after them. However the rules themselves can be declared in any
order, it isn't necessary to declare dependencies before rules that depend on them.
We normally write BUILD files in an idiom which doesn't quite match standard Python styles. The justification is that these are mostly just inherited from working on Blaze, but a brief explanation follows after an example:
# Taken from //src/core/BUILD in the Please repo go_library( name = 'core', srcs = glob(['*.go'], excludes=['*_test.go', 'version.go']) + [':version'], visibility = ['PUBLIC'], deps = [ '//third_party/go:gcfg', '//third_party/go:logging', '//third_party/go:queue', ] )
All arguments to build rules are passed as keywords. This is pretty important since (1) nobody will be able to read your BUILD file otherwise and (2) while we don't normally change the order of function arguments, we might sometimes insert earlier ones which will break code using positional arguments.
Arguments to functions like
subinclude() are not
necessarily passed as keywords.
We put spaces around the
= for each argument to the build rule.
Either single or double quotes work, as usual, but don't mix both in one file.
Lists either go all on one line:
or are broken across multiple lines like so:
[ '//third_party/go:gcfg', '//third_party/go:logging', '//third_party/go:queue', ]
Indentation is normally four spaces.
We generally try to order lists lexicographically but don't always get this 100%.
If you'd like an autoformatter for BUILD files, Google's Buildifier is very good & fast. We use a slightly modified version of it internally & on the Please repo.