File: external.md

package info (click to toggle)
bazel-bootstrap 4.2.3%2Bds-11
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 85,704 kB
  • sloc: java: 721,717; sh: 55,859; cpp: 35,360; python: 12,139; xml: 295; objc: 269; makefile: 113; ansic: 106; ruby: 3
file content (381 lines) | stat: -rwxr-xr-x 14,142 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
---
layout: documentation
title: External dependencies
---

# Working with external dependencies

Bazel can depend on targets from other projects.  Dependencies from these other
projects are called _external dependencies_.

The `WORKSPACE` file (or `WORKSPACE.bazel` file) in the [workspace directory](build-ref.html#workspace)
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. It uses the same syntax as BUILD
files, but allows a different set of rules called _repository rules_ (sometimes
also known as _workspace rules_). Bazel comes with a few [built-in repository
rules](be/workspace.html) and a set of [embedded Starlark repository
rules](repo/index.html). Users can also write [custom repository
rules](skylark/repository_rules.html) to get more complex behavior.

<a name="types"></a>
## Supported types of external dependencies

A few basic types of external dependencies can be used:

- [Dependencies on other Bazel projects](#bazel-projects)
- [Dependencies on non-Bazel projects](#non-bazel-projects)
- [Dependencies on external packages](#external-packages)

<a name="bazel-projects"></a>
### Depending on other Bazel projects

If you want to use targets from a second Bazel project, you can
use
[`local_repository`](http://docs.bazel.build/be/workspace.html#local_repository),
[`git_repository`](repo/git.html#git_repository)
or [`http_archive`](repo/http.html#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`:

```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`. External project names must be
[valid workspace names](skylark/lib/globals.html#workspace), so `_` (valid) is used to
replace `-` (invalid) in the name `coworkers_project`.

<a name="non-bazel-projects"></a>
### Depending on non-Bazel projects

Rules prefixed with `new_`, e.g.,
[`new_local_repository`](http://docs.bazel.build/be/workspace.html#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`:

```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
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.

<a name="external-packages"></a>
### Depending on external packages

<a name="maven-repositories"></a>
#### Maven artifacts and repositories

Use the ruleset [`rules_jvm_external`](https://github.com/bazelbuild/rules_jvm_external)
to download artifacts from Maven repositories and make them available as Java
dependencies.

<a name="fetching-dependencies"></a>
## Fetching dependencies

By default, external dependencies are fetched as needed during `bazel build`. If
you would like to prefetch the dependencies needed for a specific set of targets, use
[`bazel fetch`](https://docs.bazel.build/versions/master/command-line-reference.html#commands).
To unconditionally fetch all external dependencies, use
[`bazel sync`](https://docs.bazel.build/versions/master/command-line-reference.html#commands).
As fetched repositories are [stored in the output base](#layout), fetching
happens per workspace.

<a name="shadowing-dependencies"></a>
## Shadowing dependencies

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

```python
workspace(name = "myproject")

local_repository(
    name = "A",
    path = "../A",
)
local_repository(
    name = "B",
    path = "../B",
)
```

A/WORKSPACE

```python
workspace(name = "A")

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

```python
workspace(name = "B")

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:

```python
workspace(name = "myproject")

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.

## Overriding repositories from the command line

To override a declared repository with a local repository from the command line,
use the
[`--override_repository`](command-line-reference.html#flag--override_repository)
flag. Using this flag changes the contents of external repositories without
changing your source code.

For example, to override `@foo` to the local directory `/path/to/local/foo`,
pass the `--override_repository=foo=/path/to/local/foo` flag.

Some of the use cases include:

* Debugging issues. For example, you can override a `http_archive` repository
  to a local directory where you can make changes more easily.
* Vendoring. If you are in an environment where you cannot make network calls,
  override the network-based repository rules to point to local directories
  instead.

<a name="using-proxies"></a>
## 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="support-for-ipv6"></a>
## Support for IPv6
On IPv6-only machines, Bazel will be able to download dependencies with
no changes. On dual-stack IPv4/IPv6 machines, however, Bazel follows the same
convention as Java: if IPv4 is enabled, IPv4 is preferred. In some situations,
for example when IPv4 network is unable to resolve/reach external addresses,
this can cause `Network unreachable` exceptions and build failures.
In these cases, you can override Bazel's behavior to prefer IPv6
by using [`java.net.preferIPv6Addresses=true` system property](https://docs.oracle.com/javase/8/docs/api/java/net/doc-files/net-properties.html).
Specifically:

* Use `--host_jvm_args=-Djava.net.preferIPv6Addresses=true`
  [startup option](user-manual.html#startup_options),
  for example by adding the following line in your
  [`.bazelrc` file](guide.html#bazelrc):

  `startup --host_jvm_args=-Djava.net.preferIPv6Addresses=true`

* If you are running Java build targets that need to connect to the internet
  as well (integration tests sometimes needs that), also use
  `--jvmopt=-Djava.net.preferIPv6Addresses=true`
  [tool flag](user-manual.html#flags-options), for example by having the
  following line in your [`.bazelrc` file](guide.html#bazelrc):

  `build --jvmopt=-Djava.net.preferIPv6Addresses`

* If you are using
  [rules_jvm_external](https://github.com/bazelbuild/rules_jvm_external),
  for example, for dependency version resolution, also add
  `-Djava.net.preferIPv6Addresses=true` to the `COURSIER_OPTS`
  environment variable to [provide JVM options for Coursier](https://github.com/bazelbuild/rules_jvm_external#provide-jvm-options-for-coursier-with-coursier_opts)

<a name="transitive-dependencies"></a>
## Transitive dependencies

Bazel only reads dependencies listed in your `WORKSPACE` file. If your project
(`A`) depends on another project (`B`) which lists 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 limits the chances of having one library
include `C` at version 1.0 and another include `C` at 2.0.

<a name="caching"></a>
## Caching of external dependencies

By default, Bazel will only re-download external dependencies if their
definition changes. Changes to files referenced in the definition (e.g., patches
or `BUILD` files) are also taken into account by bazel.

To force a re-download, use `bazel sync`.


<a name="layout"></a>
## Layout

External dependencies are all downloaded to a directory under the subdirectory
`external` in the [output base](output_directories.html). In case of a
[local repository](be/workspace.html#local_repository), a symlink is created
there instead of creating a new directory.
You can see the `external` 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`.

## Offline builds

It is sometimes desirable or necessary to run a build in an offline fashion. For
simple use cases, e.g., traveling on an airplane,
[prefetching](#fetching-dependencies) the needed
repositories with `bazel fetch` or `bazel sync` can be enough; moreover, the
using the option `--nofetch`, fetching of further repositories can be disabled
during the build.

For true offline builds, where the providing of the needed files is to be done
by an entity different from bazel, bazel supports the option
`--distdir`. Whenever a repository rule asks bazel to fetch a file via
[`ctx.download`](skylark/lib/repository_ctx.html#download) or
[`ctx.download_and_extract`](skylark/lib/repository_ctx.html#download_and_extract)
and provides a hash sum of the file
needed, bazel will first look into the directories specified by that option for
a file matching the basename of the first URL provided, and use that local copy
if the hash matches.

Bazel itself uses this technique to bootstrap offline from the [distribution
artifact](https://bazel.build/designs/2016/10/11/distribution-artifact.html).
It does so by [collecting all the needed external
dependencies](https://github.com/bazelbuild/bazel/blob/5cfa0303d6ac3b5bd031ff60272ce80a704af8c2/WORKSPACE#L116)
in an internal
[`distdir_tar`](https://github.com/bazelbuild/bazel/blob/5cfa0303d6ac3b5bd031ff60272ce80a704af8c2/distdir.bzl#L44).

However, bazel allows the execution of arbitrary commands in repository rules,
without knowing if they call out to the network. Therefore, bazel has no option
to enforce builds being fully offline. So testing if a build works correctly
offline requires external blocking of the network, as bazel does in its
bootstrap test.

## Best practices

### Repository rules

Prefer [`http_archive`](repo/http.html#http_archive) to `git_repository` and
`new_git_repository`. The reasons are:

* Git repository rules depend on system `git(1)` whereas the HTTP downloader is built
  into Bazel and has no system dependencies.
* `http_archive` supports a list of `urls` as mirrors, and `git_repository` supports only
  a single `remote`.
* `http_archive` works with the [repository cache](guide.html#repository-cache), but not
  `git_repository`. See
   [#5116](https://github.com/bazelbuild/bazel/issues/5116) for more information.


Do not use `bind()`.  See "[Consider removing
bind](https://github.com/bazelbuild/bazel/issues/1952)" for a long discussion of its issues and
alternatives.

### Repository rules

A repository rule should generally be responsible for:

-  Detecting system settings and writing them to files.
-  Finding resources elsewhere on the system.
-  Downloading resources from URLs.
-  Generating or symlinking BUILD files into the external repository directory.

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"])`.