]> git.proxmox.com Git - rustc.git/blame - src/doc/book/second-edition/nostarch/chapter14.md
New upstream version 1.22.1+dfsg1
[rustc.git] / src / doc / book / second-edition / nostarch / chapter14.md
CommitLineData
cc61c64b
XL
1
2[TOC]
3
4# More about Cargo and Crates.io
5
3b2f2976
XL
6So far we’ve used only the most basic features of Cargo to build, run, and test
7our code, but it can do a lot more. Here we’ll go over some of its other, more
8advanced features to show you how to:
cc61c64b 9
3b2f2976
XL
10* Customize your build through release profiles
11* Publish libraries on crates.io
12* Organize larger projects with workspaces
13* Install binaries from crates.io
14* Extend Cargo with your own custom commands
cc61c64b 15
3b2f2976 16Cargo can do even more than what we can cover in this chapter too, so for a
ea8adc8c 17full explanation, see its documentation at *https://doc.rust-lang.org/cargo/*.
cc61c64b 18
3b2f2976 19## Customizing Builds with Release Profiles
cc61c64b 20
3b2f2976
XL
21In Rust *release profiles* are pre-defined, and customizable, profiles with
22different configurations, to allow the programmer more control over various
23options for compiling your code. Each profile is configured independently of
24the others.
25
ea8adc8c
XL
26Cargo has two main profiles you should know about: the `dev` profile Cargo uses
27when you run `cargo build`, and the `release` profile Cargo uses when you run
28`cargo build --release`. The `dev` profile is defined with good defaults for
29developing, and likewise the `release` profile has good defaults for release
30builds.
3b2f2976 31
ea8adc8c
XL
32These names may be familiar from the output of your builds, which shows the
33profile used in the build:
3b2f2976
XL
34
35```
cc61c64b 36$ cargo build
3b2f2976 37 Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
cc61c64b
XL
38$ cargo build --release
39 Finished release [optimized] target(s) in 0.0 secs
40```
41
ea8adc8c
XL
42The “dev” and “release” notifications here indicate that the compiler is using
43different profiles.
cc61c64b 44
3b2f2976 45### Customizing Release Profiles
cc61c64b 46
3b2f2976
XL
47Cargo has default settings for each of the profiles that apply when there
48aren’t any `[profile.*]` sections in the project’s *Cargo.toml* file. By adding
49`[profile.*]` sections for any profile we want to customize, we can choose to
50override any subset of the default settings. For example, here are the default
51values for the `opt-level` setting for the `dev` and `release` profiles:
52
ea8adc8c
XL
53Filename: Cargo.toml
54
3b2f2976 55```
cc61c64b
XL
56[profile.dev]
57opt-level = 0
58
59[profile.release]
60opt-level = 3
61```
62
63The `opt-level` setting controls how many optimizations Rust will apply to your
3b2f2976
XL
64code, with a range of zero to three. Applying more optimizations makes
65compilation take longer, so if you’re in development and compiling very often,
66you’d want compiling to be fast at the expense of the resulting code running
67slower. That’s why the default `opt-level` for `dev` is `0`. When you’re ready
68to release, it’s better to spend more time compiling. You’ll only be compiling
69in release mode once, and running the compiled program many times, so release
70mode trades longer compile time for code that runs faster. That’s why the
71default `opt-level` for the `release` profile is `3`.
72
73We can choose to override any default setting by adding a different value for
74them in *Cargo.toml*. If we wanted to use optimization level 1 in the
75development profile, for example, we can add these two lines to our project’s
76*Cargo.toml*:
77
3b2f2976 78Filename: Cargo.toml
cc61c64b 79
3b2f2976 80```
cc61c64b
XL
81[profile.dev]
82opt-level = 1
83```
84
3b2f2976
XL
85This overrides the default setting of `0`. Now when we run `cargo build`, Cargo
86will use the defaults for the `dev` profile plus our customization to
87`opt-level`. Because we set `opt-level` to `1`, Cargo will apply more
88optimizations than the default, but not as many as a release build.
cc61c64b 89
3b2f2976 90For the full list of configuration options and defaults for each profile, see
ea8adc8c 91Cargo’s documentation at *https://doc.rust-lang.org/cargo/*.
cc61c64b
XL
92
93## Publishing a Crate to Crates.io
94
3b2f2976
XL
95We’ve used packages from crates.io as dependencies of our project, but you can
96also share your code for other people to use by publishing your own packages.
97Crates.io distributes the source code of your packages, so it primarily hosts
98code that’s open source.
cc61c64b 99
3b2f2976
XL
100Rust and Cargo have features that help make your published package easier for
101people to find and use. We’ll talk about some of those features, then cover how
102to publish a package.
cc61c64b 103
3b2f2976 104### Making Useful Documentation Comments
cc61c64b 105
3b2f2976
XL
106Accurately documenting your packages will help other users know how and when to
107use them, so it’s worth spending some time to write documentation. In Chapter
1083, we discussed how to comment Rust code with `//`. Rust also has particular
109kind of comment for documentation, known conveniently as *documentation
110comments*, that will generate HTML documentation. The HTML displays the
111contents of documentation comments for public API items, intended for
112programmers interested in knowing how to *use* your crate, as opposed to how
113your crate is *implemented*.
cc61c64b 114
3b2f2976
XL
115Documentation comments use `///` instead of `//` and support Markdown notation
116for formatting the text if you’d like. You place documentation comments just
ea8adc8c 117before the item they are documenting. Listing 14-1 shows documentation comments
3b2f2976 118for an `add_one` function in a crate named `my_crate`:
cc61c64b 119
3b2f2976 120Filename: src/lib.rs
cc61c64b 121
3b2f2976 122```
cc61c64b
XL
123/// Adds one to the number given.
124///
125/// # Examples
126///
127/// ```
128/// let five = 5;
129///
3b2f2976 130/// assert_eq!(6, my_crate::add_one(5));
cc61c64b
XL
131/// ```
132pub fn add_one(x: i32) -> i32 {
133 x + 1
134}
3b2f2976
XL
135```
136
ea8adc8c 137Listing 14-1: A documentation comment for a function
cc61c64b 138
3b2f2976
XL
139Here, we give a description of what the `add_one` function does, then start a
140section with the heading “Examples”, and code that demonstrates how to use the
141`add_one` function. We can generate the HTML documentation from this
142documentation comment by running `cargo doc`. This command runs the `rustdoc`
143tool distributed with Rust and puts the generated HTML documentation in the
144*target/doc* directory.
cc61c64b 145
3b2f2976
XL
146For convenience, running `cargo doc --open` will build the HTML for your
147current crate’s documentation (as well as the documentation for all of your
148crate’s dependencies) and open the result in a web browser. Navigate to the
149`add_one` function and you’ll see how the text in the documentation comments
ea8adc8c 150gets rendered, shown here in Figure 14-2:
cc61c64b 151
3b2f2976
XL
152<img alt="Rendered HTML documentation for the `add_one` function of `my_crate`" src="img/trpl14-03.png" class="center" />
153
ea8adc8c 154Figure 14-2: HTML documentation for the `add_one` function
3b2f2976
XL
155
156#### Commonly Used Sections
157
ea8adc8c 158We used the `# Examples` markdown heading in Listing 14-1 to create a section
3b2f2976
XL
159in the HTML with the title “Examples”. Some other sections that crate authors
160commonly use in their documentation include:
161
ea8adc8c
XL
162* **Panics**: The scenarios in which this function could `panic!`. Callers of
163 this function who don’t want their programs to panic should make sure that
164 they don’t call this function in these situations.
165* **Errors**: If this function returns a `Result`, describing the kinds of
166 errors that might occur and what conditions might cause those errors to be
167 returned can be helpful to callers so that they can write code to handle the
168 different kinds of errors in different ways.
169* **Safety**: If this function is `unsafe` to call (we will discuss unsafety in
170 Chapter 19), there should be a section explaining why the function is unsafe
171 and covering the invariants that this function expects callers to uphold.
3b2f2976
XL
172
173Most documentation comment sections don’t need all of these sections, but this
174is a good list to check to remind you of the kinds of things that people
175calling your code will be interested in knowing about.
176
177#### Documentation Comments as Tests
cc61c64b
XL
178
179Adding examples in code blocks in your documentation comments is a way to
3b2f2976
XL
180clearly demonstrate how to use your library, but it has an additional bonus:
181running `cargo test` will run the code examples in your documentation as tests!
182Nothing is better than documentation with examples. Nothing is worse than
183examples that don’t actually work because the code has changed since the
cc61c64b 184documentation has been written. Try running `cargo test` with the documentation
ea8adc8c 185for the `add_one` function like in Listing 14-1; you should see a section in
3b2f2976 186the test results like this:
cc61c64b 187
3b2f2976
XL
188```
189 Doc-tests my_crate
cc61c64b
XL
190
191running 1 test
3b2f2976 192test src/lib.rs - add_one (line 5) ... ok
cc61c64b
XL
193
194test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
195```
196
3b2f2976
XL
197Now try changing either the function or the example so that the `assert_eq!` in
198the example will panic. Run `cargo test` again, and you’ll see that the doc
199tests catch that the example and the code are out of sync from one another!
cc61c64b 200
3b2f2976
XL
201#### Commenting Contained Items
202
3b2f2976
XL
203There’s another style of doc comment, `//!`, that adds documentation to the
204item that contains the comments, rather than adding documentation to the items
205following the comments. These are typically used inside the crate root file
ea8adc8c
XL
206(*src/lib.rs* by convention) or inside a module to document the crate or the
207module as a whole.
3b2f2976
XL
208
209For example, if we wanted to add documentation that described the purpose of
210the `my_crate` crate that contains the `add_one` function, we can add
211documentation comments that start with `//!` to the beginning of *src/lib.rs*
ea8adc8c 212as shown in Listing 14-3:
3b2f2976
XL
213
214Filename: src/lib.rs
cc61c64b
XL
215
216```
3b2f2976 217//! # My Crate
cc61c64b 218//!
3b2f2976
XL
219//! `my_crate` is a collection of utilities to make performing certain
220//! calculations more convenient.
221
222/// Adds one to the number given.
223// ...snip...
cc61c64b
XL
224```
225
ea8adc8c 226Listing 14-3: Documentation for the `my_crate` crate as a whole
3b2f2976
XL
227
228Notice there isn’t any code after the last line that begins with `//!`. Because
229we started the comments with `//!` instead of `///`, we’re documenting the item
230that contains this comment rather than an item that follows this comment. In
231this case, the item that contains this comment is the *src/lib.rs* file, which
232is the crate root. These comments describe the entire crate.
233
234If we run `cargo doc --open`, we’ll see these comments displayed on the front
235page of the documentation for `my_crate` above the list of public items in the
ea8adc8c 236crate, as shown in Figure 14-4:
3b2f2976
XL
237
238<img alt="Rendered HTML documentation with a comment for the crate as a whole" src="img/trpl14-05.png" class="center" />
239
ea8adc8c 240Figure 14-4: Rendered documentation for `my_crate` including the comment
3b2f2976
XL
241describing the crate as a whole
242
3b2f2976
XL
243Documentation comments within items are useful for describing crates and
244modules especially. Use them to talk about the purpose of the container overall
245to help users of your crate understand your organization.
246
ea8adc8c 247#### Exporting a Convenient Public API with `pub use`
cc61c64b
XL
248
249In Chapter 7, we covered how to organize our code into modules with the `mod`
250keyword, how to make items public with the `pub` keyword, and how to bring
3b2f2976
XL
251items into a scope with the `use` keyword. The structure that makes sense to
252you while you’re developing a crate may not be very convenient for your users,
253however. You may wish to organize your structs in a hierarchy containing
254multiple levels, but people that want to use a type you’ve defined deep in the
255hierarchy might have trouble finding out that those types exist. They might
256also be annoyed at having to type `use
257my_crate::some_module::another_module::UsefulType;` rather than `use
258my_crate::UsefulType;`.
259
3b2f2976
XL
260The structure of your public API is a major consideration when publishing a
261crate. People who use your crate are less familiar with the structure than you
262are, and might have trouble finding the pieces they want to use if the module
263hierarchy is large.
264
265The good news is that, if the structure *isn’t* convenient for others to use
266from another library, you don’t have to rearrange your internal organization:
267you can choose to re-export items to make a public structure that’s different
268to your private structure, using `pub use`. Re-exporting takes a public item in
269one location and makes it public in another location as if it was defined in
270the other location instead.
271
3b2f2976
XL
272For example, say we made a library named `art` for modeling artistic concepts.
273Within this library is a `kinds` module containing two enums named
274`PrimaryColor` and `SecondaryColor` and a `utils` module containing a function
ea8adc8c 275named `mix` as shown in Listing 14-5:
3b2f2976
XL
276
277Filename: src/lib.rs
278
279```
cc61c64b
XL
280//! # Art
281//!
282//! A library for modeling artistic concepts.
283
284pub mod kinds {
285 /// The primary colors according to the RYB color model.
286 pub enum PrimaryColor {
287 Red,
288 Yellow,
289 Blue,
290 }
291
292 /// The secondary colors according to the RYB color model.
293 pub enum SecondaryColor {
294 Orange,
295 Green,
296 Purple,
297 }
298}
299
300pub mod utils {
301 use kinds::*;
302
303 /// Combines two primary colors in equal amounts to create
304 /// a secondary color.
305 pub fn mix(c1: PrimaryColor, c2: PrimaryColor) -> SecondaryColor {
306 // ...snip...
307 }
308}
309```
310
ea8adc8c 311Listing 14-5: An `art` library with items organized into `kinds` and `utils`
cc61c64b
XL
312modules
313
3b2f2976 314The front page of the documentation for this crate generated by `cargo doc`
ea8adc8c 315would look like Figure 14-6:
3b2f2976
XL
316
317<img alt="Rendered documentation for the `art` crate that lists the `kinds` and `utils` modules" src="img/trpl14-07.png" class="center" />
318
ea8adc8c
XL
319Figure 14-6: Front page of the documentation for `art` that lists the `kinds`
320and `utils` modules
cc61c64b 321
3b2f2976
XL
322Note that the `PrimaryColor` and `SecondaryColor` types aren’t listed on the
323front page, nor is the `mix` function. We have to click on `kinds` and `utils`
324in order to see them.
cc61c64b 325
3b2f2976
XL
326Another crate depending on this library would need `use` statements that import
327the items from `art` including specifying the module structure that’s currently
ea8adc8c 328defined. Listing 14-7 shows an example of a crate that uses the `PrimaryColor`
3b2f2976 329and `mix` items from the `art` crate:
cc61c64b 330
3b2f2976
XL
331Filename: src/main.rs
332
333```
cc61c64b
XL
334extern crate art;
335
336use art::kinds::PrimaryColor;
337use art::utils::mix;
338
339fn main() {
340 let red = PrimaryColor::Red;
341 let yellow = PrimaryColor::Yellow;
342 mix(red, yellow);
343}
344```
345
ea8adc8c 346Listing 14-7: A crate using the `art` crate’s items with its internal structure
3b2f2976 347exported
cc61c64b 348
ea8adc8c 349The author of the code in Listing 14-7 that uses the `art` crate had to figure
3b2f2976
XL
350out that `PrimaryColor` is in the `kinds` module and `mix` is in the `utils`
351module. The module structure of the `art` crate is more relevant to developers
352working on the `art` crate than developers using the `art` crate. The internal
353structure that organizes parts of the crate into the `kinds` module and the
354`utils` module doesn’t add any useful information to someone trying to
355understand how to use the `art` crate. The `art` crate’s module structure adds
356confusion in having to figure out where to look and inconvenience in having to
357specify the module names in the `use` statements.
cc61c64b 358
3b2f2976 359To remove the internal organization from the public API, we can take the `art`
ea8adc8c
XL
360crate code from Listing 14-5 and add `pub use` statements to re-export the
361items at the top level, as shown in Listing 14-8:
cc61c64b 362
3b2f2976 363Filename: src/lib.rs
cc61c64b 364
3b2f2976 365```
cc61c64b
XL
366//! # Art
367//!
368//! A library for modeling artistic concepts.
369
370pub use kinds::PrimaryColor;
371pub use kinds::SecondaryColor;
372pub use utils::mix;
373
374pub mod kinds {
375 // ...snip...
3b2f2976
XL
376}
377
378pub mod utils {
379 // ...snip...
380}
cc61c64b
XL
381```
382
ea8adc8c 383Listing 14-8: Adding `pub use` statements to re-export items
cc61c64b 384
3b2f2976 385The API documentation generated with `cargo doc` for this crate will now list
ea8adc8c 386and link re-exports on the front page as shown in Figure 14-9, which makes
3b2f2976 387these types easier to find.
cc61c64b 388
3b2f2976
XL
389<img alt="Rendered documentation for the `art` crate with the re-exports on the front page" src="img/trpl14-10.png" class="center" />
390
ea8adc8c 391Figure 14-9: Front page of the documentation for `art` that lists the
3b2f2976 392re-exports
cc61c64b 393
3b2f2976 394Users of the `art` crate can still see and choose to use the internal structure
ea8adc8c
XL
395as in Listing 14-7, or they can use the more convenient structure from Listing
39614-8, as shown in Listing 14-10:
cc61c64b 397
3b2f2976 398Filename: src/main.rs
cc61c64b 399
3b2f2976 400```
cc61c64b
XL
401extern crate art;
402
403use art::PrimaryColor;
404use art::mix;
405
406fn main() {
407 // ...snip...
408}
409```
410
ea8adc8c 411Listing 14-10: A program using the re-exported items from the `art` crate
cc61c64b 412
3b2f2976
XL
413In cases where there are many nested modules, re-exporting the types at the top
414level with `pub use` can make a big difference in the experience of people who
415use the crate.
416
417Creating a useful public API structure is more of an art than a science, and
418you can iterate to find the API that works best for your users. Choosing `pub
419use` gives you flexibility in how you structure your crate internally, and
420decouples that internal structure with what you present to your users. Take a
421look at some of the code of crates you’ve installed to see if their internal
422structure differs from their public API.
423
424### Setting up a Crates.io Account
425
426Before you can publish any crates, you need to create an account on crates.io
427and get an API token. To do so, visit the home page at *https://crates.io* and
ea8adc8c 428log in via a GitHub account—the GitHub account is a requirement for now, but
3b2f2976
XL
429the site may support other ways of creating an account in the future. Once
430you’re logged in, visit your account settings at *https://crates.io/me* and
431retrieve your API key. Then run the `cargo login` command with your API key,
432like this:
cc61c64b 433
3b2f2976 434```
cc61c64b
XL
435$ cargo login abcdefghijklmnopqrstuvwxyz012345
436```
437
438This command will inform Cargo of your API token and store it locally in
ea8adc8c 439*~/.cargo/credentials*. Note that this token is a *secret* and should not be
3b2f2976
XL
440shared with anyone else. If it is shared with anyone for any reason, you should
441revoke it and generate a new token on Crates.io.
cc61c64b
XL
442
443### Before Publishing a New Crate
444
3b2f2976
XL
445Now you have an account, and let’s say you already have a crate you want to
446publish. Before publishing, you’ll need to add some metadata to your crate by
447adding it to the `[package]` section of the crate’s *Cargo.toml*.
448
3b2f2976
XL
449Your crate will first need a unique name. While you’re working on a crate
450locally, you may name a crate whatever you’d like. However, crate names on
451Crates.io are allocated on a first-come-first-serve basis. Once a crate name is
452taken, no one else may publish a crate with that name. Search for the name
453you’d like to use on the site to find out if it has been taken. If it hasn’t,
454edit the name in *Cargo.toml* under `[package]` to have the name you want to
455use for publishing like so:
456
ea8adc8c
XL
457Filename: Cargo.toml
458
3b2f2976
XL
459```
460[package]
461name = "guessing_game"
462```
cc61c64b 463
3b2f2976
XL
464Even if you’ve chosen a unique name, if you try to run `cargo publish` to
465publish the crate at this point, you’ll get a warning and then an error:
cc61c64b 466
3b2f2976 467```
cc61c64b
XL
468$ cargo publish
469 Updating registry `https://github.com/rust-lang/crates.io-index`
470warning: manifest has no description, license, license-file, documentation,
471homepage or repository.
472...snip...
473error: api errors: missing or empty metadata fields: description, license.
cc61c64b
XL
474```
475
3b2f2976
XL
476This is because we’re missing some crucial information: a description and
477license are required so that people will know what your crate does and under
478what terms they may use it. To rectify this error, we need to include this
479information in *Cargo.toml*.
cc61c64b 480
3b2f2976
XL
481Make a description that’s just a sentence or two, as it will appear with your
482crate in search results and on your crate’s page. For the `license` field, you
483need to give a *license identifier value*. The Linux Foundation’s Software
484Package Data Exchange (SPDX) at *http://spdx.org/licenses/* lists the
485identifiers you can use for this value. For example, to specify that you’ve
486licensed your crate using the MIT License, add the `MIT` identifier:
487
ea8adc8c
XL
488Filename: Cargo.toml
489
3b2f2976
XL
490```
491[package]
492name = "guessing_game"
493license = "MIT"
494```
495
3b2f2976
XL
496If you want to use a license that doesn’t appear in the SPDX, you need to place
497the text of that license in a file, include the file in your project, then use
498`license-file` to specify the name of that file instead of using the `license`
499key.
cc61c64b
XL
500
501Guidance on which license is right for your project is out of scope for this
502book. Many people in the Rust community choose to license their projects in the
ea8adc8c 503same way as Rust itself, with a dual license of `MIT/Apache-2.0`—this
3b2f2976
XL
504demonstrates that you can also specify multiple license identifiers separated
505by a slash.
cc61c64b 506
3b2f2976
XL
507So, with a unique name, the version, and author details that `cargo new` added
508when you created the crate, your description, and the license you chose added,
509the *Cargo.toml* for a project that’s ready to publish might look like this:
cc61c64b 510
ea8adc8c
XL
511Filename: Cargo.toml
512
3b2f2976 513```
cc61c64b
XL
514[package]
515name = "guessing_game"
516version = "0.1.0"
517authors = ["Your Name <you@example.com>"]
518description = "A fun game where you guess what number the computer has chosen."
519license = "MIT/Apache-2.0"
520
521[dependencies]
522```
523
ea8adc8c 524Cargo’s documentation at *https://doc.rust-lang.org/cargo/* describes other
3b2f2976
XL
525metadata you can specify to ensure your crate can be discovered and used more
526easily!
cc61c64b
XL
527
528### Publishing to Crates.io
529
3b2f2976
XL
530Now that you’ve created an account, saved your API token, chosen a name for
531your crate, and specified the required metadata, you’re ready to publish!
532Publishing a crate uploads a specific version to crates.io for others to use.
cc61c64b 533
3b2f2976
XL
534Take care when publishing a crate, because a publish is *permanent*. The
535version can never be overwritten, and the code cannot be deleted. One major
536goal of Crates.io is to act as a permanent archive of code so that builds of
537all projects that depend on crates from Crates.io will continue to work.
538Allowing deletion of versions would make fulfilling that goal impossible.
539However, there is no limit to the number of versions of a crate you can publish.
cc61c64b 540
3b2f2976 541Let’s run the `cargo publish` command again. It should succeed now:
cc61c64b 542
3b2f2976 543```
cc61c64b
XL
544$ cargo publish
545 Updating registry `https://github.com/rust-lang/crates.io-index`
546Packaging guessing_game v0.1.0 (file:///projects/guessing_game)
547Verifying guessing_game v0.1.0 (file:///projects/guessing_game)
548Compiling guessing_game v0.1.0
549(file:///projects/guessing_game/target/package/guessing_game-0.1.0)
3b2f2976 550 Finished dev [unoptimized + debuginfo] target(s) in 0.19 secs
cc61c64b
XL
551Uploading guessing_game v0.1.0 (file:///projects/guessing_game)
552```
553
3b2f2976
XL
554Congratulations! You’ve now shared your code with the Rust community, and
555anyone can easily add your crate as a dependency of their project.
cc61c64b
XL
556
557### Publishing a New Version of an Existing Crate
558
3b2f2976
XL
559When you’ve made changes to your crate and are ready to release a new version,
560you change the `version` value specified in your *Cargo.toml* and republish.
ea8adc8c
XL
561Use the Semantic Versioning rules at *http://semver.org/* to decide what an
562appropriate next version number is based on the kinds of changes you’ve made.
563Then run `cargo publish` to upload the new version.
cc61c64b
XL
564
565### Removing Versions from Crates.io with `cargo yank`
566
3b2f2976
XL
567While you can’t remove previous versions of a crate, you can prevent any future
568projects from adding them as a new dependency. This is useful when a version of
569a crate ends up being broken for one reason or another. For situations such as
570this, Cargo supports *yanking* a version of a crate.
571
ea8adc8c
XL
572Yanking a version prevents new projects from starting to depend on that version
573while allowing all existing projects that depend on it to continue to download
574and depend on that version. Essentially, a yank means that all projects with a
575*Cargo.lock* will not break, while any future *Cargo.lock* files generated will
576not use the yanked version.
cc61c64b
XL
577
578To yank a version of a crate, run `cargo yank` and specify which version you
579want to yank:
580
3b2f2976 581```
cc61c64b
XL
582$ cargo yank --vers 1.0.1
583```
584
585You can also undo a yank, and allow projects to start depending on a version
586again, by adding `--undo` to the command:
587
3b2f2976 588```
cc61c64b
XL
589$ cargo yank --vers 1.0.1 --undo
590```
591
3b2f2976
XL
592A yank *does not* delete any code. The yank feature is not intended for
593deleting accidentally uploaded secrets, for example. If that happens, you must
594reset those secrets immediately.
595
cc61c64b
XL
596## Cargo Workspaces
597
598In Chapter 12, we built a package that included both a binary crate and a
3b2f2976
XL
599library crate. You may find, as your project develops, that the library crate
600continues to get bigger and you want to split your package up further into
601multiple library crates. In this situation, Cargo has a feature called
602*workspaces* that can help manage multiple related packages that are developed
603in tandem.
cc61c64b
XL
604
605A *workspace* is a set of packages that will all share the same *Cargo.lock*
3b2f2976
XL
606and output directory. Let’s make a project using a workspace, using trivial
607code so we can concentrate on the structure of a workspace. We’ll have a binary
608that uses two libraries: one library that will provide an `add_one` function
609and a second library that will provide an `add_two` function. These three
610crates will all be part of the same workspace. We’ll start by creating a new
611crate for the binary:
cc61c64b 612
3b2f2976 613```
cc61c64b
XL
614$ cargo new --bin adder
615 Created binary (application) `adder` project
616$ cd adder
617```
618
3b2f2976
XL
619We need to modify the binary package’s *Cargo.toml* and add a `[workspace]`
620section to tell Cargo the `adder` package is a workspace. Add this at the
621bottom of the file:
cc61c64b 622
ea8adc8c
XL
623Filename: Cargo.toml
624
3b2f2976 625```
cc61c64b
XL
626[workspace]
627```
628
629Like many Cargo features, workspaces support convention over configuration: we
3b2f2976
XL
630don’t need to add anything more than this to *Cargo.toml* to define our
631workspace as long as we follow the convention.
632
3b2f2976
XL
633### Specifying Workspace Dependencies
634
ea8adc8c
XL
635By default, Cargo will include all transitive path dependencies. A *path
636dependency* is when any crate, whether in a workspace or not, specifies that it
637has a dependency on a crate in a local directory by using the `path` attribute
638on the dependency specification in *Cargo.toml*. If a crate has the
639`[workspace]` key, or if the crate is itself part of a workspace, and we
640specify path dependencies where the paths are subdirectories of the crate’s
641directory, those dependent crates will be considered part of the workspace.
642Let’s specify in the *Cargo.toml* for the top-level `adder` crate that it will
643have a dependency on an `add-one` crate that will be in the `add-one`
644subdirectory, by changing *Cargo.toml* to look like this:
3b2f2976 645
ea8adc8c 646Filename: Cargo.toml
cc61c64b 647
3b2f2976 648```
cc61c64b
XL
649[dependencies]
650add-one = { path = "add-one" }
651```
652
3b2f2976
XL
653If we add dependencies to *Cargo.toml* that don’t have a `path` specified,
654those dependencies will be normal dependencies that aren’t in this workspace
655and are assumed to come from Crates.io.
cc61c64b 656
3b2f2976 657### Creating the Second Crate in the Workspace
cc61c64b 658
3b2f2976
XL
659Next, while in the `adder` directory, generate an `add-one` crate:
660
661```
cc61c64b
XL
662$ cargo new add-one
663 Created library `add-one` project
664```
665
666Your `adder` directory should now have these directories and files:
667
3b2f2976 668```
cc61c64b
XL
669├── Cargo.toml
670├── add-one
671│   ├── Cargo.toml
672│   └── src
673│   └── lib.rs
674└── src
675 └── main.rs
676```
677
3b2f2976 678In *add-one/src/lib.rs*, let’s add an `add_one` function:
cc61c64b 679
3b2f2976 680Filename: add-one/src/lib.rs
cc61c64b 681
3b2f2976 682```
cc61c64b
XL
683pub fn add_one(x: i32) -> i32 {
684 x + 1
685}
686```
687
3b2f2976
XL
688Open up *src/main.rs* for `adder` and add an `extern crate` line at the top of
689the file to bring the new `add-one` library crate into scope. Then change the
ea8adc8c
XL
690`main` function to call the `add_one` function, as in Listing 14-11:
691
692Filename: src/main.rs
cc61c64b 693
3b2f2976 694```
cc61c64b
XL
695extern crate add_one;
696
697fn main() {
698 let num = 10;
699 println!("Hello, world! {} plus one is {}!", num, add_one::add_one(num));
700}
701```
702
ea8adc8c 703Listing 14-11: Using the `add-one` library crate from the `adder` crate
cc61c64b 704
3b2f2976
XL
705Let’s build the `adder` crate by running `cargo build` in the *adder* directory!
706
707```
cc61c64b
XL
708$ cargo build
709 Compiling add-one v0.1.0 (file:///projects/adder/add-one)
710 Compiling adder v0.1.0 (file:///projects/adder)
3b2f2976 711 Finished dev [unoptimized + debuginfo] target(s) in 0.68 secs
cc61c64b
XL
712```
713
3b2f2976
XL
714Note that this builds both the `adder` crate and the `add-one` crate in
715*adder/add-one*. Now your *adder* directory should have these files:
cc61c64b 716
3b2f2976
XL
717```
718├── Cargo.lock
719├── Cargo.toml
720├── add-one
721│   ├── Cargo.toml
722│   └── src
723│   └── lib.rs
724├── src
725│   └── main.rs
726└── target
727```
cc61c64b 728
3b2f2976
XL
729The workspace has one *target* directory at the top level; *add-one* doesn’t
730have its own *target* directory. Even if we go into the `add-one` directory and
731run `cargo build`, the compiled artifacts end up in *adder/target* rather than
732*adder/add-one/target*. The crates in a workspace depend on each other. If each
733crate had its own *target* directory, each crate in the workspace would have to
734recompile each other crate in the workspace in order to have the artifacts in
735its own *target* directory. By sharing one *target* directory, the crates in
736the workspace can avoid rebuilding the other crates in the workspace more than
737necessary.
738
3b2f2976
XL
739#### Depending on an External Crate in a Workspace
740
741Also notice the workspace only has one *Cargo.lock*, rather than having a
742top-level *Cargo.lock* and *add-one/Cargo.lock*. This ensures that all crates
743are using the same version of all dependencies. If we add the `rand` crate to
744both *Cargo.toml* and *add-one/Cargo.toml*, Cargo will resolve both of those to
745one version of `rand` and record that in the one *Cargo.lock*. Making all
746crates in the workspace use the same dependencies means the crates in the
747workspace will always be compatible with each other. Let’s try this out now.
748
749Let’s add the `rand` crate to the `[dependencies]` section in
750*add-one/Cargo.toml* in order to be able to use the `rand` crate in the
751`add-one` crate:
752
753Filename: add-one/Cargo.toml
cc61c64b 754
3b2f2976 755```
cc61c64b
XL
756[dependencies]
757
758rand = "0.3.14"
759```
760
3b2f2976
XL
761We can now add `extern crate rand;` to *add-one/src/lib.rs*, and building the
762whole workspace by running `cargo build` in the *adder* directory will bring in
763and compile the `rand` crate:
cc61c64b 764
3b2f2976 765```
cc61c64b
XL
766$ cargo build
767 Updating registry `https://github.com/rust-lang/crates.io-index`
768 Downloading rand v0.3.14
769 ...snip...
770 Compiling rand v0.3.14
771 Compiling add-one v0.1.0 (file:///projects/adder/add-one)
772 Compiling adder v0.1.0 (file:///projects/adder)
3b2f2976 773 Finished dev [unoptimized + debuginfo] target(s) in 10.18 secs
cc61c64b
XL
774```
775
3b2f2976
XL
776The top level *Cargo.lock* now contains information about `add-one`’s
777dependency on `rand`. However, even though `rand` is used somewhere in the
778workspace, we can’t use it in other crates in the workspace unless we add
cc61c64b 779`rand` to their *Cargo.toml* as well. If we add `extern crate rand;` to
3b2f2976 780*src/main.rs* for the top level `adder` crate, for example, we’ll get an error:
cc61c64b 781
3b2f2976 782```
cc61c64b
XL
783$ cargo build
784 Compiling adder v0.1.0 (file:///projects/adder)
785error[E0463]: can't find crate for `rand`
786 --> src/main.rs:1:1
787 |
7881 | extern crate rand;
789 | ^^^^^^^^^^^^^^^^^^^ can't find crate
790```
791
3b2f2976
XL
792To fix this, edit *Cargo.toml* for the top level `adder` crate and indicate
793that `rand` is a dependency for that crate as well. Building the `adder` crate
794will add `rand` to the list of dependencies for `adder` in *Cargo.lock*, but no
795additional copies of `rand` will be downloaded. Cargo has ensured for us that
796any crate in the workspace using the `rand` crate will be using the same
797version. Using the same version of `rand` across the workspace saves space
798since we won’t have multiple copies and ensures that the crates in the
799workspace will be compatible with each other.
800
801#### Adding a Test to a Workspace
cc61c64b 802
3b2f2976
XL
803For another enhancement, let’s add a test of the `add_one::add_one` function
804within the `add_one` crate:
cc61c64b 805
3b2f2976 806Filename: add-one/src/lib.rs
cc61c64b 807
3b2f2976 808```
cc61c64b
XL
809pub fn add_one(x: i32) -> i32 {
810 x + 1
811}
812
813#[cfg(test)]
814mod tests {
815 use super::*;
816
817 #[test]
818 fn it_works() {
819 assert_eq!(3, add_one(2));
820 }
821}
822```
823
824Now run `cargo test` in the top-level *adder* directory:
825
3b2f2976 826```
cc61c64b
XL
827$ cargo test
828 Compiling adder v0.1.0 (file:///projects/adder)
3b2f2976 829 Finished dev [unoptimized + debuginfo] target(s) in 0.27 secs
cc61c64b
XL
830 Running target/debug/adder-f0253159197f7841
831
832running 0 tests
833
834test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
835```
836
837Wait a second, zero tests? We just added one! If we look at the output, we can
3b2f2976
XL
838see that `cargo test` in a workspace only runs tests for the top level crate.
839To run tests for all of the crates in the workspace, we need to pass the
840`--all` flag:
cc61c64b 841
3b2f2976
XL
842```
843$ cargo test --all
844 Finished dev [unoptimized + debuginfo] target(s) in 0.37 secs
cc61c64b
XL
845 Running target/debug/deps/add_one-abcabcabc
846
847running 1 test
848test tests::it_works ... ok
849
3b2f2976
XL
850test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
851
852 Running target/debug/deps/adder-abcabcabc
853
854running 0 tests
855
856test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
cc61c64b
XL
857
858 Doc-tests add-one
859
860running 0 tests
861
3b2f2976
XL
862test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
863```
864
865When passing `--all`, `cargo test` will run the tests for all of the crates in
866the workspace. We can also choose to run tests for one particular crate in a
867workspace from the top level directory by using the `-p` flag and specifying
868the name of the crate we want to test:
869
870```
871$ cargo test -p add-one
872 Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
873 Running target/debug/deps/add_one-b3235fea9a156f74
874
875running 1 test
876test tests::it_works ... ok
877
878test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
879
880 Doc-tests add-one
881
882running 0 tests
883
884test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
cc61c64b
XL
885```
886
3b2f2976
XL
887This output shows `cargo test` only ran the tests for the `add-one` crate and
888didn’t run the `adder` crate tests.
889
890If you choose to publish the crates in the workspace to crates.io, each crate
891in the workspace will get published separately. The `cargo publish` command
892does not have an `--all` flag or a `-p` flag, so it is necessary to change to
893each crate’s directory and run `cargo publish` on each crate in the workspace
894in order to publish them.
cc61c64b 895
3b2f2976
XL
896Now try adding an `add-two` crate to this workspace in a similar way as the
897`add-one` crate for some more practice!
898
899As your project grows, consider using a workspace: smaller components are
900easier to understand individually than one big blob of code. Keeping the crates
901in a workspace can make coordination among them easier if they work together
902and are often changed at the same time.
cc61c64b
XL
903
904## Installing Binaries from Crates.io with `cargo install`
905
906The `cargo install` command allows you to install and use binary crates
3b2f2976 907locally. This isn’t intended to replace system packages; it’s meant to be a
cc61c64b 908convenient way for Rust developers to install tools that others have shared on
3b2f2976
XL
909crates.io. Only packages that have binary targets can be installed. A binary
910target is the runnable program that gets created if the crate has a
911*src/main.rs* or another file specified as a binary, as opposed to a library
912target that isn’t runnable on its own but is suitable for including within
913other programs. Usually, crates have information in the *README* file about
914whether a crate is a library, has a binary target, or both.
915
3b2f2976
XL
916All binaries from `cargo install` are put into the installation root’s *bin*
917folder. If you installed Rust using *rustup.rs* and don’t have any custom
ea8adc8c
XL
918configurations, this will be `$HOME/.cargo/bin`. Ensure that directory is in
919your `$PATH` to be able to run programs you’ve gotten through `cargo install`.
3b2f2976
XL
920
921For example, we mentioned in Chapter 12 that there’s a Rust implementation of
cc61c64b
XL
922the `grep` tool for searching files called `ripgrep`. If we want to install
923`ripgrep`, we can run:
924
3b2f2976 925```
cc61c64b
XL
926$ cargo install ripgrep
927Updating registry `https://github.com/rust-lang/crates.io-index`
928 Downloading ripgrep v0.3.2
929 ...snip...
930 Compiling ripgrep v0.3.2
931 Finished release [optimized + debuginfo] target(s) in 97.91 secs
932 Installing ~/.cargo/bin/rg
933```
934
935The last line of the output shows the location and the name of the installed
3b2f2976
XL
936binary, which in the case of `ripgrep` is `rg`. As long as the installation
937directory is in your `$PATH` as mentioned above, you can then run `rg --help`
938and start using a faster, rustier tool for searching files!
cc61c64b
XL
939
940## Extending Cargo with Custom Commands
941
3b2f2976 942Cargo is designed so you can extend it with new subcommands without having to
cc61c64b
XL
943modify Cargo itself. If a binary in your `$PATH` is named `cargo-something`,
944you can run it as if it were a Cargo subcommand by running `cargo something`.
3b2f2976
XL
945Custom commands like this are also listed when you run `cargo --list`. Being
946able to `cargo install` extensions and then run them just like the built-in
947Cargo tools is a super convenient benefit of Cargo’s design!
cc61c64b
XL
948
949## Summary
950
951Sharing code with Cargo and crates.io is part of what makes the Rust ecosystem
3b2f2976
XL
952useful for many different tasks. Rust’s standard library is small and stable,
953but crates are easy to share, use, and improve on a timeline different from the
954language itself. Don’t be shy about sharing code that’s useful to you on
955Crates.io; it’s likely that it will be useful to someone else as well!