blob: 29646ed6a2f84a74fbf6a4919f531c019a2924d8 [file] [log] [blame] [view]
---
layout: 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](/docs/build-ref.html#workspaces). 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](/docs/be/workspace.html) 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`](http://bazel.io/docs/bazel-user-manual.html#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).
<a name="transitive-dependencies"></a>
## 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](https://github.com/bazelbuild/bazel) to use it.
`cd` to the GitHub clone and run the following to build the tool and see usage:
```
bazel run //src/tools/generate_workspace
```
You can either specify directories containing Bazel projects (i.e., `WORKSPACE`
files) or Maven projects (i.e., `pom.xml` files). For example:
```bash
$ bazel run //src/tools/generate_workspace -- \
> --maven_project=/path/to/my/project \
> --bazel_project=/path/to/skunkworks \
> --bazel_project=/path/to/teleporter/project
Wrote:
/tmp/1437415510621-0/2015-07-20-14-05-10.WORKSPACE
/tmp/1437415510621-0/2015-07-20-14-05-10.BUILD
```
The `WORKSPACE` file contains the transitive dependencies of given projects. The
`BUILD` file contains 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 or Maven projects, 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:
```python
# 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`](http://bazel.io/docs/be/workspace.html#local_repository)
or [`http_archive`](http://bazel.io/docs/be/workspace.html#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`:
```python
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`](http://bazel.io/docs/be/workspace.html#new_local_repository)
and [`new_http_archive`](http://bazel.io/docs/be/workspace.html#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`:
```python
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:
```python
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.