fwe | acae1cd | 2022-02-17 09:45:38 -0800 | [diff] [blame] | 1 | Project: /_project.yaml |
| 2 | Book: /_book.yaml |
| 3 | |
| 4 | # Best Practices |
| 5 | |
| 6 | This page assumes you are familiar with Bazel and provides guidelines and |
| 7 | advice on structuring your projects to take full advantage of Bazel's features. |
| 8 | |
| 9 | The overall goals are: |
| 10 | |
| 11 | - To use fine-grained dependencies to allow parallelism and incrementality. |
| 12 | - To keep dependencies well-encapsulated. |
| 13 | - To make code well-structured and testable. |
| 14 | - To create a build configuration that is easy to understand and maintain. |
| 15 | |
| 16 | These guidelines are not requirements: few projects will be able to adhere to |
| 17 | all of them. As the man page for lint says, "A special reward will be presented |
| 18 | to the first person to produce a real program that produces no errors with |
| 19 | strict checking." However, incorporating as many of these principles as possible |
| 20 | should make a project more readable, less error-prone, and faster to build. |
| 21 | |
| 22 | This page uses the requirement levels described in |
| 23 | [this RFC](https://www.ietf.org/rfc/rfc2119.txt){: .external}. |
| 24 | |
| 25 | ## Running builds and tests {:#running-builds-tests} |
| 26 | |
| 27 | A project should always be able to run `bazel build //...` and |
| 28 | `bazel test //...` successfully on its stable branch. Targets that are necessary |
| 29 | but do not build under certain circumstances (such as,require specific build |
| 30 | flags, don't build on a certain platform, require license agreements) should be |
| 31 | tagged as specifically as possible (for example, "`requires-osx`"). This |
| 32 | tagging allows targets to be filtered at a more fine-grained level than the |
| 33 | "manual" tag and allows someone inspecting the `BUILD` file to understand what |
| 34 | a target's restrictions are. |
| 35 | |
| 36 | ## Third-party dependencies {:#third-party-dependencies} |
| 37 | |
| 38 | You may declare third-party dependencies: |
| 39 | |
| 40 | * Either declare them as remote repositories in the `WORKSPACE` file. |
| 41 | * Or put them in a directory called `third_party/` under your workspace directory. |
| 42 | |
| 43 | ## Depending on binaries {:#binaries} |
| 44 | |
| 45 | Everything should be built from source whenever possible. Generally this means |
| 46 | that, instead of depending on a library `some-library.so`, you'd create a |
| 47 | `BUILD` file and build `some-library.so` from its sources, then depend on that |
| 48 | target. |
| 49 | |
| 50 | Always building from source ensures that a build is not using a library that |
| 51 | was built with incompatible flags or a different architecture. There are also |
| 52 | some features like coverage, static analysis, or dynamic analysis that only |
| 53 | work on the source. |
| 54 | |
| 55 | ## Versioning {:#versioning} |
| 56 | |
| 57 | Prefer building all code from head whenever possible. When versions must be |
| 58 | used, avoid including the version in the target name (for example, `//guava`, |
| 59 | not `//guava-20.0`). This naming makes the library easier to update (only one |
| 60 | target needs to be updated). It's also more resilient to diamond dependency |
| 61 | issues: if one library depends on `guava-19.0` and one depends on `guava-20.0`, |
| 62 | you could end up with a library that tries to depend on two different versions. |
| 63 | If you created a misleading alias to point both targets to one `guava` library, |
| 64 | then the `BUILD` files are misleading. |
| 65 | |
| 66 | ## Using the `.bazelrc` file {:#bazelrc-file} |
| 67 | |
| 68 | For project-specific options, use the configuration file your |
| 69 | `{{ '<var>' }}workspace{{ '</var>' }}/.bazelrc` (see [bazelrc format](/docs/bazelrc)). |
| 70 | |
| 71 | If you want to support per-user options for your project that you **do not** |
| 72 | want to check into source control, include the line: |
| 73 | |
| 74 | ``` |
| 75 | try-import %workspace%/user.bazelrc |
| 76 | ``` |
| 77 | (or any other file name) in your `{{ '<var>' }}workspace{{ '</var>' }}/.bazelrc` |
| 78 | and add `user.bazelrc` to your `.gitignore`. |
| 79 | |
| 80 | ## Packages {:#packages} |
| 81 | |
| 82 | Every directory that contains buildable files should be a package. If a `BUILD` |
| 83 | file refers to files in subdirectories (such as, `srcs = ["a/b/C.java"]`) it's |
| 84 | a sign that a `BUILD` file should be added to that subdirectory. The longer |
| 85 | this structure exists, the more likely circular dependencies will be |
| 86 | inadvertently created, a target's scope will creep, and an increasing number |
| 87 | of reverse dependencies will have to be updated. |