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