• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""# Crate Universe
2
3Crate Universe is a set of Bazel rule for generating Rust targets using Cargo.
4
5## Setup
6
7After loading `rules_rust` in your workspace, set the following to begin using `crate_universe`:
8
9```python
10load("@rules_rust//crate_universe:repositories.bzl", "crate_universe_dependencies")
11
12crate_universe_dependencies()
13```
14
15Note that if the current version of `rules_rust` is not a release artifact, you may need to set additional
16flags such as [`bootstrap = True`](#crate_universe_dependencies-bootstrap) on the `crate_universe_dependencies`
17call above or [crates_repository::generator_urls](#crates_repository-generator_urls) in uses of `crates_repository`.
18
19## Rules
20
21- [crates_repository](#crates_repository)
22- [crates_vendor](#crates_vendor)
23
24## Utility Macros
25
26- [crate_universe_dependencies](#crate_universe_dependencies)
27- [crate.annotation](#crateannotation)
28- [crate.select](#crateselect)
29- [crate.spec](#cratespec)
30- [crate.workspace_member](#crateworkspace_member)
31- [render_config](#render_config)
32- [splicing_config](#splicing_config)
33
34## Workflows
35
36The [`crates_repository`](#crates_repository) rule (the primary repository rule of `rules_rust`'s cargo support) supports a number of different
37ways users can express and organize their dependencies. The most common are listed below though there are more to be found in
38the [./examples/crate_universe](https://github.com/bazelbuild/rules_rust/tree/main/examples/crate_universe) directory.
39
40### Cargo Workspaces
41
42One of the simpler ways to wire up dependencies would be to first structure your project into a [Cargo workspace][cw].
43The `crates_repository` rule can ingest a root `Cargo.toml` file and generate dependencies from there.
44
45```python
46load("@rules_rust//crate_universe:defs.bzl", "crates_repository")
47
48crates_repository(
49    name = "crate_index",
50    cargo_lockfile = "//:Cargo.lock",
51    lockfile = "//:Cargo.Bazel.lock",
52    manifests = ["//:Cargo.toml"],
53)
54
55load("@crate_index//:defs.bzl", "crate_repositories")
56
57crate_repositories()
58```
59
60The generated `crates_repository` contains helper macros which make collecting dependencies for Bazel targets simpler.
61Notably, the `all_crate_deps` and `aliases` macros (see [Dependencies API](#dependencies-api)) commonly allow the
62`Cargo.toml` files to be the single source of truth for dependencies. Since these macros come from the generated
63repository, the dependencies and alias definitions they return will automatically update BUILD targets.
64
65```python
66load("@crate_index//:defs.bzl", "aliases", "all_crate_deps")
67load("@rules_rust//rust:defs.bzl", "rust_library", "rust_test")
68
69rust_library(
70    name = "lib",
71    aliases = aliases(),
72    deps = all_crate_deps(
73        normal = True,
74    ),
75    proc_macro_deps = all_crate_deps(
76        proc_macro = True,
77    ),
78)
79
80rust_test(
81    name = "unit_test",
82    crate = ":lib",
83    aliases = aliases(
84        normal_dev = True,
85        proc_macro_dev = True,
86    ),
87    deps = all_crate_deps(
88        normal_dev = True,
89    ),
90    proc_macro_deps = all_crate_deps(
91        proc_macro_dev = True,
92    ),
93)
94```
95
96### Direct Packages
97
98In cases where Rust targets have heavy interractions with other Bazel targests ([Cc][cc], [Proto][proto], etc.),
99maintaining `Cargo.toml` files may have deminishing returns as things like [rust-analyzer][ra] begin to be confused
100about missing targets or environment variables defined only in Bazel. In workspaces like this, it may be desirable
101to have a "Cargo free" setup. `crates_repository` supports this through the `packages` attribute.
102
103```python
104load("@rules_rust//crate_universe:defs.bzl", "crate", "crates_repository", "render_config")
105
106crates_repository(
107    name = "crate_index",
108    cargo_lockfile = "//:Cargo.lock",
109    lockfile = "//:Cargo.Bazel.lock",
110    packages = {
111        "async-trait": crate.spec(
112            version = "0.1.51",
113        ),
114        "mockall": crate.spec(
115            version = "0.10.2",
116        ),
117        "tokio": crate.spec(
118            version = "1.12.0",
119        ),
120    },
121    # Setting the default package name to `""` forces the use of the macros defined in this repository
122    # to always use the root package when looking for dependencies or aliases. This should be considered
123    # optional as the repository also exposes alises for easy access to all dependencies.
124    render_config = render_config(
125        default_package_name = ""
126    ),
127)
128
129load("@crate_index//:defs.bzl", "crate_repositories")
130
131crate_repositories()
132```
133
134Consuming dependencies may be more ergonomic in this case through the aliases defined in the new repository.
135
136```python
137load("@rules_rust//rust:defs.bzl", "rust_library", "rust_test")
138
139rust_library(
140    name = "lib",
141    deps = [
142        "@crate_index//:tokio",
143    ],
144    proc_macro_deps = [
145        "@crate_index//:async-trait",
146    ],
147)
148
149rust_test(
150    name = "unit_test",
151    crate = ":lib",
152    deps = [
153        "@crate_index//:mockall",
154    ],
155)
156```
157
158### Binary dependencies
159
160Neither of the above approaches supports depending on binary-only packages.
161
162In order to depend on a Cargo package that contains binaries and no library, you
163will need to do one of the following:
164
165- Fork the package to add an empty lib.rs, which makes the package visible to
166  Cargo metadata and compatible with the above approaches;
167
168- Or handwrite your own build target for the binary, use `http_archive` to
169  import its source code, and use `crates_repository` to make build targets for
170  its dependencies. This is demonstrated below using the `rustfilt` crate as an
171  example.
172
173```python
174# in WORKSPACE.bazel
175
176load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
177
178http_archive(
179    name = "rustfilt",
180    build_file = "//rustfilt:BUILD.rustfilt.bazel",
181    sha256 = "c8d748b182c8f95224336d20dcc5609598af612581ce60cfb29da4dc8d0091f2",
182    strip_prefix = "rustfilt-0.2.1",
183    type = "tar.gz",
184    urls = ["https://crates.io/api/v1/crates/rustfilt/0.2.1/download"],
185)
186
187load("@rules_rust//crate_universe:defs.bzl", "crates_repository")
188
189crates_repository(
190    name = "rustfilt_deps",
191    cargo_lockfile = "//rustfilt:Cargo.lock",
192    manifests = ["@rustfilt//:Cargo.toml"],
193)
194
195load("@rustfilt_deps//:defs.bzl", rustfilt_deps = "crate_repositories")
196
197rustfilt_deps()
198```
199
200```python
201# in rustfilt/BUILD.rustfilt.bazel
202
203load("@rules_rust//rust:defs.bzl", "rust_binary")
204
205rust_binary(
206    name = "rustfilt",
207    srcs = glob(["src/**/*.rs"]),
208    edition = "2018",
209    deps = [
210        "@rustfilt_deps//:clap",
211        "@rustfilt_deps//:lazy_static",
212        "@rustfilt_deps//:regex",
213        "@rustfilt_deps//:rustc-demangle",
214    ],
215)
216```
217
218If you use either `crates_repository` or `crates_vendor` to depend on a Cargo
219package that contains _both_ a library crate _and_ binaries, by default only the
220library gets made available to Bazel. To generate Bazel targets for the binary
221crates as well, you must opt in to it with an annotation on the package:
222
223```python
224load("@rules_rust//crate_universe:defs.bzl", "crates_repository", "crate")
225
226crates_repository(
227    name = "crate_index",
228    annotations = {
229        "thepackage": [crate.annotation(
230            gen_binaries = True,
231            # Or, to expose just a subset of the package's binaries by name:
232            gen_binaries = ["rustfilt"],
233        )],
234    },
235    # Or, to expose every binary of every package:
236    generate_binaries = True,
237    ...
238)
239```
240
241## Dependencies API
242
243After rendering dependencies, convenience macros may also be generated to provide
244convenient accessors to larger sections of the dependency graph.
245
246- [aliases](#aliases)
247- [crate_deps](#crate_deps)
248- [all_crate_deps](#all_crate_deps)
249- [crate_repositories](#crate_repositories)
250
251---
252
253---
254
255[cw]: https://doc.rust-lang.org/book/ch14-03-cargo-workspaces.html
256[cc]: https://docs.bazel.build/versions/main/be/c-cpp.html
257[proto]: https://rules-proto-grpc.com/en/latest/lang/rust.html
258[ra]: https://rust-analyzer.github.io/
259"""
260
261load(
262    "//crate_universe:defs.bzl",
263    _crate = "crate",
264    _crates_repository = "crates_repository",
265    _crates_vendor = "crates_vendor",
266    _render_config = "render_config",
267    _splicing_config = "splicing_config",
268)
269load(
270    "//crate_universe:repositories.bzl",
271    _crate_universe_dependencies = "crate_universe_dependencies",
272)
273load(
274    "//crate_universe/3rdparty/crates:defs.bzl",
275    _aliases = "aliases",
276    _all_crate_deps = "all_crate_deps",
277    _crate_deps = "crate_deps",
278    _crate_repositories = "crate_repositories",
279)
280
281# Rules
282crates_repository = _crates_repository
283crates_vendor = _crates_vendor
284
285# Utility Macros
286crate_universe_dependencies = _crate_universe_dependencies
287crate = _crate
288render_config = _render_config
289splicing_config = _splicing_config
290
291# Dependencies API
292aliases = _aliases
293all_crate_deps = _all_crate_deps
294crate_deps = _crate_deps
295crate_repositories = _crate_repositories
296