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