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