README.md
1# Vendored Rust Dependencies
2
3This example shows how to vendor Rust dependencies and use those vendored dependencies in a binary target.
4You can run the example vendoring target:
5
6`bazel run //basic/3rdparty:crates_vendor`
7
8And the build target:
9
10`bazel build //...`
11
12## Setup
13
14For the setup,
15you need to add the skylib in addition to the rust rules to your MODUE.bazel.
16
17```starlark
18module(
19 name = "deps_vendored",
20 version = "0.0.0"
21)
22###############################################################################
23# B A Z E L C E N T R A L R E G I S T R Y # https://registry.bazel.build/
24###############################################################################
25# https://github.com/bazelbuild/bazel-skylib/releases/
26bazel_dep(name = "bazel_skylib", version = "1.7.1")
27
28# https://github.com/bazelbuild/rules_rust/releases
29bazel_dep(name = "rules_rust", version = "0.46.0")
30
31###############################################################################
32# T O O L C H A I N S
33###############################################################################
34
35# Rust toolchain
36RUST_EDITION = "2021"
37RUST_VERSION = "1.79.0"
38
39rust = use_extension("@rules_rust//rust:extensions.bzl", "rust")
40rust.toolchain(
41 edition = RUST_EDITION,
42 versions = [RUST_VERSION],
43)
44use_repo(rust, "rust_toolchains")
45register_toolchains("@rust_toolchains//:all")
46
47###############################################################################
48# R U S T C R A T E S
49###############################################################################
50crate = use_extension("@rules_rust//crate_universe:extension.bzl", "crate")
51```
52
53Note, it is important to load the crate_universe rules otherwise you will get an error
54as the rule set is needed in the vendored target.
55
56Assuming you have a package called `basic` in which you want to vendor dependencies,
57then you create a folder `basic/3rdparty`. The folder name can be arbitrary,
58but by convention, its either thirdparty or 3rdparty to indicate vendored dependencies.
59In the 3rdparty folder, you add a target crates_vendor to declare your dependencies to vendor. In the example, we vendor a specific version of bzip2.
60
61```starlark
62load("@rules_rust//crate_universe:defs.bzl", "crate", "crates_vendor")
63
64crates_vendor(
65 name = "crates_vendor",
66 annotations = {
67 "bzip2-sys": [crate.annotation(
68 gen_build_script = True,
69 )],
70 },
71 cargo_lockfile = "Cargo.Bazel.lock",
72 generate_build_scripts = False,
73 mode = "remote",
74 packages = {
75 "bzip2": crate.spec(
76 version = "=0.3.3",
77 ),
78 },
79 repository_name = "basic",
80 tags = ["manual"],
81)
82```
83
84Next, you have to run `Cargo build` to generate a Cargo.lock file with all resolved dependencies.
85Then, you rename Cargo.lock to Cargo.Bazel.lock and place it inside the `basic/3rdparty` folder.
86
87At this point, you have the following folder and files:
88
89```
90basic
91 ├── 3rdparty
92 │ ├── BUILD.bazel
93 │ ├── Cargo.Bazel.lock
94```
95
96Now you can run the `crates_vendor` target:
97
98`bazel run //basic/3rdparty:crates_vendor`
99
100This generates a crate folders with all configurations for the vendored dependencies.
101
102```
103basic
104 ├── 3rdparty
105 │ ├── cratea
106 │ ├── BUILD.bazel
107 │ ├── Cargo.Bazel.lock
108```
109
110## Usage
111
112Suppose you have an application in `basic/src` that is defined in `basic/BUILD.bazel` and
113that depends on a vendored dependency. You find a list of all available vendored dependencies
114in the BUILD file of the generated folder: `basic/3rdparty/crates/BUILD.bazel`
115You declare a vendored dependency in you target as following:
116
117```starlark
118load("@rules_rust//rust:defs.bzl", "rust_binary")
119
120rust_binary(
121 name = "hello_sys",
122 srcs = ["src/main.rs"],
123 # Note the `crate_unvierse` dependencies here need to have been loaded
124 # in the WORKSPACE file. See `//:sys_deps.bzl` for more details.
125 deps = ["//basic/3rdparty/crates:bzip2"],
126 visibility = ["//visibility:public"],
127)
128```
129Note, the vendored dependency is not yet accessible.
130
131Before you can build, you have to define how to load the vendored dependencies. For that,
132you first create a file `sys_deps.bzl` and add the following content:
133
134```starlark
135# rename the default name "crate_repositories" in case you import multiple vendored folders.
136load("//basic/3rdparty/crates:defs.bzl", basic_crate_repositories = "crate_repositories")
137
138def sys_deps():
139 """
140 This macro loads dependencies for the `basic` crate examples
141
142 Commonly `*-sys` crates are built on top of some existing library and
143 will have a number of dependencies. The examples here use
144 [crate_universe](https://bazelbuild.github.io/rules_rust/crate_universe.html)
145 to gather these dependencies and make them available in the workspace.
146 """
147
148 # Load the vendored dependencies
149 basic_crate_repositories()
150```
151
152This is straightforward, you import the generated crate_repositories from the crates folder,
153rename it to avoid name clashes in case you import from multiple vendored folders, and then
154just load the vendored dependencies.
155
156In a WORKSPACE configuration, you would just load and call sys_deps(), but in a MODULE configuration, you cannot do that. Instead, you create a new file `WORKSPACE.bzlmod` and add the following content.
157
158```starlark
159load("//:sys_deps.bzl", "sys_deps")
160sys_deps()
161```
162
163Now, you can build the project as usual:
164
165`bazel build //...`
166
167If you ever see an error referring to some cyclical dependencies in a WORKSPACE, it
168is caused because you did not load the bazel_skylib at the top of the MODULE.bazel file.
169To fix this error, make sure to have the following entry in your MODULE.bazel file:
170
171```starlark
172# ...
173# https://github.com/bazelbuild/bazel-skylib/releases/
174bazel_dep(name = "bazel_skylib", version = "1.7.1")
175# ....
176```
177
178Your build will complete once skylib loads.