blob: 722b162ea1f1a39165b5920017a7d9283ad3e95e [file] [log] [blame] [view]
fweacae1cd2022-02-17 09:45:38 -08001Project: /_project.yaml
2Book: /_book.yaml
3
4# Working with External Dependencies
5
6Bazel can depend on targets from other projects. Dependencies from these other
7projects are called _external dependencies_.
8
9Note: Bazel 5.0 and newer has a new external dependency system, codenamed
10"Bzlmod", which renders a lot of the content on this page obsolete. See [Bzlmod
11user guide](/docs/bzlmod) for more information.
12
13The `WORKSPACE` file (or `WORKSPACE.bazel` file) in the
14[workspace directory](/concepts/build-ref#workspace)
15tells Bazel how to get other projects' sources. These other projects can
16contain one or more `BUILD` files with their own targets. `BUILD` files within
17the main project can depend on these external targets by using their name from
18the `WORKSPACE` file.
19
20For example, suppose there are two projects on a system:
21
22```
23/
24 home/
25 user/
26 project1/
27 WORKSPACE
28 BUILD
29 srcs/
30 ...
31 project2/
32 WORKSPACE
33 BUILD
34 my-libs/
35```
36
37If `project1` wanted to depend on a target, `:foo`, defined in
38`/home/user/project2/BUILD`, it could specify that a repository named
39`project2` could be found at `/home/user/project2`. Then targets in
40`/home/user/project1/BUILD` could depend on `@project2//:foo`.
41
42The `WORKSPACE` file allows users to depend on targets from other parts of the
43filesystem or downloaded from the internet. It uses the same syntax as `BUILD`
44files, but allows a different set of rules called _repository rules_ (sometimes
45also known as _workspace rules_). Bazel comes with a few [built-in repository
46rules](/reference/be/workspace) and a set of [embedded Starlark repository
47rules](/rules/lib/repo/index). Users can also write [custom repository
48rules](/rules/repository_rules) to get more complex behavior.
49
50## Supported types of external dependencies {:#types}
51
52A few basic types of external dependencies can be used:
53
54- [Dependencies on other Bazel projects](#bazel-projects)
55- [Dependencies on non-Bazel projects](#non-bazel-projects)
56- [Dependencies on external packages](#external-packages)
57
58### Depending on other Bazel projects {:#bazel-projects}
59
60If you want to use targets from a second Bazel project, you can
61use
62[`local_repository`](/reference/be/workspace#local_repository),
63[`git_repository`](/rules/lib/repo/git#git_repository)
64or [`http_archive`](/rules/lib/repo/http#http_archive)
65to symlink it from the local filesystem, reference a git repository or download
66it (respectively).
67
68For example, suppose you are working on a project, `my-project/`, and you want
69to depend on targets from your coworker's project, `coworkers-project/`. Both
70projects use Bazel, so you can add your coworker's project as an external
71dependency and then use any targets your coworker has defined from your own
72BUILD files. You would add the following to `my_project/WORKSPACE`:
73
74```python
75local_repository(
76 name = "coworkers_project",
77 path = "/path/to/coworkers-project",
78)
79```
80
81If your coworker has a target `//foo:bar`, your project can refer to it as
82`@coworkers_project//foo:bar`. External project names must be
83[valid workspace names](/rules/lib/globals#workspace).
84
85### Depending on non-Bazel projects {:#non-bazel-projects}
86
87Rules prefixed with `new_`, such as
88[`new_local_repository`](/reference/be/workspace#new_local_repository),
89allow you to create targets from projects that do not use Bazel.
90
91For example, suppose you are working on a project, `my-project/`, and you want
92to depend on your coworker's project, `coworkers-project/`. Your coworker's
93project uses `make` to build, but you'd like to depend on one of the .so files
94it generates. To do so, add the following to `my_project/WORKSPACE`:
95
96```python
97new_local_repository(
98 name = "coworkers_project",
99 path = "/path/to/coworkers-project",
100 build_file = "coworker.BUILD",
101)
102```
103
104`build_file` specifies a `BUILD` file to overlay on the existing project, for
105example:
106
107```python
108cc_library(
109 name = "some-lib",
110 srcs = glob(["**"]),
111 visibility = ["//visibility:public"],
112)
113```
114
115You can then depend on `@coworkers_project//:some-lib` from your project's
116`BUILD` files.
117
118### Depending on external packages {:#external-packages}
119
120#### Maven artifacts and repositories {:#maven-repositories}
121
122Use the ruleset [`rules_jvm_external`](https://github.com/bazelbuild/rules_jvm_external){: .external}
123to download artifacts from Maven repositories and make them available as Java
124dependencies.
125
126## Fetching dependencies {:#fetching-dependencies}
127
128By default, external dependencies are fetched as needed during `bazel build`. If
129you would like to prefetch the dependencies needed for a specific set of targets, use
130[`bazel fetch`](/reference/command-line-reference#commands).
131To unconditionally fetch all external dependencies, use
132[`bazel sync`](/reference/command-line-reference#commands).
133As fetched repositories are [stored in the output base](#layout), fetching
134happens per workspace.
135
136## Shadowing dependencies {:#shadowing-dependencies}
137
138Whenever possible, it is recommended to have a single version policy in your
139project. This is required for dependencies that you compile against and end up
140in your final binary. But for cases where this isn't true, it is possible to
141shadow dependencies. Consider the following scenario:
142
143myproject/WORKSPACE
144
145```python
146workspace(name = "myproject")
147
148local_repository(
149 name = "A",
150 path = "../A",
151)
152local_repository(
153 name = "B",
154 path = "../B",
155)
156```
157
158A/WORKSPACE
159
160```python
161workspace(name = "A")
162
163load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
164http_archive(
165 name = "testrunner",
166 urls = ["https://github.com/testrunner/v1.zip"],
167 sha256 = "...",
168)
169```
170
171B/WORKSPACE
172
173```python
174workspace(name = "B")
175
176load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
177http_archive(
178 name = "testrunner",
179 urls = ["https://github.com/testrunner/v2.zip"],
180 sha256 = "..."
181)
182```
183
184Both dependencies `A` and `B` depend on `testrunner`, but they depend on
185different versions of `testrunner`. There is no reason for these test runners to
186not peacefully coexist within `myproject`, however they will clash with each
187other since they have the same name. To declare both dependencies,
188update myproject/WORKSPACE:
189
190```python
191workspace(name = "myproject")
192
193load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
194http_archive(
195 name = "testrunner-v1",
196 urls = ["https://github.com/testrunner/v1.zip"],
197 sha256 = "..."
198)
199http_archive(
200 name = "testrunner-v2",
201 urls = ["https://github.com/testrunner/v2.zip"],
202 sha256 = "..."
203)
204local_repository(
205 name = "A",
206 path = "../A",
207 repo_mapping = {"@testrunner" : "@testrunner-v1"}
208)
209local_repository(
210 name = "B",
211 path = "../B",
212 repo_mapping = {"@testrunner" : "@testrunner-v2"}
213)
214```
215
216This mechanism can also be used to join diamonds. For example if `A` and `B`
217had the same dependency but call it by different names, those dependencies can
218be joined in myproject/WORKSPACE.
219
220## Overriding repositories from the command line {:#overriding-repositories}
221
222To override a declared repository with a local repository from the command line,
223use the
224[`--override_repository`](/reference/command-line-reference#flag--override_repository)
225flag. Using this flag changes the contents of external repositories without
226changing your source code.
227
228For example, to override `@foo` to the local directory `/path/to/local/foo`,
229pass the `--override_repository=foo=/path/to/local/foo` flag.
230
231Some of the use cases include:
232
233* Debugging issues. For example, you can override a `http_archive` repository
234 to a local directory where you can make changes more easily.
235* Vendoring. If you are in an environment where you cannot make network calls,
236 override the network-based repository rules to point to local directories
237 instead.
238
239## Using proxies {:#using-proxies}
240
241Bazel will pick up proxy addresses from the `HTTPS_PROXY` and `HTTP_PROXY`
242environment variables and use these to download HTTP/HTTPS files (if specified).
243
244## Support for IPv6 {:#support-for-ipv6}
245
246On IPv6-only machines, Bazel will be able to download dependencies with
247no changes. On dual-stack IPv4/IPv6 machines, however, Bazel follows the same
248convention as Java: if IPv4 is enabled, IPv4 is preferred. In some situations,
249for example when IPv4 network is unable to resolve/reach external addresses,
250this can cause `Network unreachable` exceptions and build failures.
251In these cases, you can override Bazel's behavior to prefer IPv6
252by using [`java.net.preferIPv6Addresses=true` system property](https://docs.oracle.com/javase/8/docs/api/java/net/doc-files/net-properties.html){: .external}.
253Specifically:
254
255* Use `--host_jvm_args=-Djava.net.preferIPv6Addresses=true`
fwe6c2bd4a2022-02-18 10:47:46 -0800256 [startup option](/docs/user-manual#startup-options),
fweacae1cd2022-02-17 09:45:38 -0800257 for example by adding the following line in your
258 [`.bazelrc` file](/docs/bazelrc):
259
260 `startup --host_jvm_args=-Djava.net.preferIPv6Addresses=true`
261
262* If you are running Java build targets that need to connect to the internet
263 as well (integration tests sometimes needs that), also use
264 `--jvmopt=-Djava.net.preferIPv6Addresses=true`
fwe6c2bd4a2022-02-18 10:47:46 -0800265 [tool flag](/docs/user-manual#jvmopt), for example by having the
fweacae1cd2022-02-17 09:45:38 -0800266 following line in your [`.bazelrc` file](/docs/bazelrc):
267
268 `build --jvmopt=-Djava.net.preferIPv6Addresses`
269
270* If you are using
271 [rules_jvm_external](https://github.com/bazelbuild/rules_jvm_external){: .external},
272 for example, for dependency version resolution, also add
273 `-Djava.net.preferIPv6Addresses=true` to the `COURSIER_OPTS`
274 environment variable to [provide JVM options for Coursier](https://github.com/bazelbuild/rules_jvm_external#provide-jvm-options-for-coursier-with-coursier_opts){: .external}
275
276## Transitive dependencies {:#transitive-dependencies}
277
278Bazel only reads dependencies listed in your `WORKSPACE` file. If your project
279(`A`) depends on another project (`B`) which lists a dependency on a third
280project (`C`) in its `WORKSPACE` file, you'll have to add both `B`
281and `C` to your project's `WORKSPACE` file. This requirement can balloon the
282`WORKSPACE` file size, but limits the chances of having one library
283include `C` at version 1.0 and another include `C` at 2.0.
284
285## Caching of external dependencies {:#caching-external-dependencies}
286
287By default, Bazel will only re-download external dependencies if their
288definition changes. Changes to files referenced in the definition (such as patches
289or `BUILD` files) are also taken into account by bazel.
290
291To force a re-download, use `bazel sync`.
292
293## Layout {:#layout}
294
295External dependencies are all downloaded to a directory under the subdirectory
296`external` in the [output base](/docs/output_directories). In case of a
297[local repository](/reference/be/workspace#local_repository), a symlink is created
298there instead of creating a new directory.
299You can see the `external` directory by running:
300
301```posix-terminal
302ls $(bazel info output_base)/external
303```
304
305Note that running `bazel clean` will not actually delete the external
306directory. To remove all external artifacts, use `bazel clean --expunge`.
307
308## Offline builds {:#offline-builds}
309
310It is sometimes desirable or necessary to run a build in an offline fashion. For
311simple use cases, such as traveling on an airplane,
312[prefetching](#fetching-dependencies) the needed
313repositories with `bazel fetch` or `bazel sync` can be enough; moreover, the
314using the option `--nofetch`, fetching of further repositories can be disabled
315during the build.
316
317For true offline builds, where the providing of the needed files is to be done
318by an entity different from bazel, bazel supports the option
319`--distdir`. Whenever a repository rule asks bazel to fetch a file via
320[`ctx.download`](/rules/lib/repository_ctx#download) or
321[`ctx.download_and_extract`](/rules/lib/repository_ctx#download_and_extract)
322and provides a hash sum of the file
323needed, bazel will first look into the directories specified by that option for
324a file matching the basename of the first URL provided, and use that local copy
325if the hash matches.
326
327Bazel itself uses this technique to bootstrap offline from the [distribution
fwe6c2bd4a2022-02-18 10:47:46 -0800328artifact](https://github.com/bazelbuild/bazel-website/blob/master/designs/_posts/2016-10-11-distribution-artifact.md).
fweacae1cd2022-02-17 09:45:38 -0800329It does so by [collecting all the needed external
330dependencies](https://github.com/bazelbuild/bazel/blob/5cfa0303d6ac3b5bd031ff60272ce80a704af8c2/WORKSPACE#L116){: .external}
331in an internal
332[`distdir_tar`](https://github.com/bazelbuild/bazel/blob/5cfa0303d6ac3b5bd031ff60272ce80a704af8c2/distdir.bzl#L44){: .external}.
333
334However, bazel allows the execution of arbitrary commands in repository rules,
335without knowing if they call out to the network. Therefore, bazel has no option
336to enforce builds being fully offline. So testing if a build works correctly
337offline requires external blocking of the network, as bazel does in its
338bootstrap test.
339
340## Best practices {:#best-practices}
341
342### Repository rules {:#repository-rules}
343
344A repository rule should generally be responsible for:
345
346- Detecting system settings and writing them to files.
347- Finding resources elsewhere on the system.
348- Downloading resources from URLs.
349- Generating or symlinking BUILD files into the external repository directory.
350
351Avoid using `repository_ctx.execute` when possible. For example, when using a non-Bazel C++
352library that has a build using Make, it is preferable to use `repository_ctx.download()` and then
353write a BUILD file that builds it, instead of running `ctx.execute(["make"])`.
354
355Prefer [`http_archive`](/rules/lib/repo/http#http_archive) to `git_repository` and
356`new_git_repository`. The reasons are:
357
358* Git repository rules depend on system `git(1)` whereas the HTTP downloader is built
359 into Bazel and has no system dependencies.
360* `http_archive` supports a list of `urls` as mirrors, and `git_repository` supports only
361 a single `remote`.
362* `http_archive` works with the [repository cache](/docs/build#repository-cache), but not
363 `git_repository`. See
364 [#5116](https://github.com/bazelbuild/bazel/issues/5116){: .external} for more information.
365
366Do not use `bind()`. See "[Consider removing
367bind](https://github.com/bazelbuild/bazel/issues/1952){: .external}" for a long
368discussion of its issues and alternatives.