]>
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 | ||
11 | So far we’ve used only the most basic features of Cargo to build, run, and test | |
12 | our code, but it can do a lot more. In this chapter, we’ll discuss some of its | |
13 | other, 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 |
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 | |
5099ac24 FG |
23 | *https://doc.rust-lang.org/cargo/*. |
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 | |
33 | build` and the `release` profile Cargo uses when you run `cargo build | |
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 | |
04454e1e FG |
48 | Cargo has default settings for each of the profiles that apply when you haven't |
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, | |
04454e1e FG |
67 | you’ll want fewer optimizations to compile faster even if the resulting code |
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 | |
04454e1e | 92 | Cargo’s documentation at *https://doc.rust-lang.org/cargo/reference/profiles.html*. |
5099ac24 FG |
93 | |
94 | ## Publishing a Crate to Crates.io | |
95 | ||
96 | We’ve used packages from *https://crates.io/* as dependencies of our project, | |
97 | but you can also share your code with other people by publishing your own | |
98 | packages. The crate registry at *https://crates.io* distributes the source code | |
99 | of your packages, so it primarily hosts code that is open source. | |
100 | ||
04454e1e FG |
101 | Rust and Cargo have features that make your published package easier for people |
102 | to find and use. We’ll talk about some of these features next and then explain | |
103 | how to publish a package. | |
5099ac24 FG |
104 | |
105 | ### Making Useful Documentation Comments | |
106 | ||
107 | Accurately documenting your packages will help other users know how and when to | |
108 | use them, so it’s worth investing the time to write documentation. In Chapter | |
109 | 3, we discussed how to comment Rust code using two slashes, `//`. Rust also has | |
110 | a particular kind of comment for documentation, known conveniently as a | |
111 | *documentation comment*, that will generate HTML documentation. The HTML | |
112 | displays the contents of documentation comments for public API items intended | |
113 | for programmers interested in knowing how to *use* your crate as opposed to how | |
114 | your crate is *implemented*. | |
115 | ||
116 | Documentation comments use three slashes, `///`, instead of two and support | |
117 | Markdown notation for formatting the text. Place documentation comments just | |
118 | before the item they’re documenting. Listing 14-1 shows documentation comments | |
119 | for an `add_one` function in a crate named `my_crate`. | |
120 | ||
121 | Filename: 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 | /// ``` | |
134 | pub fn add_one(x: i32) -> i32 { | |
135 | x + 1 | |
136 | } | |
137 | ``` | |
138 | ||
139 | Listing 14-1: A documentation comment for a function | |
140 | ||
141 | Here, we give a description of what the `add_one` function does, start a | |
142 | section with the heading `Examples`, and then provide code that demonstrates | |
143 | how to use the `add_one` function. We can generate the HTML documentation from | |
144 | this documentation comment by running `cargo doc`. This command runs the | |
145 | `rustdoc` tool distributed with Rust and puts the generated HTML documentation | |
146 | in the *target/doc* directory. | |
147 | ||
148 | For convenience, running `cargo doc --open` will build the HTML for your | |
149 | current crate’s documentation (as well as the documentation for all of your | |
150 | crate’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 | |
152 | rendered, 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 | ||
156 | Figure 14-1: HTML documentation for the `add_one` function | |
157 | ||
158 | #### Commonly Used Sections | |
159 | ||
160 | We used the `# Examples` Markdown heading in Listing 14-1 to create a section | |
161 | in the HTML with the title “Examples.” Here are some other sections that crate | |
162 | authors 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 | ||
175 | Most documentation comments don’t need all of these sections, but this is a | |
04454e1e FG |
176 | good checklist to remind you of the aspects of your code users will be |
177 | interested in knowing about. | |
5099ac24 FG |
178 | |
179 | #### Documentation Comments as Tests | |
180 | ||
181 | Adding example code blocks in your documentation comments can help demonstrate | |
182 | how to use your library, and doing so has an additional bonus: running `cargo | |
183 | test` will run the code examples in your documentation as tests! Nothing is | |
184 | better than documentation with examples. But nothing is worse than examples | |
185 | that don’t work because the code has changed since the documentation was | |
186 | written. If we run `cargo test` with the documentation for the `add_one` | |
187 | function from Listing 14-1, we will see a section in the test results like this: | |
188 | ||
189 | ``` | |
190 | Doc-tests my_crate | |
191 | ||
192 | running 1 test | |
193 | test src/lib.rs - add_one (line 5) ... ok | |
194 | ||
195 | test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.27s | |
196 | ``` | |
197 | ||
198 | Now if we change either the function or the example so the `assert_eq!` in the | |
199 | example panics and run `cargo test` again, we’ll see that the doc tests catch | |
200 | that the example and the code are out of sync with each other! | |
201 | ||
202 | #### Commenting Contained Items | |
203 | ||
04454e1e FG |
204 | The style of doc comment `//!` adds documentation to the item that contains the |
205 | comments rather than to the items following the comments. We typically use | |
206 | these doc comments inside the crate root file (*src/lib.rs* by convention) or | |
207 | inside a module to document the crate or the module as a whole. | |
5099ac24 | 208 | |
04454e1e FG |
209 | For example, to add documentation that describes the purpose of the `my_crate` |
210 | crate that contains the `add_one` function, we add documentation comments that | |
211 | start with `//!` to the beginning of the *src/lib.rs* file, as shown in Listing | |
212 | 14-2: | |
5099ac24 FG |
213 | |
214 | Filename: 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 | ||
226 | Listing 14-2: Documentation for the `my_crate` crate as a whole | |
227 | ||
228 | Notice there isn’t any code after the last line that begins with `//!`. Because | |
229 | we started the comments with `//!` instead of `///`, we’re documenting the item | |
230 | that contains this comment rather than an item that follows this comment. In | |
04454e1e FG |
231 | this case, that item is the *src/lib.rs* file, which is the crate root. These |
232 | comments describe the entire crate. | |
5099ac24 FG |
233 | |
234 | When we run `cargo doc --open`, these comments will display on the front | |
235 | page of the documentation for `my_crate` above the list of public items in the | |
236 | crate, 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 | ||
240 | Figure 14-2: Rendered documentation for `my_crate`, including the comment | |
241 | describing the crate as a whole | |
242 | ||
243 | Documentation comments within items are useful for describing crates and | |
244 | modules especially. Use them to explain the overall purpose of the container to | |
245 | help your users understand the crate’s organization. | |
246 | ||
247 | ### Exporting a Convenient Public API with `pub use` | |
248 | ||
5099ac24 FG |
249 | The structure of your public API is a major consideration when publishing a |
250 | crate. People who use your crate are less familiar with the structure than you | |
251 | are and might have difficulty finding the pieces they want to use if your crate | |
252 | has a large module hierarchy. | |
253 | ||
04454e1e FG |
254 | In Chapter 7, we covered how to make items public using the `pub` keyword, and |
255 | bring items into a scope with the `use` keyword. However, the structure that | |
256 | makes sense to you while you’re developing a crate might not be very convenient | |
257 | for your users. You might want to organize your structs in a hierarchy | |
258 | containing multiple levels, but then people who want to use a type you’ve | |
259 | defined deep in the hierarchy might have trouble finding out that type exists. | |
260 | They 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 |
264 | The good news is that if the structure *isn’t* convenient for others to use |
265 | from another library, you don’t have to rearrange your internal organization: | |
266 | instead, you can re-export items to make a public structure that’s different | |
267 | from your private structure by using `pub use`. Re-exporting takes a public | |
268 | item in one location and makes it public in another location, as if it were | |
269 | defined in the other location instead. | |
270 | ||
271 | For example, say we made a library named `art` for modeling artistic concepts. | |
272 | Within this library are two modules: a `kinds` module containing two enums | |
273 | named `PrimaryColor` and `SecondaryColor` and a `utils` module containing a | |
274 | function named `mix`, as shown in Listing 14-3: | |
275 | ||
276 | Filename: src/lib.rs | |
277 | ||
278 | ``` | |
279 | //! # Art | |
280 | //! | |
281 | //! A library for modeling artistic concepts. | |
282 | ||
283 | pub 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 | ||
299 | pub 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 | ||
310 | Listing 14-3: An `art` library with items organized into `kinds` and `utils` | |
311 | modules | |
312 | ||
313 | Figure 14-3 shows what the front page of the documentation for this crate | |
314 | generated 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 | ||
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 | |
328 | `PrimaryColor` and `mix` items from the `art` crate: | |
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 | |
357 | items at the top level, as shown in Listing 14-5: | |
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 { | |
371 | // --snip-- | |
372 | } | |
373 | ||
374 | pub mod utils { | |
375 | // --snip-- | |
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 | ||
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 | ||
387 | Figure 14-4: The front page of the documentation for `art` | |
388 | that lists the re-exports | |
389 | ||
390 | The `art` crate users can still see and use the internal structure from Listing | |
391 | 14-3 as demonstrated in Listing 14-4, or they can use the more convenient | |
392 | structure in Listing 14-5, as shown in Listing 14-6: | |
393 | ||
394 | Filename: src/main.rs | |
395 | ||
396 | ``` | |
397 | use art::mix; | |
398 | use art::PrimaryColor; | |
399 | ||
400 | fn main() { | |
401 | // --snip-- | |
402 | } | |
403 | ``` | |
404 | ||
405 | Listing 14-6: A program using the re-exported items from the `art` crate | |
406 | ||
407 | In cases where there are many nested modules, re-exporting the types at the top | |
408 | level with `pub use` can make a significant difference in the experience of | |
409 | people who use the crate. | |
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 | |
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 | |
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 | |
425 | *https://crates.io/me/* and retrieve your API key. Then run the `cargo login` | |
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 | |
435 | revoke it and generate a new token on *https://crates.io/*. | |
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 | |
445 | *https://crates.io/* are allocated on a first-come, first-served basis. Once a | |
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 | |
465 | warning: manifest has no description, license, license-file, documentation, homepage or repository. | |
466 | See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. | |
467 | --snip-- | |
468 | error: failed to publish to registry at https://crates.io | |
469 | ||
470 | Caused 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 | 474 | This errors because you’re missing some crucial information: a description and |
5099ac24 | 475 | license are required so people will know what your crate does and under what |
04454e1e FG |
476 | terms they can use it. In *Cargo.toml*, add a description that's just a |
477 | sentence or two, because it will appear with your crate in search results. For | |
478 | the `license` field, you need to give a *license identifier value*. The Linux | |
479 | Foundation’s Software Package Data Exchange (SPDX) at | |
480 | *http://spdx.org/licenses/* lists the identifiers you can use for this value. | |
481 | For example, to specify that you’ve licensed your crate using the MIT License, | |
482 | add the `MIT` identifier: | |
5099ac24 FG |
483 | |
484 | Filename: Cargo.toml | |
485 | ||
486 | ``` | |
487 | [package] | |
488 | name = "guessing_game" | |
489 | license = "MIT" | |
490 | ``` | |
491 | ||
492 | If you want to use a license that doesn’t appear in the SPDX, you need to place | |
493 | the text of that license in a file, include the file in your project, and then | |
494 | use `license-file` to specify the name of that file instead of using the | |
495 | `license` key. | |
496 | ||
497 | Guidance on which license is appropriate for your project is beyond the scope | |
498 | of this book. Many people in the Rust community license their projects in the | |
499 | same way as Rust by using a dual license of `MIT OR Apache-2.0`. This practice | |
500 | demonstrates that you can also specify multiple license identifiers separated | |
501 | by `OR` to have multiple licenses for your project. | |
502 | ||
503 | With 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 | ||
506 | Filename: Cargo.toml | |
507 | ||
508 | ``` | |
509 | [package] | |
510 | name = "guessing_game" | |
511 | version = "0.1.0" | |
512 | edition = "2021" | |
513 | description = "A fun game where you guess what number the computer has chosen." | |
514 | license = "MIT OR Apache-2.0" | |
515 | ||
516 | [dependencies] | |
517 | ``` | |
518 | ||
519 | Cargo’s documentation at *https://doc.rust-lang.org/cargo/* describes other | |
520 | metadata you can specify to ensure others can discover and use your crate more | |
521 | easily. | |
522 | ||
523 | ### Publishing to Crates.io | |
524 | ||
525 | Now that you’ve created an account, saved your API token, chosen a name for | |
526 | your crate, and specified the required metadata, you’re ready to publish! | |
527 | Publishing a crate uploads a specific version to *https://crates.io/* for | |
528 | others to use. | |
529 | ||
04454e1e FG |
530 | Be careful, because a publish is *permanent*. The version can never be |
531 | overwritten, and the code cannot be deleted. One major goal of crates.io is to | |
532 | act as a permanent archive of code so that builds of all projects that depend | |
533 | on crates from *https://crates.io/* will continue to work. Allowing version | |
534 | deletions would make fulfilling that goal impossible. However, there is no | |
535 | limit to the number of crate versions you can publish. | |
5099ac24 FG |
536 | |
537 | Run 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 | ||
550 | Congratulations! You’ve now shared your code with the Rust community, and | |
551 | anyone can easily add your crate as a dependency of their project. | |
552 | ||
553 | ### Publishing a New Version of an Existing Crate | |
554 | ||
555 | When you’ve made changes to your crate and are ready to release a new version, | |
556 | you change the `version` value specified in your *Cargo.toml* file and | |
557 | republish. Use the Semantic Versioning rules at *http://semver.org/* to decide | |
558 | what an appropriate next version number is based on the kinds of changes you’ve | |
559 | made. Then run `cargo publish` to upload the new version. | |
560 | ||
04454e1e | 561 | ### Deprecating Versions from Crates.io with `cargo yank` |
5099ac24 FG |
562 | |
563 | Although you can’t remove previous versions of a crate, you can prevent any | |
564 | future projects from adding them as a new dependency. This is useful when a | |
565 | crate version is broken for one reason or another. In such situations, Cargo | |
566 | supports *yanking* a crate version. | |
567 | ||
04454e1e FG |
568 | Yanking a version prevents new projects from depending on that version while |
569 | allowing all existing projects that depend on it to continue. Essentially, a | |
570 | yank 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 |
573 | To yank a version of a crate, in the directory of the crate that you’ve |
574 | previously published, run `cargo yank` and specify which version you want to | |
575 | yank: | |
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 |
582 | this 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 | |
584 | been published to crates.io. Do you have suggestions on how to make this | |
585 | clearer? I've tried a bit above /Carol --> | |
586 | ||
5099ac24 FG |
587 | By adding `--undo` to the command, you can also undo a yank and allow projects |
588 | to start depending on a version again: | |
589 | ||
590 | ``` | |
591 | $ cargo yank --vers 1.0.1 --undo | |
592 | ``` | |
593 | ||
04454e1e FG |
594 | A yank *does not* delete any code. It cannot, for example, delete accidentally |
595 | uploaded secrets. If that happens, you must reset those secrets immediately. | |
5099ac24 FG |
596 | |
597 | ## Cargo Workspaces | |
598 | ||
599 | In Chapter 12, we built a package that included a binary crate and a library | |
600 | crate. As your project develops, you might find that the library crate | |
04454e1e FG |
601 | continues to get bigger and you want to split your package further into |
602 | multiple library crates. Cargo offers a feature called *workspaces* that can | |
603 | help manage multiple related packages that are developed in tandem. | |
5099ac24 FG |
604 | |
605 | ### Creating a Workspace | |
606 | ||
607 | A *workspace* is a set of packages that share the same *Cargo.lock* and output | |
608 | directory. Let’s make a project using a workspace—we’ll use trivial code so we | |
609 | can concentrate on the structure of the workspace. There are multiple ways to | |
04454e1e | 610 | structure a workspace, so we'll just show one common way. We’ll have a |
5099ac24 FG |
611 | workspace containing a binary and two libraries. The binary, which will provide |
612 | the main functionality, will depend on the two libraries. One library will | |
613 | provide an `add_one` function, and a second library an `add_two` function. | |
614 | These three crates will be part of the same workspace. We’ll start by creating | |
615 | a new directory for the workspace: | |
616 | ||
617 | ``` | |
618 | $ mkdir add | |
619 | $ cd add | |
620 | ``` | |
621 | ||
622 | Next, in the *add* directory, we create the *Cargo.toml* file that will | |
623 | configure the entire workspace. This file won’t have a `[package]` section or | |
624 | the metadata we’ve seen in other *Cargo.toml* files. Instead, it will start | |
625 | with a `[workspace]` section that will allow us to add members to the workspace | |
626 | by specifying the path to the package with our binary crate; in this case, | |
627 | that path is *adder*: | |
628 | ||
629 | Filename: Cargo.toml | |
630 | ||
631 | ``` | |
632 | [workspace] | |
633 | ||
634 | members = [ | |
635 | "adder", | |
636 | ] | |
637 | ``` | |
638 | ||
639 | Next, 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 | ||
647 | At this point, we can build the workspace by running `cargo build`. The files | |
648 | in 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 |
660 | The workspace has one *target* directory at the top level that the compiled |
661 | artifacts 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* | |
664 | rather than *add/adder/target*. Cargo structures the *target* directory in a | |
665 | workspace like this because the crates in a workspace are meant to depend on | |
666 | each other. If each crate had its own *target* directory, each crate would have | |
667 | to recompile each of the other crates in the workspace to place the artifacts | |
668 | in its own *target* directory. By sharing one *target* directory, the crates | |
669 | can avoid unnecessary rebuilding. | |
5099ac24 FG |
670 | |
671 | ### Creating the Second Package in the Workspace | |
672 | ||
04454e1e FG |
673 | Next, 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 | |
675 | the `members` list: | |
5099ac24 FG |
676 | |
677 | Filename: Cargo.toml | |
678 | ||
679 | ``` | |
680 | [workspace] | |
681 | ||
682 | members = [ | |
683 | "adder", | |
684 | "add_one", | |
685 | ] | |
686 | ``` | |
687 | ||
688 | Then generate a new library crate named `add_one`: | |
689 | ||
690 | ``` | |
691 | $ cargo new add_one --lib | |
692 | Created library `add_one` package | |
693 | ``` | |
694 | ||
695 | Your *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 | ||
711 | In the *add_one/src/lib.rs* file, let’s add an `add_one` function: | |
712 | ||
713 | Filename: add_one/src/lib.rs | |
714 | ||
715 | ``` | |
716 | pub fn add_one(x: i32) -> i32 { | |
717 | x + 1 | |
718 | } | |
719 | ``` | |
720 | ||
04454e1e FG |
721 | Now we can have the `adder` package with our binary depend on the `add_one` |
722 | package that has our library. First, we’ll need to add a path dependency on | |
723 | `add_one` to *adder/Cargo.toml*. | |
5099ac24 FG |
724 | |
725 | Filename: adder/Cargo.toml | |
726 | ||
727 | ``` | |
728 | [dependencies] | |
729 | add_one = { path = "../add_one" } | |
730 | ``` | |
731 | ||
732 | Cargo doesn’t assume that crates in a workspace will depend on each other, so | |
04454e1e | 733 | we need to be explicit about the dependency relationships. |
5099ac24 | 734 | |
04454e1e FG |
735 | Next, 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 | |
737 | top to bring the new `add_one` library crate into scope. Then change the `main` | |
5099ac24 FG |
738 | function to call the `add_one` function, as in Listing 14-7. |
739 | ||
740 | Filename: adder/src/main.rs | |
741 | ||
742 | ``` | |
743 | use add_one; | |
744 | ||
745 | fn 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 | ||
755 | Listing 14-7: Using the `add_one` library crate from the `adder` crate | |
756 | ||
757 | Let’s build the workspace by running `cargo build` in the top-level *add* | |
758 | directory! | |
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 | ||
767 | To run the binary crate from the *add* directory, we can specify which | |
768 | package in the workspace we want to run by using the `-p` argument and the | |
769 | package 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` | |
775 | Hello, world! 10 plus one is 11! | |
776 | ``` | |
777 | ||
778 | This 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 |
782 | Notice that the workspace has only one *Cargo.lock* file at the top level, |
783 | rather than having a *Cargo.lock* in each crate’s directory. This ensures that | |
784 | all crates are using the same version of all dependencies. If we add the `rand` | |
785 | package to the *adder/Cargo.toml* and *add_one/Cargo.toml* files, Cargo will | |
786 | resolve 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 | |
788 | means 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 | |
790 | so we can use the `rand` crate in the `add_one` crate: | |
5099ac24 FG |
791 | |
792 | Filename: add_one/Cargo.toml | |
793 | ||
794 | ``` | |
795 | [dependencies] | |
796 | rand = "0.8.3" | |
797 | ``` | |
798 | ||
799 | We can now add `use rand;` to the *add_one/src/lib.rs* file, and building the | |
800 | whole workspace by running `cargo build` in the *add* directory will bring in | |
801 | and compile the `rand` crate. We will get one warning because we aren’t | |
802 | referring 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) | |
811 | warning: unused import: `rand` | |
812 | --> add_one/src/lib.rs:1:5 | |
813 | | | |
814 | 1 | use rand; | |
815 | | ^^^^ | |
816 | | | |
817 | = note: `#[warn(unused_imports)]` on by default | |
818 | ||
819 | warning: 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 | ||
825 | The 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 | |
827 | workspace, 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;` | |
829 | to 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) | |
835 | error[E0432]: unresolved import `rand` | |
836 | --> adder/src/main.rs:2:5 | |
837 | | | |
838 | 2 | use rand; | |
839 | | ^^^^ no external crate `rand` | |
840 | ``` | |
841 | ||
842 | To fix this, edit the *Cargo.toml* file for the `adder` package and indicate | |
843 | that `rand` is a dependency for it as well. Building the `adder` package will | |
844 | add `rand` to the list of dependencies for `adder` in *Cargo.lock*, but no | |
845 | additional copies of `rand` will be downloaded. Cargo has ensured that every | |
04454e1e FG |
846 | crate in every package in the workspace using the `rand` package will be using |
847 | the same version, saving us space and ensuring that the crates in the workspace | |
848 | will be compatible with each other. | |
5099ac24 FG |
849 | |
850 | #### Adding a Test to a Workspace | |
851 | ||
852 | For another enhancement, let’s add a test of the `add_one::add_one` function | |
853 | within the `add_one` crate: | |
854 | ||
855 | Filename: add_one/src/lib.rs | |
856 | ||
857 | ``` | |
858 | pub fn add_one(x: i32) -> i32 { | |
859 | x + 1 | |
860 | } | |
861 | ||
862 | #[cfg(test)] | |
863 | mod tests { | |
864 | use super::*; | |
865 | ||
866 | #[test] | |
867 | fn it_works() { | |
868 | assert_eq!(3, add_one(2)); | |
869 | } | |
870 | } | |
871 | ``` | |
872 | ||
04454e1e FG |
873 | Now run `cargo test` in the top-level *add* directory. Running `cargo test` in |
874 | a workspace structured like this one will run the tests for all the crates in | |
875 | the 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 | ||
884 | running 1 test | |
885 | test tests::it_works ... ok | |
886 | ||
887 | test 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 | ||
891 | running 0 tests | |
892 | ||
893 | test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s | |
894 | ||
895 | Doc-tests add_one | |
896 | ||
897 | running 0 tests | |
898 | ||
899 | test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s | |
900 | ``` | |
901 | ||
902 | The first section of the output shows that the `it_works` test in the `add_one` | |
903 | crate passed. The next section shows that zero tests were found in the `adder` | |
904 | crate, and then the last section shows zero documentation tests were found in | |
04454e1e | 905 | the `add_one` crate. |
5099ac24 FG |
906 | |
907 | We can also run tests for one particular crate in a workspace from the | |
908 | top-level directory by using the `-p` flag and specifying the name of the crate | |
909 | we 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 | ||
916 | running 1 test | |
917 | test tests::it_works ... ok | |
918 | ||
919 | test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s | |
920 | ||
921 | Doc-tests add_one | |
922 | ||
923 | running 0 tests | |
924 | ||
925 | test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s | |
926 | ``` | |
927 | ||
928 | This output shows `cargo test` only ran the tests for the `add_one` crate and | |
929 | didn’t run the `adder` crate tests. | |
930 | ||
931 | If you publish the crates in the workspace to *https://crates.io/*, each crate | |
04454e1e FG |
932 | in the workspace will need to be published separately. Like `cargo test`, we |
933 | can publish a particular crate in our workspace by using the `-p` flag and | |
934 | specifying the name of the crate we want to publish. | |
5099ac24 FG |
935 | |
936 | For additional practice, add an `add_two` crate to this workspace in a similar | |
937 | way as the `add_one` crate! | |
938 | ||
939 | As your project grows, consider using a workspace: it’s easier to understand | |
940 | smaller, individual components than one big blob of code. Furthermore, keeping | |
04454e1e FG |
941 | the crates in a workspace can make coordination between crates easier if they |
942 | are often changed at the same time. | |
5099ac24 | 943 | |
04454e1e | 944 | ## Installing Binaries with `cargo install` |
5099ac24 FG |
945 | |
946 | The `cargo install` command allows you to install and use binary crates | |
947 | locally. This isn’t intended to replace system packages; it’s meant to be a | |
948 | convenient 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 | |
950 | targets. A *binary target* is the runnable program that is created if the crate | |
951 | has a *src/main.rs* file or another file specified as a binary, as opposed to a | |
952 | library target that isn’t runnable on its own but is suitable for including | |
953 | within other programs. Usually, crates have information in the *README* file | |
954 | about whether a crate is a library, has a binary target, or both. | |
955 | ||
956 | All binaries installed with `cargo install` are stored in the installation | |
957 | root’s *bin* folder. If you installed Rust using *rustup.rs* and don’t have any | |
958 | custom configurations, this directory will be *$HOME/.cargo/bin*. Ensure that | |
959 | directory is in your `$PATH` to be able to run programs you’ve installed with | |
960 | `cargo install`. | |
961 | ||
962 | For example, in Chapter 12 we mentioned that there’s a Rust implementation of | |
04454e1e FG |
963 | the `grep` tool called `ripgrep` for searching files. To install `ripgrep`, we |
964 | can 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 | ||
979 | The second-to-last line of the output shows the location and the name of the | |
980 | installed binary, which in the case of `ripgrep` is `rg`. As long as the | |
981 | installation directory is in your `$PATH`, as mentioned previously, you can | |
982 | then run `rg --help` and start using a faster, rustier tool for searching files! | |
983 | ||
984 | ## Extending Cargo with Custom Commands | |
985 | ||
986 | Cargo is designed so you can extend it with new subcommands without having to | |
987 | modify Cargo. If a binary in your `$PATH` is named `cargo-something`, you can | |
988 | run it as if it was a Cargo subcommand by running `cargo something`. Custom | |
989 | commands like this are also listed when you run `cargo --list`. Being able to | |
990 | use `cargo install` to install extensions and then run them just like the | |
991 | built-in Cargo tools is a super convenient benefit of Cargo’s design! | |
992 | ||
993 | ## Summary | |
994 | ||
995 | Sharing code with Cargo and *https://crates.io/* is part of what makes the Rust | |
996 | ecosystem useful for many different tasks. Rust’s standard library is small and | |
997 | stable, but crates are easy to share, use, and improve on a timeline different | |
998 | from that of the language. Don’t be shy about sharing code that’s useful to you | |
999 | on *https://crates.io/*; it’s likely that it will be useful to someone else as | |
1000 | well! |