Bazel can depend on targets from other projects. Dependencies from these other projects are called external dependencies.
The WORKSPACE
file in the workspace directory tells Bazel how to get other projects' sources. These other projects can contain one or more BUILD
files with their own targets. BUILD
files within the main project can depend on these external targets by using their name from the WORKSPACE
file.
For example, suppose there are two projects on a system:
/ home/ user/ project1/ WORKSPACE BUILD srcs/ ... project2/ WORKSPACE BUILD my-libs/
If project1
wanted to depend on a target, :foo
, defined in /home/user/project2/BUILD
, it could specify that a repository named project2
could be found at /home/user/project2
. Then targets in /home/user/project1/BUILD
could depend on @project2//:foo
.
The WORKSPACE
file allows users to depend on targets from other parts of the filesystem or downloaded from the internet. Users can also write custom repository rules to get more complex behavior.
This WORKSPACE
file uses the same syntax as BUILD files, but allows a different set of rules. The full list of built-in rules are in the Build Encyclopedia's Workspace Rules.
A few basic types of external dependencies can be used:
If you want to use targets from a second Bazel project, you can use local_repository
, git_repository
or http_archive
to symlink it from the local filesystem, reference a git repository 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
. External project names must be valid workspace names, so _
(valid) is used to replace -
(invalid) in the name coworkers_project
.
Rules prefixed with new_
, e.g., new_local_repository
, 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:
cc_library( name = "some-lib", srcs = glob(["**"]), visibility = ["//visibility:public"], )
You can then depend on @coworkers_project//:some-lib
from your project's BUILD files.
Use the rule maven_jar
(and optionally the rule maven_server
) to download a jar from a Maven repository and make it available as a Java dependency.
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
.
Whenever possible, it is recommended to have a single version policy in your project. This is required for dependencies that you compile against and end up in your final binary. But for cases where this isn't true, it is possible to shadow dependencies. Consider the following scenario:
myproject/WORKSPACE
local_repository( name = "A", path = "../A", ) local_repository( name = "B", path = "../B", )
A/WORKSPACE
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "testrunner", urls = ["https://github.com/testrunner/v1.zip"], sha256 = "...", )
B/WORKSPACE
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "testrunner", urls = ["https://github.com/testrunner/v2.zip"], sha256 = "..." )
Both dependencies A
and B
depend on testrunner
, but they depend on different versions of testrunner
. There is no reason for these test runners to not peacefully coexist within myproject
, however they will clash with each other since they have the same name. To declare both dependencies, update myproject/WORKSPACE:
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "testrunner-v1", urls = ["https://github.com/testrunner/v1.zip"], sha256 = "..." ) http_archive( name = "testrunner-v2", urls = ["https://github.com/testrunner/v2.zip"], sha256 = "..." ) local_repository( name = "A", path = "../A", repo_mapping = {"@testrunner" : "@testrunner-v1"} ) local_repository( name = "B", path = "../B", repo_mapping = {"@testrunner" : "@testrunner-v2"} )
This mechanism can also be used to join diamonds. For example if A
and B
had the same dependency but call it by different names, those dependencies can be joined in myproject/WORKSPACE.
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).
Bazel only reads dependencies listed in your WORKSPACE
file. If your project (A
) depends on another project (B
) which list a dependency on a third project (C
) in its WORKSPACE
file, you‘ll have to add both B
and C
to your project’s WORKSPACE
file. This requirement 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.
Large WORKSPACE
files can be generated using the tool generate_workspace
. For details, see Generate external dependencies from Maven projects.
Bazel caches external dependencies and re-downloads or updates them when the WORKSPACE
file changes.
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
.
Prefer http_archive
and new_http_archive
to git_repository
, new_git_repository
, and maven_jar
.
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:
Do not use bind()
. See “Consider removing bind” for a long discussion of its issues and alternatives.
When using a new_
repository rule, prefer to specify build_file_content
, not build_file
.
A repository rule should generally be responsible for:
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"])
.