Documentation

Working with external dependencies

Bazel is designed to have absolutely everything needed for a build, from source code to libraries to compilers, under one directory (the workspace directory). This is impractical for some version control systems and goes against how many existing projects are structured. Thus, Bazel has a system for pulling in dependencies from outside of the workspace.

External dependencies can be specified in a WORKSPACE file in the workspace directory. This WORKSPACE file uses the same Python-like syntax of BUILD files, but allows a different set of rules. See the full list of rules that are allowed in the Workspace list of rules in the Build Encyclopedia.

External dependencies are all downloaded and symlinked under a directory named external. You can see this directory by running:

ls $(bazel info output_base)/external

Note that running bazel clean will not actually delete the external directory: to remove all external artifacts, use bazel clean --expunge.

Fetching dependencies

By default, external dependencies are fetched as needed during bazel build. If you would like to disable this behavior or prefetch dependencies, use bazel fetch.

Using Proxies

Bazel will pick up proxy addresses from the HTTPS_PROXY and HTTP_PROXY environment variables and use these to download HTTP/HTTPS files (if specified).

Transitive dependencies

Bazel only reads dependencies listed in your WORKSPACE file. This means that if your project (A) depends on another project (B) which list a dependency on project C in its WORKSPACE file, you'll have to add both B and C to your project's WORKSPACE file. This can balloon the WORKSPACE file size, but hopefully limits the chances of having one library include C at version 1.0 and another include C at 2.0.

Bazel provides a tool to help generate these expansive WORKSPACE files, called generate_workspace. This is not included with the binary installer, so you'll need to clone the GitHub repo to use it. We recommend using the tag corresponding to your current version of bazel, which you can check by running bazel version.

cd to the GitHub clone, git checkout the appropriate tag, and run the following to build the tool and see usage:

bazel run //src/tools/generate_workspace

Note that you need run this from your Bazel source folder even if you build your binary from source.

You can specify directories containing Bazel projects (i.e., directories containing a WORKSPACE file), Maven projects (i.e., directories containing a pom.xml file), or Maven artifact coordinates directly. For example:

$ bazel run //src/tools/generate_workspace -- \
>    --maven_project=/path/to/my/project \
>    --bazel_project=/path/to/skunkworks \
>    --bazel_project=/path/to/teleporter/project \
>    --artifact=groupId:artifactId:version \
>    --artifact=groupId:artifactId:version
Wrote:
/tmp/1437415510621-0/2015-07-20-14-05-10.WORKSPACE
/tmp/1437415510621-0/2015-07-20-14-05-10.BUILD

The WORKSPACE file will contain the transitive dependencies of the given projects and artifacts. The BUILD file will contain a single target, transitive-deps, that contains all of the dependencies. You can copy these files to your project and add transitive-deps as a dependency of your java_ targets in BUILD files.

If you specify multiple Bazel projects, Maven projects, or artifacts, they will all be combined into one WORKSPACE file (e.g., if the Bazel project depends on junit and the Maven project also depends on junit, junit will only appear once as a dependency in the output).

You may wish to curate the generated WORKSPACE file to ensure it is using the correct version of each dependency. If several different versions of an artifact are requested (by different libraries that depend on it), then generate_workspace chooses a version and annotates the maven_jar with the other versions requested, for example:

# org.springframework:spring:2.5.6
# javax.mail:mail:1.4
# httpunit:httpunit:1.6 wanted version 1.0.2
# org.springframework:spring-support:2.0.2 wanted version 1.0.2
# org.slf4j:nlog4j:1.2.24 wanted version 1.0.2
maven_jar(
    name = "javax_activation_activation",
    artifact = "javax.activation:activation:1.1",
)

This indicates that org.springframework:spring:2.5.6, javax.mail:mail:1.4, httpunit:httpunit:1.6, org.springframework:spring-support:2.0.2, and org.slf4j:nlog4j:1.2.24 all depend on javax.activation. However, two of these libraries wanted version 1.1 and three of them wanted 1.0.2. The WORKSPACE file is using version 1.1, but that might not be the right version to use.

You may also want to break transitive-deps into smaller targets, as it is unlikely that all of your targets depend on the transitive closure of your maven jars.

Types of external dependencies

There are a few basic types of external dependencies that can be created.

Combining Bazel projects

If you have a second Bazel project that you'd like to use targets from, you can use local_repository or http_archive to symlink it from the local filesystem or download it (respectively).

For example, suppose you are working on a project, my-project/, and you want to depend on targets from your coworker's project, coworkers-project/. Both projects use Bazel, so you can add your coworker's project as an external dependency and then use any targets your coworker has defined from your own BUILD files. You would add the following to my_project/WORKSPACE:

local_repository(
    name = "coworkers-project",
    path = "/path/to/coworkers-project",
)

If your coworker has a target //foo:bar, your project can refer to it as @coworkers-project//foo:bar.

Depending on non-Bazel projects

Rules prefixed with new_ (e.g., new_local_repository and new_http_archive ) allow you to create targets from projects that do not use Bazel.

For example, suppose you are working on a project, my-project/, and you want to depend on your coworker's project, coworkers-project/. Your coworker's project uses make to build, but you'd like to depend on one of the .so files it generates. To do so, add the following to my_project/WORKSPACE:

new_local_repository(
    name = "coworkers-project",
    path = "/path/to/coworkers-project",
    build_file = "coworker.BUILD",
)

build_file specifies a BUILD file to overlay on the existing project, for example:

java_library(
    name = "some-lib",
    srcs = glob(["**"]),
    visibility = ["//visibility:public"],
)

You can then depend on @coworkers-project//:some-lib from your project's BUILD files.

Caching of external dependencies

Bazel caches external dependencies and only re-downloads or updates them when the WORKSPACE file changes. If the WORKSPACE file does not change, Bazel assumes that the external dependencies have not changed, either. This can cause unexpected results, especially with local repositories.

For instance, in the example above, suppose that my-project/ has a target that depends on @coworkers-project//:a, which you build. Then you change to coworkers-project/ and pull the latest updates to their library, which changes the behavior of @coworkers-project//:a. If you go back to my-project/ and build your target again, it will assume @coworkers-project//:a is already up-to-date and reuse the cached library (instead of realizing that the sources have changed and, thus, rebuilding).

To avoid this situation, prefer remote repositories to local ones and do not manually change the files in [output_base]/external. If you change a file in [output_base]/external, rerun bazel fetch ... to update the cache.