xref: /aosp_15_r20/external/bazelbuild-rules_rust/crate_universe/docs_workspace.bzl (revision d4726bddaa87cc4778e7472feed243fa4b6c267f)
1"""# Crate Universe
2
3Crate Universe is a set of Bazel rule for generating Rust targets using Cargo.
4
5This doc describes using crate_universe from a WORKSPACE file.
6
7If you're using bzlmod, please see [the bzlmod equivalent of this doc](crate_universe_bzlmod.html).
8
9## Setup
10
11After loading `rules_rust` in your workspace, set the following to begin using `crate_universe`:
12
13```python
14load("@rules_rust//crate_universe:repositories.bzl", "crate_universe_dependencies")
15
16crate_universe_dependencies()
17```
18
19Note that if the current version of `rules_rust` is not a release artifact, you may need to set additional
20flags such as [`bootstrap = True`](#crate_universe_dependencies-bootstrap) on the `crate_universe_dependencies`
21call above or [crates_repository::generator_urls](#crates_repository-generator_urls) in uses of `crates_repository`.
22
23## Rules
24
25- [crates_repository](#crates_repository)
26- [crates_vendor](#crates_vendor)
27
28## Utility Macros
29
30- [crate_universe_dependencies](#crate_universe_dependencies)
31- [crate.annotation](#crateannotation)
32- [crate.select](#crateselect)
33- [crate.spec](#cratespec)
34- [crate.workspace_member](#crateworkspace_member)
35- [render_config](#render_config)
36- [splicing_config](#splicing_config)
37
38## Workflows
39
40The [`crates_repository`](#crates_repository) rule (the primary repository rule of `rules_rust`'s cargo support) supports a number of different
41ways users can express and organize their dependencies. The most common are listed below though there are more to be found in
42the [./examples/crate_universe](https://github.com/bazelbuild/rules_rust/tree/main/examples/crate_universe) directory.
43
44### Cargo Workspaces
45
46One of the simpler ways to wire up dependencies would be to first structure your project into a [Cargo workspace][cw].
47The `crates_repository` rule can ingest a root `Cargo.toml` file and generate dependencies from there.
48
49```python
50load("@rules_rust//crate_universe:defs.bzl", "crates_repository")
51
52crates_repository(
53    name = "crate_index",
54    cargo_lockfile = "//:Cargo.lock",
55    lockfile = "//:Cargo.Bazel.lock",
56    manifests = ["//:Cargo.toml"],
57)
58
59load("@crate_index//:defs.bzl", "crate_repositories")
60
61crate_repositories()
62```
63
64The generated `crates_repository` contains helper macros which make collecting dependencies for Bazel targets simpler.
65Notably, the `all_crate_deps` and `aliases` macros (see [Dependencies API](#dependencies-api)) commonly allow the
66`Cargo.toml` files to be the single source of truth for dependencies. Since these macros come from the generated
67repository, the dependencies and alias definitions they return will automatically update BUILD targets.
68
69```python
70load("@crate_index//:defs.bzl", "aliases", "all_crate_deps")
71load("@rules_rust//rust:defs.bzl", "rust_library", "rust_test")
72
73rust_library(
74    name = "lib",
75    aliases = aliases(),
76    deps = all_crate_deps(
77        normal = True,
78    ),
79    proc_macro_deps = all_crate_deps(
80        proc_macro = True,
81    ),
82)
83
84rust_test(
85    name = "unit_test",
86    crate = ":lib",
87    aliases = aliases(
88        normal_dev = True,
89        proc_macro_dev = True,
90    ),
91    deps = all_crate_deps(
92        normal_dev = True,
93    ),
94    proc_macro_deps = all_crate_deps(
95        proc_macro_dev = True,
96    ),
97)
98```
99
100### Direct Packages
101
102In cases where Rust targets have heavy interractions with other Bazel targests ([Cc][cc], [Proto][proto], etc.),
103maintaining `Cargo.toml` files may have deminishing returns as things like [rust-analyzer][ra] begin to be confused
104about missing targets or environment variables defined only in Bazel. In workspaces like this, it may be desirable
105to have a "Cargo free" setup. `crates_repository` supports this through the `packages` attribute.
106
107```python
108load("@rules_rust//crate_universe:defs.bzl", "crate", "crates_repository", "render_config")
109
110crates_repository(
111    name = "crate_index",
112    cargo_lockfile = "//:Cargo.lock",
113    lockfile = "//:Cargo.Bazel.lock",
114    packages = {
115        "async-trait": crate.spec(
116            version = "0.1.51",
117        ),
118        "mockall": crate.spec(
119            version = "0.10.2",
120        ),
121        "tokio": crate.spec(
122            version = "1.12.0",
123        ),
124    },
125    # Setting the default package name to `""` forces the use of the macros defined in this repository
126    # to always use the root package when looking for dependencies or aliases. This should be considered
127    # optional as the repository also exposes alises for easy access to all dependencies.
128    render_config = render_config(
129        default_package_name = ""
130    ),
131)
132
133load("@crate_index//:defs.bzl", "crate_repositories")
134
135crate_repositories()
136```
137
138Consuming dependencies may be more ergonomic in this case through the aliases defined in the new repository.
139
140```python
141load("@rules_rust//rust:defs.bzl", "rust_library", "rust_test")
142
143rust_library(
144    name = "lib",
145    deps = [
146        "@crate_index//:tokio",
147    ],
148    proc_macro_deps = [
149        "@crate_index//:async-trait",
150    ],
151)
152
153rust_test(
154    name = "unit_test",
155    crate = ":lib",
156    deps = [
157        "@crate_index//:mockall",
158    ],
159)
160```
161
162### Binary dependencies
163
164Neither of the above approaches supports depending on binary-only packages.
165
166In order to depend on a Cargo package that contains binaries and no library, you
167will need to do one of the following:
168
169- Fork the package to add an empty lib.rs, which makes the package visible to
170  Cargo metadata and compatible with the above approaches;
171
172- Or handwrite your own build target for the binary, use `http_archive` to
173  import its source code, and use `crates_repository` to make build targets for
174  its dependencies. This is demonstrated below using the `rustfilt` crate as an
175  example.
176
177```python
178# in WORKSPACE.bazel
179
180load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
181
182http_archive(
183    name = "rustfilt",
184    build_file = "//rustfilt:BUILD.rustfilt.bazel",
185    sha256 = "c8d748b182c8f95224336d20dcc5609598af612581ce60cfb29da4dc8d0091f2",
186    strip_prefix = "rustfilt-0.2.1",
187    type = "tar.gz",
188    urls = ["https://static.crates.io/crates/rustfilt/rustfilt-0.2.1.crate"],
189)
190
191load("@rules_rust//crate_universe:defs.bzl", "crates_repository")
192
193crates_repository(
194    name = "rustfilt_deps",
195    cargo_lockfile = "//rustfilt:Cargo.lock",
196    manifests = ["@rustfilt//:Cargo.toml"],
197)
198
199load("@rustfilt_deps//:defs.bzl", rustfilt_deps = "crate_repositories")
200
201rustfilt_deps()
202```
203
204```python
205# in rustfilt/BUILD.rustfilt.bazel
206
207load("@rules_rust//rust:defs.bzl", "rust_binary")
208
209rust_binary(
210    name = "rustfilt",
211    srcs = glob(["src/**/*.rs"]),
212    edition = "2018",
213    deps = [
214        "@rustfilt_deps//:clap",
215        "@rustfilt_deps//:lazy_static",
216        "@rustfilt_deps//:regex",
217        "@rustfilt_deps//:rustc-demangle",
218    ],
219)
220```
221
222If you use either `crates_repository` or `crates_vendor` to depend on a Cargo
223package that contains _both_ a library crate _and_ binaries, by default only the
224library gets made available to Bazel. To generate Bazel targets for the binary
225crates as well, you must opt in to it with an annotation on the package:
226
227```python
228load("@rules_rust//crate_universe:defs.bzl", "crates_repository", "crate")
229
230crates_repository(
231    name = "crate_index",
232    annotations = {
233        "thepackage": [crate.annotation(
234            gen_binaries = True,
235            # Or, to expose just a subset of the package's binaries by name:
236            gen_binaries = ["rustfilt"],
237        )],
238    },
239    # Or, to expose every binary of every package:
240    generate_binaries = True,
241    ...
242)
243```
244
245## Dependencies API
246
247After rendering dependencies, convenience macros may also be generated to provide
248convenient accessors to larger sections of the dependency graph.
249
250- [aliases](#aliases)
251- [crate_deps](#crate_deps)
252- [all_crate_deps](#all_crate_deps)
253- [crate_repositories](#crate_repositories)
254
255## Building crates with complicated dependencies
256
257Some crates have build.rs scripts which are complicated to run. Typically these build C++ (or other languages), or attempt to find pre-installed libraries on the build machine.
258
259There are a few approaches to making sure these run:
260
261### Some things work without intervention
262
263Some build scripts will happily run without any support needed.
264
265rules_rust already supplies a configured C++ toolchain as input to build script execution, and sets variables like `CC`, `CXX`, `LD`, `LDFLAGS`, etc as needed. Many crates which invoke a compiler with the default environment, or forward these env vars, will Just Work (e.g. if using [`cc-rs`][cc-rs]).
266
267rules_rust is open to PRs which make build scripts more likely to work by default with intervention assuming they're broadly applicable (e.g. setting extra widely-known env vars is probably fine, wiring up additional toolchains like `cmake` that aren't present by default for most Bazel users probably isn't).
268
269### Supplying extra tools to build
270
271Some build scripts can be made to work by pulling in some extra files and making them available to the build script.
272
273Commonly this is done by passing the file to the `build_script_data` annotation for the crate, and using `build_script_env` to tell the build script where the file is. That env var may often use `$(execroot)` to get the path to the label, or `$${pwd}/` as a prefix if the path given is relative to the execroot (as will frequently happen when using a toolchain).A
274
275There is an example of this in the "complicated dependencies" section of https://github.com/bazelbuild/rules_rust/blob/main/examples/crate_universe/WORKSPACE.bazel which builds libz-ng-sys.
276
277### Building with Bazel and supplying via an override
278
279Some build scripts have hooks to allow replacing parts that are complicated to build with output prepared by Bazel.
280
281We can use those hooks by specifying paths (generally using the `build_script_data` and `build_script_env` annotations) and pointing them at labels which Bazel will then build. These env vars may often use `$(execroot)` to get the path to the label, or `$${pwd}/` as a prefix if the path given is relative to the execroot (as will frequently happen when using a toolchain).
282
283There is an example of this in the "complicated dependencies" section of https://github.com/bazelbuild/rules_rust/blob/main/examples/crate_universe/WORKSPACE.bazel which builds boring-sys.
284
285---
286
287---
288
289[cw]: https://doc.rust-lang.org/book/ch14-03-cargo-workspaces.html
290[cc]: https://docs.bazel.build/versions/main/be/c-cpp.html
291[proto]: https://rules-proto-grpc.com/en/latest/lang/rust.html
292[ra]: https://rust-analyzer.github.io/
293[cc-rs]: https://github.com/rust-lang/cc-rs
294"""
295
296load(
297    "//crate_universe:defs.bzl",
298    _crate = "crate",
299    _crates_repository = "crates_repository",
300    _crates_vendor = "crates_vendor",
301    _render_config = "render_config",
302    _splicing_config = "splicing_config",
303)
304load(
305    "//crate_universe:repositories.bzl",
306    _crate_universe_dependencies = "crate_universe_dependencies",
307)
308load(
309    "//crate_universe/3rdparty/crates:defs.bzl",
310    _aliases = "aliases",
311    _all_crate_deps = "all_crate_deps",
312    _crate_deps = "crate_deps",
313    _crate_repositories = "crate_repositories",
314)
315
316# Rules
317crates_repository = _crates_repository
318crates_vendor = _crates_vendor
319
320# Utility Macros
321crate_universe_dependencies = _crate_universe_dependencies
322crate = _crate
323render_config = _render_config
324splicing_config = _splicing_config
325
326# Dependencies API
327aliases = _aliases
328all_crate_deps = _all_crate_deps
329crate_deps = _crate_deps
330crate_repositories = _crate_repositories
331