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