--- layout: documentation title: Best practices --- # Best practices for Bazel This document assumes that you are familiar with Bazel and provides advice on structuring your projects to take full advantage of Bazel's features. The overall goals are: - To use fine-grained dependencies to allow parallelism and incrementality. - To keep dependencies well-encapsulated. - To make code well-structured and testable. - To create a build configuration that is easy to understand and maintain. These guidelines are not requirements: few projects will be able to adhere to all of them. As the man page for lint says, "A special reward will be presented to the first person to produce a real program that produces no errors with strict checking." However, incorporating as many of these principles as possible should make a project more readable, less error-prone, and faster to build. This document uses the requirement levels described in [this RFC](https://www.ietf.org/rfc/rfc2119.txt). ## Contents - [General structure](#general-structure) - [Running builds and tests](#running-builds-and-tests) - [Third party dependencies](#third-party-dependencies) - [Depending on binaries](#depending-on-binaries) - [Versioning](#versioning) - [.bazelrc](#bazelrc) - [Packages](#packages) - [BUILD files](#build-files) - [.bzl files](#bzl-files) - [.bzl files style guide](#bzl-files-style-guide) - [Packaging rules](#packaging-rules) - [Rule choice](#rule-choice) - [WORKSPACE files](#workspace-files) - [Repository rules](#repository-rules) - [Custom BUILD files](#custom-build-files) - [Repository rules](#repository-rules) - [Programming languages](#programming-languages) - [C++ and Bazel](#c-and-bazel) - [Java and Bazel](#java-and-bazel) - [Protos and Bazel](#protos-and-bazel) # General structure ## Running builds and tests A project should always be able to run `bazel build //...` and `bazel test //...` successfully on its stable branch. Targets that are necessary but do not build under certain circumstances (e.g., require specific build flags, do not build on a certain platform, require license agreements) should be tagged as specifically as possible (e.g., "`requires-osx`"). This tagging allows targets to be filtered at a more fine-grained level than the "manual" tag and allows someone inspecting the BUILD file to understand what a target's restrictions are. ## Third party dependencies Prefer declaring third party dependencies as remote repositories in the WORKSPACE file. If it's necessary to check third party dependencies into your repository, put them in a directory called `third_party/` under your workspace directory. Note that all BUILD files in `third_party/` must include [license](https://docs.bazel.build/be/functions.html#licenses) declarations. ## Depending on binaries Everything should be built from source whenever possible. Generally this means that, instead of depending on a library `some-library.so`, you'd create a BUILD file and build `some-library.so` from its sources, then depend on that target. Always building from source ensures that a build is not using a library that was built with incompatible flags or a different architecture. There are also some features like coverage, static analysis, or dynamic analysis that will only work on the source. ## Versioning Prefer building all code from head whenever possible. When versions must be used, avoid including the version in the target name (e.g., `//guava`, not `//guava-20.0`). This naming makes the library easier to update (only one target needs to be updated). It is also more resilient to diamond dependency issues: if one library depends on `guava-19.0` and one depends on `guava-20.0`, you could end up with a library that tries to depend on two different versions. If you created a misleading alias to point both targets to one guava library, then the BUILD files are misleading. ## `.bazelrc` For project-specific options, use the configuration file `_your-workspace_/tools/bazel.rc` (see [bazelrc format](https://docs.bazel.build/user-manual.html#bazelrc)). For options that you **do not** want to check into source control, create the configuration file `_your-workspace_/.bazelrc` and add `.bazelrc` to your `.gitignore`. Note that this file has a different name than the file above (`bazel.rc` vs `.bazelrc`). ## Packages Every directory that contains buildable files should be a package. If a BUILD file refers to files in subdirectories (e.g., `srcs = ["a/b/C.java"]`) it is a sign that a BUILD file should be added to that subdirectory. The longer this structure exists, the more likely circular dependencies will be inadvertently created, a target's scope will creep, and an increasing number of reverse dependencies will have to be updated. # BUILD files See the [BUILD file style guide](https://docs.bazel.build/skylark/build-style.html). # .bzl files ## .bzl files style guide See the [Style guide for .bzl files](https://docs.bazel.build/skylark/bzl-style.html) for guidelines. ## Packaging rules See [Packaging rules](https://docs.bazel.build/skylark/deploying.html) for advice on how to structure and where to put new rules. ## Rule choice When using a language for which Bazel has built-in rules (e.g., C++), prefer using these rules to writing your own. These rules are documented in the [build encyclopedia](https://docs.bazel.build/be/overview.html). # WORKSPACE files ## Repository rules Prefer `http_archive` and `new_http_archive` to `git_repository`, `new_git_repository`, and `maven_jar`. `git_repository` depends on jGit, which has several unpleasant bugs, and `maven_jar` uses Maven's internal API, which generally works but is less optimized for Bazel than `http_archive`'s downloader logic. Track the following issues filed to remediate these problems: - [Use `http_archive` as `git_repository`'s backend.](https://github.com/bazelbuild/bazel/issues/2147) - [Improve `maven_jar`'s backend.](https://github.com/bazelbuild/bazel/issues/1752) Do not use `bind()`. See "[Consider removing bind](https://github.com/bazelbuild/bazel/issues/1952)" for a long discussion of its issues and alternatives. ## Custom BUILD files When using a `new_` repository rule, prefer to specify `build_file_content`, not `build_file`. ## Repository rules A repository rule should generally be responsible for: - Detecting system settings and writing them to files. - Finding resources elsewhere on the system. - Downloading resources from URLs. - Generating or symlinking BUILD files into the external repository directory. Avoid using `repository_ctx.execute` when possible. For example, when using a non-Bazel C++ library that has a build using Make, it is preferable to use `repository_ctx.download()` and then write a BUILD file that builds it, instead of running `ctx.execute(["make"])`. # Programming languages This section describes best practices for specific programming languages. ## C++ and Bazel For best practices for C++ projects, see [C++ and Bazel](bazel-and-cpp.md). ## Java and Bazel For best practices for Java projects, see [Java and Bazel](bazel-and-java.md). ## Protos and Bazel Recommended code organization: - One `proto_library` rule per `.proto` file. - A file named `foo.proto` will be in a rule named `foo_proto`, which is located in the same package. - A `[language]_proto_library` that wraps a `proto_library` named `foo_proto` should be called `foo_[language]_proto`, and be located in the same package.