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