A build rule is a procedure for producing output files from a set of input files in the context of a specified build configuration. Build rules are specified in build files.
Note: A build rule must explicitly specify all of its required inputs in its arguments in order for Buck to be able to ensure that it can build the output in a way that is deterministic and reproducible.
Buck's collection of build rules
Buck comes with a collection of built-in build rules, as there are many common procedures when building software. For example, compiling Java code against the Android SDK is a common operation, so Buck provides the build rule
android_library to do that. Similarly, the final product of most Android development is an APK, so the build rule
android_binary can be used to create an APK.
This documentation organizes Buck's build rules by development language and by target platform. Examples are: C++, Java, Python (development languages) and Android, iOS, .NET (target platforms). Consult the table of contents to locate the build rules that are appropriate for your development project.
Source files as inputs to build rules
Most build rules specify source files as inputs. For example, a
cxx_library rule would specify
.cpp files as inputs. To support specifying these files, a
cxx_library rule provides the
srcs argument. Some languages, such as C++, use header files as well. To specify these,
cxx_library provides a
In addition to
headers, some rules provide variants of these arguments—such as
platform_headers—to support groups of source files that should be used as inputs only when building for specific platforms. (For more information, see the descriptions for
platform_headers in, for example, the topic for
Package boundaries and access to source files
In Buck, a build file defines a package, which corresponds roughly to the directory that contains the BUCK file and those subdirectories that do not themselves contain BUCK files. (To learn more, see the Key Concepts topic.)
A rule in a BUCK file cannot specify a source file as an input unless that source file is in that BUCK file's package. An exception to this restriction exists for header files, but only if a rule in the package that contains the header file exports that header file using the
exported_headers argument. (For more information, see the description for
exported_headers in, for example, the topic for
More commonly though, the package for a BUCK file contains all the source files required for the rules defined in that BUCK file. Functionality in source files from other packages is made available through the artifacts produced by the rules in the BUCK files for those packages. For example, a
cxx_binary might use the functionality in a
cxx_library that is defined in another package. To access that functionality, the
cxx_binary would take that
cxx_library as a dependency.
Symlinks: Use with caution if at all
We recommend that you do not use symlinks—either absolute or relative—to specify input files to build rules. Although using symlinks in this context does sometimes work, it can lead to unexpected behavior and errors.
Dependencies: Output from one rule as input to another rule
A build rule can use the output from another build rule as one of its inputs by specifying that rule as a dependency. Typically, a build rule specifies its dependencies as a list of build targets in its
deps argument. However, the rule can also specify dependencies—as build targets—in other arguments, such as
Example: The output of a
java_library rule is a JAR file. If a
java_library rule specifies another
java_library rule as a dependency, the JAR file produced by the specified rule is added to the classpath for the
java_library that depends on it.
Example: If a
java_binary rule specifies a
java_library rule as a dependency, the JAR file for the specified
java_library is available on the classpath for the
java_binary. In addition, in the case of
java_binary, the JAR files for any dependencies of the
java_library rule are also made available to the
java_binary rule—and if those dependencies have dependencies of their own, they are added as well. This exhaustive cascade of dependencies is referred to as the rule's transitive closure.
Required dependencies are always built first
Buck guarantees that any dependencies that a rule lists that are required in order to build that rule are built successfully before Buck builds the rule itself. Note though that there can be special cases—such as
apple_bundle—where listed dependencies do not actually need to be built before the rule.
In order for a build rule to take a dependency on another build rule, the build rule on which the dependency is taken must be visible to the build rule taking the dependency. A build rule's
visibility argument is a list of build target patterns that specify the rules that can take this rule as a dependency. For more information about the concept of visibility in Buck, see the Visibility topic.
Dependencies define a graph
Build rules and their dependencies define a directed acyclic graph (DAG). Buck requires this graph to be acyclic because to make it easier to build independent subgraphs in parallel.
How to handle special cases: genrules and macros
Although Buck provides a rich set of built-in build rules for developers, it is not able to address all possible needs. As an "escape hatch," Buck provides a category of generic build rules called genrules. With a genrule, you can perform arbitrary operations using a shell script. Examples of genrules are:
Multiple output files with genrules
In most cases, a build produces exactly one output file. However, with genrules, you can specify an output directory and write arbitrary files to that directory.
Finally, note that you can define your own functions that generate build rules. In general, this should not be something that you need to do, but taking advantage of this option might help you add something to Buck's build process without editing its source code. For more details, see the topic Custom Macros.