feat: added cleanscript
This commit is contained in:
22
ch14/ch14-00-more-about-cargo.html
Normal file
22
ch14/ch14-00-more-about-cargo.html
Normal file
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>More about Cargo and Crates.io</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="more-about-cargo-and-cratesio"><a class="header" href="#more-about-cargo-and-cratesio">More About Cargo and Crates.io</a></h1>
|
||||
<p>So far, we’ve used only the most basic features of Cargo to build, run, and
|
||||
test our code, but it can do a lot more. In this chapter, we’ll discuss some of
|
||||
its other, more advanced features to show you how to do the following:</p>
|
||||
<ul>
|
||||
<li>Customize your build through release profiles.</li>
|
||||
<li>Publish libraries on <a href="https://crates.io/">crates.io</a><!-- ignore -->.</li>
|
||||
<li>Organize large projects with workspaces.</li>
|
||||
<li>Install binaries from <a href="https://crates.io/">crates.io</a><!-- ignore -->.</li>
|
||||
<li>Extend Cargo using custom commands.</li>
|
||||
</ul>
|
||||
<p>Cargo can do even more than the functionality we cover in this chapter, so for
|
||||
a full explanation of all its features, see <a href="https://doc.rust-lang.org/cargo/">its documentation</a>.</p>
|
||||
</body>
|
||||
</html>
|
||||
64
ch14/ch14-01-release-profiles.html
Normal file
64
ch14/ch14-01-release-profiles.html
Normal file
@@ -0,0 +1,64 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Customizing Builds with Release Profiles</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2 id="customizing-builds-with-release-profiles"><a class="header" href="#customizing-builds-with-release-profiles">Customizing Builds with Release Profiles</a></h2>
|
||||
<p>In Rust, <em>release profiles</em> are predefined, customizable profiles with
|
||||
different configurations that allow a programmer to have more control over
|
||||
various options for compiling code. Each profile is configured independently of
|
||||
the others.</p>
|
||||
<p>Cargo has two main profiles: the <code>dev</code> profile Cargo uses when you run <code>cargo build</code>, and the <code>release</code> profile Cargo uses when you run <code>cargo build --release</code>. The <code>dev</code> profile is defined with good defaults for development,
|
||||
and the <code>release</code> profile has good defaults for release builds.</p>
|
||||
<p>These profile names might be familiar from the output of your builds:</p>
|
||||
<!-- manual-regeneration
|
||||
anywhere, run:
|
||||
cargo build
|
||||
cargo build --release
|
||||
and ensure output below is accurate
|
||||
-->
|
||||
<pre><code class="language-console">$ cargo build
|
||||
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
|
||||
$ cargo build --release
|
||||
Finished `release` profile [optimized] target(s) in 0.32s
|
||||
</code></pre>
|
||||
<p>The <code>dev</code> and <code>release</code> are these different profiles used by the compiler.</p>
|
||||
<p>Cargo has default settings for each of the profiles that apply when you haven’t
|
||||
explicitly added any <code>[profile.*]</code> sections in the project’s <em>Cargo.toml</em> file.
|
||||
By adding <code>[profile.*]</code> sections for any profile you want to customize, you
|
||||
override any subset of the default settings. For example, here are the default
|
||||
values for the <code>opt-level</code> setting for the <code>dev</code> and <code>release</code> profiles:</p>
|
||||
<p><span class="filename">Filename: Cargo.toml</span></p>
|
||||
<pre><code class="language-toml">[profile.dev]
|
||||
opt-level = 0
|
||||
|
||||
[profile.release]
|
||||
opt-level = 3
|
||||
</code></pre>
|
||||
<p>The <code>opt-level</code> setting controls the number of optimizations Rust will apply to
|
||||
your code, with a range of 0 to 3. Applying more optimizations extends
|
||||
compiling time, so if you’re in development and compiling your code often,
|
||||
you’ll want fewer optimizations to compile faster even if the resultant code
|
||||
runs slower. The default <code>opt-level</code> for <code>dev</code> is therefore <code>0</code>. When you’re
|
||||
ready to release your code, it’s best to spend more time compiling. You’ll only
|
||||
compile in release mode once, but you’ll run the compiled program many times,
|
||||
so release mode trades longer compile time for code that runs faster. That is
|
||||
why the default <code>opt-level</code> for the <code>release</code> profile is <code>3</code>.</p>
|
||||
<p>You can override a default setting by adding a different value for it in
|
||||
<em>Cargo.toml</em>. For example, if we want to use optimization level 1 in the
|
||||
development profile, we can add these two lines to our project’s <em>Cargo.toml</em>
|
||||
file:</p>
|
||||
<p><span class="filename">Filename: Cargo.toml</span></p>
|
||||
<pre><code class="language-toml">[profile.dev]
|
||||
opt-level = 1
|
||||
</code></pre>
|
||||
<p>This code overrides the default setting of <code>0</code>. Now when we run <code>cargo build</code>,
|
||||
Cargo will use the defaults for the <code>dev</code> profile plus our customization to
|
||||
<code>opt-level</code>. Because we set <code>opt-level</code> to <code>1</code>, Cargo will apply more
|
||||
optimizations than the default, but not as many as in a release build.</p>
|
||||
<p>For the full list of configuration options and defaults for each profile, see
|
||||
<a href="https://doc.rust-lang.org/cargo/reference/profiles.html">Cargo’s documentation</a>.</p>
|
||||
</body>
|
||||
</html>
|
||||
479
ch14/ch14-02-publishing-to-crates-io.html
Normal file
479
ch14/ch14-02-publishing-to-crates-io.html
Normal file
@@ -0,0 +1,479 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Publishing a Crate to Crates.io</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2 id="publishing-a-crate-to-cratesio"><a class="header" href="#publishing-a-crate-to-cratesio">Publishing a Crate to Crates.io</a></h2>
|
||||
<p>We’ve used packages from <a href="https://crates.io/">crates.io</a><!-- ignore --> as
|
||||
dependencies of our project, but you can also share your code with other people
|
||||
by publishing your own packages. The crate registry at
|
||||
<a href="https://crates.io/">crates.io</a><!-- ignore --> distributes the source code of
|
||||
your packages, so it primarily hosts code that is open source.</p>
|
||||
<p>Rust and Cargo have features that make your published package easier for people
|
||||
to find and use. We’ll talk about some of these features next and then explain
|
||||
how to publish a package.</p>
|
||||
<h3 id="making-useful-documentation-comments"><a class="header" href="#making-useful-documentation-comments">Making Useful Documentation Comments</a></h3>
|
||||
<p>Accurately documenting your packages will help other users know how and when to
|
||||
use them, so it’s worth investing the time to write documentation. In Chapter
|
||||
3, we discussed how to comment Rust code using two slashes, <code>//</code>. Rust also has
|
||||
a particular kind of comment for documentation, known conveniently as a
|
||||
<em>documentation comment</em>, that will generate HTML documentation. The HTML
|
||||
displays the contents of documentation comments for public API items intended
|
||||
for programmers interested in knowing how to <em>use</em> your crate as opposed to how
|
||||
your crate is <em>implemented</em>.</p>
|
||||
<p>Documentation comments use three slashes, <code>///</code>, instead of two and support
|
||||
Markdown notation for formatting the text. Place documentation comments just
|
||||
before the item they’re documenting. Listing 14-1 shows documentation comments
|
||||
for an <code>add_one</code> function in a crate named <code>my_crate</code>.</p>
|
||||
<figure class="listing" id="listing-14-1">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust ignore">/// Adds one to the number given.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let arg = 5;
|
||||
/// let answer = my_crate::add_one(arg);
|
||||
///
|
||||
/// assert_eq!(6, answer);
|
||||
/// ```
|
||||
pub fn add_one(x: i32) -> i32 {
|
||||
x + 1
|
||||
}</code></pre>
|
||||
<figcaption><a href="#listing-14-1">Listing 14-1</a>: A documentation comment for a function</figcaption>
|
||||
</figure>
|
||||
<p>Here, we give a description of what the <code>add_one</code> function does, start a
|
||||
section with the heading <code>Examples</code>, and then provide code that demonstrates
|
||||
how to use the <code>add_one</code> function. We can generate the HTML documentation from
|
||||
this documentation comment by running <code>cargo doc</code>. This command runs the
|
||||
<code>rustdoc</code> tool distributed with Rust and puts the generated HTML documentation
|
||||
in the <em>target/doc</em> directory.</p>
|
||||
<p>For convenience, running <code>cargo doc --open</code> will build the HTML for your
|
||||
current crate’s documentation (as well as the documentation for all of your
|
||||
crate’s dependencies) and open the result in a web browser. Navigate to the
|
||||
<code>add_one</code> function and you’ll see how the text in the documentation comments is
|
||||
rendered, as shown in Figure 14-1.</p>
|
||||
<img alt="Rendered HTML documentation for the `add_one` function of `my_crate`" src="../img/trpl14-01.png" class="center" />
|
||||
<p><span class="caption">Figure 14-1: The HTML documentation for the <code>add_one</code>
|
||||
function</span></p>
|
||||
<h4 id="commonly-used-sections"><a class="header" href="#commonly-used-sections">Commonly Used Sections</a></h4>
|
||||
<p>We used the <code># Examples</code> Markdown heading in Listing 14-1 to create a section
|
||||
in the HTML with the title “Examples.” Here are some other sections that crate
|
||||
authors commonly use in their documentation:</p>
|
||||
<ul>
|
||||
<li><strong>Panics</strong>: These are the scenarios in which the function being documented
|
||||
could panic. Callers of the function who don’t want their programs to panic
|
||||
should make sure they don’t call the function in these situations.</li>
|
||||
<li><strong>Errors</strong>: If the function returns a <code>Result</code>, describing the kinds of
|
||||
errors that might occur and what conditions might cause those errors to be
|
||||
returned can be helpful to callers so that they can write code to handle the
|
||||
different kinds of errors in different ways.</li>
|
||||
<li><strong>Safety</strong>: If the function is <code>unsafe</code> to call (we discuss unsafety in
|
||||
Chapter 20), there should be a section explaining why the function is unsafe
|
||||
and covering the invariants that the function expects callers to uphold.</li>
|
||||
</ul>
|
||||
<p>Most documentation comments don’t need all of these sections, but this is a
|
||||
good checklist to remind you of the aspects of your code users will be
|
||||
interested in knowing about.</p>
|
||||
<h4 id="documentation-comments-as-tests"><a class="header" href="#documentation-comments-as-tests">Documentation Comments as Tests</a></h4>
|
||||
<p>Adding example code blocks in your documentation comments can help demonstrate
|
||||
how to use your library and has an additional bonus: Running <code>cargo test</code> will
|
||||
run the code examples in your documentation as tests! Nothing is better than
|
||||
documentation with examples. But nothing is worse than examples that don’t work
|
||||
because the code has changed since the documentation was written. If we run
|
||||
<code>cargo test</code> with the documentation for the <code>add_one</code> function from Listing
|
||||
14-1, we will see a section in the test results that looks like this:</p>
|
||||
<!-- manual-regeneration
|
||||
cd listings/ch14-more-about-cargo/listing-14-01/
|
||||
cargo test
|
||||
copy just the doc-tests section below
|
||||
-->
|
||||
<pre><code class="language-text"> Doc-tests my_crate
|
||||
|
||||
running 1 test
|
||||
test src/lib.rs - add_one (line 5) ... ok
|
||||
|
||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.27s
|
||||
</code></pre>
|
||||
<p>Now, if we change either the function or the example so that the <code>assert_eq!</code>
|
||||
in the example panics, and run <code>cargo test</code> again, we’ll see that the doc tests
|
||||
catch that the example and the code are out of sync with each other!</p>
|
||||
<!-- Old headings. Do not remove or links may break. -->
|
||||
<p><a id="commenting-contained-items"></a></p>
|
||||
<h4 id="contained-item-comments"><a class="header" href="#contained-item-comments">Contained Item Comments</a></h4>
|
||||
<p>The style of doc comment <code>//!</code> adds documentation to the item that <em>contains</em>
|
||||
the comments rather than to the items <em>following</em> the comments. We typically
|
||||
use these doc comments inside the crate root file (<em>src/lib.rs</em> by convention)
|
||||
or inside a module to document the crate or the module as a whole.</p>
|
||||
<p>For example, to add documentation that describes the purpose of the <code>my_crate</code>
|
||||
crate that contains the <code>add_one</code> function, we add documentation comments that
|
||||
start with <code>//!</code> to the beginning of the <em>src/lib.rs</em> file, as shown in Listing
|
||||
14-2.</p>
|
||||
<figure class="listing" id="listing-14-2">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust ignore">//! # My Crate
|
||||
//!
|
||||
//! `my_crate` is a collection of utilities to make performing certain
|
||||
//! calculations more convenient.
|
||||
|
||||
/// Adds one to the number given.
|
||||
// --snip--
|
||||
<span class="boring">///
|
||||
</span><span class="boring">/// # Examples
|
||||
</span><span class="boring">///
|
||||
</span><span class="boring">/// ```
|
||||
</span><span class="boring">/// let arg = 5;
|
||||
</span><span class="boring">/// let answer = my_crate::add_one(arg);
|
||||
</span><span class="boring">///
|
||||
</span><span class="boring">/// assert_eq!(6, answer);
|
||||
</span><span class="boring">/// ```
|
||||
</span><span class="boring">pub fn add_one(x: i32) -> i32 {
|
||||
</span><span class="boring"> x + 1
|
||||
</span><span class="boring">}</span></code></pre>
|
||||
<figcaption><a href="#listing-14-2">Listing 14-2</a>: The documentation for the <code>my_crate</code> crate as a whole</figcaption>
|
||||
</figure>
|
||||
<p>Notice there isn’t any code after the last line that begins with <code>//!</code>. Because
|
||||
we started the comments with <code>//!</code> instead of <code>///</code>, we’re documenting the item
|
||||
that contains this comment rather than an item that follows this comment. In
|
||||
this case, that item is the <em>src/lib.rs</em> file, which is the crate root. These
|
||||
comments describe the entire crate.</p>
|
||||
<p>When we run <code>cargo doc --open</code>, these comments will display on the front page
|
||||
of the documentation for <code>my_crate</code> above the list of public items in the
|
||||
crate, as shown in Figure 14-2.</p>
|
||||
<p>Documentation comments within items are useful for describing crates and
|
||||
modules especially. Use them to explain the overall purpose of the container to
|
||||
help your users understand the crate’s organization.</p>
|
||||
<img alt="Rendered HTML documentation with a comment for the crate as a whole" src="../img/trpl14-02.png" class="center" />
|
||||
<p><span class="caption">Figure 14-2: The rendered documentation for <code>my_crate</code>,
|
||||
including the comment describing the crate as a whole</span></p>
|
||||
<!-- Old headings. Do not remove or links may break. -->
|
||||
<p><a id="exporting-a-convenient-public-api-with-pub-use"></a></p>
|
||||
<h3 id="exporting-a-convenient-public-api"><a class="header" href="#exporting-a-convenient-public-api">Exporting a Convenient Public API</a></h3>
|
||||
<p>The structure of your public API is a major consideration when publishing a
|
||||
crate. People who use your crate are less familiar with the structure than you
|
||||
are and might have difficulty finding the pieces they want to use if your crate
|
||||
has a large module hierarchy.</p>
|
||||
<p>In Chapter 7, we covered how to make items public using the <code>pub</code> keyword, and
|
||||
how to bring items into a scope with the <code>use</code> keyword. However, the structure
|
||||
that makes sense to you while you’re developing a crate might not be very
|
||||
convenient for your users. You might want to organize your structs in a
|
||||
hierarchy containing multiple levels, but then people who want to use a type
|
||||
you’ve defined deep in the hierarchy might have trouble finding out that type
|
||||
exists. They might also be annoyed at having to enter <code>use my_crate::some_module::another_module::UsefulType;</code> rather than <code>use my_crate::UsefulType;</code>.</p>
|
||||
<p>The good news is that if the structure <em>isn’t</em> convenient for others to use
|
||||
from another library, you don’t have to rearrange your internal organization:
|
||||
Instead, you can re-export items to make a public structure that’s different
|
||||
from your private structure by using <code>pub use</code>. <em>Re-exporting</em> takes a public
|
||||
item in one location and makes it public in another location, as if it were
|
||||
defined in the other location instead.</p>
|
||||
<p>For example, say we made a library named <code>art</code> for modeling artistic concepts.
|
||||
Within this library are two modules: a <code>kinds</code> module containing two enums
|
||||
named <code>PrimaryColor</code> and <code>SecondaryColor</code> and a <code>utils</code> module containing a
|
||||
function named <code>mix</code>, as shown in Listing 14-3.</p>
|
||||
<figure class="listing" id="listing-14-3">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust noplayground test_harness">//! # Art
|
||||
//!
|
||||
//! A library for modeling artistic concepts.
|
||||
|
||||
pub mod kinds {
|
||||
/// The primary colors according to the RYB color model.
|
||||
pub enum PrimaryColor {
|
||||
Red,
|
||||
Yellow,
|
||||
Blue,
|
||||
}
|
||||
|
||||
/// The secondary colors according to the RYB color model.
|
||||
pub enum SecondaryColor {
|
||||
Orange,
|
||||
Green,
|
||||
Purple,
|
||||
}
|
||||
}
|
||||
|
||||
pub mod utils {
|
||||
use crate::kinds::*;
|
||||
|
||||
/// Combines two primary colors in equal amounts to create
|
||||
/// a secondary color.
|
||||
pub fn mix(c1: PrimaryColor, c2: PrimaryColor) -> SecondaryColor {
|
||||
// --snip--
|
||||
<span class="boring"> unimplemented!();
|
||||
</span> }
|
||||
}</code></pre>
|
||||
<figcaption><a href="#listing-14-3">Listing 14-3</a>: An <code>art</code> library with items organized into <code>kinds</code> and <code>utils</code> modules</figcaption>
|
||||
</figure>
|
||||
<p>Figure 14-3 shows what the front page of the documentation for this crate
|
||||
generated by <code>cargo doc</code> would look like.</p>
|
||||
<img alt="Rendered documentation for the `art` crate that lists the `kinds` and `utils` modules" src="../img/trpl14-03.png" class="center" />
|
||||
<p><span class="caption">Figure 14-3: The front page of the documentation for <code>art</code>
|
||||
that lists the <code>kinds</code> and <code>utils</code> modules</span></p>
|
||||
<p>Note that the <code>PrimaryColor</code> and <code>SecondaryColor</code> types aren’t listed on the
|
||||
front page, nor is the <code>mix</code> function. We have to click <code>kinds</code> and <code>utils</code> to
|
||||
see them.</p>
|
||||
<p>Another crate that depends on this library would need <code>use</code> statements that
|
||||
bring the items from <code>art</code> into scope, specifying the module structure that’s
|
||||
currently defined. Listing 14-4 shows an example of a crate that uses the
|
||||
<code>PrimaryColor</code> and <code>mix</code> items from the <code>art</code> crate.</p>
|
||||
<figure class="listing" id="listing-14-4">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><code class="language-rust ignore">use art::kinds::PrimaryColor;
|
||||
use art::utils::mix;
|
||||
|
||||
fn main() {
|
||||
let red = PrimaryColor::Red;
|
||||
let yellow = PrimaryColor::Yellow;
|
||||
mix(red, yellow);
|
||||
}</code></pre>
|
||||
<figcaption><a href="#listing-14-4">Listing 14-4</a>: A crate using the <code>art</code> crate’s items with its internal structure exported</figcaption>
|
||||
</figure>
|
||||
<p>The author of the code in Listing 14-4, which uses the <code>art</code> crate, had to
|
||||
figure out that <code>PrimaryColor</code> is in the <code>kinds</code> module and <code>mix</code> is in the
|
||||
<code>utils</code> module. The module structure of the <code>art</code> crate is more relevant to
|
||||
developers working on the <code>art</code> crate than to those using it. The internal
|
||||
structure doesn’t contain any useful information for someone trying to
|
||||
understand how to use the <code>art</code> crate, but rather causes confusion because
|
||||
developers who use it have to figure out where to look, and must specify the
|
||||
module names in the <code>use</code> statements.</p>
|
||||
<p>To remove the internal organization from the public API, we can modify the
|
||||
<code>art</code> crate code in Listing 14-3 to add <code>pub use</code> statements to re-export the
|
||||
items at the top level, as shown in Listing 14-5.</p>
|
||||
<figure class="listing" id="listing-14-5">
|
||||
<span class="file-name">Filename: src/lib.rs</span>
|
||||
<pre><code class="language-rust ignore">//! # Art
|
||||
//!
|
||||
//! A library for modeling artistic concepts.
|
||||
|
||||
pub use self::kinds::PrimaryColor;
|
||||
pub use self::kinds::SecondaryColor;
|
||||
pub use self::utils::mix;
|
||||
|
||||
pub mod kinds {
|
||||
// --snip--
|
||||
<span class="boring"> /// The primary colors according to the RYB color model.
|
||||
</span><span class="boring"> pub enum PrimaryColor {
|
||||
</span><span class="boring"> Red,
|
||||
</span><span class="boring"> Yellow,
|
||||
</span><span class="boring"> Blue,
|
||||
</span><span class="boring"> }
|
||||
</span><span class="boring">
|
||||
</span><span class="boring"> /// The secondary colors according to the RYB color model.
|
||||
</span><span class="boring"> pub enum SecondaryColor {
|
||||
</span><span class="boring"> Orange,
|
||||
</span><span class="boring"> Green,
|
||||
</span><span class="boring"> Purple,
|
||||
</span><span class="boring"> }
|
||||
</span>}
|
||||
|
||||
pub mod utils {
|
||||
// --snip--
|
||||
<span class="boring"> use crate::kinds::*;
|
||||
</span><span class="boring">
|
||||
</span><span class="boring"> /// Combines two primary colors in equal amounts to create
|
||||
</span><span class="boring"> /// a secondary color.
|
||||
</span><span class="boring"> pub fn mix(c1: PrimaryColor, c2: PrimaryColor) -> SecondaryColor {
|
||||
</span><span class="boring"> SecondaryColor::Orange
|
||||
</span><span class="boring"> }
|
||||
</span>}</code></pre>
|
||||
<figcaption><a href="#listing-14-5">Listing 14-5</a>: Adding <code>pub use</code> statements to re-export items</figcaption>
|
||||
</figure>
|
||||
<p>The API documentation that <code>cargo doc</code> generates for this crate will now list
|
||||
and link re-exports on the front page, as shown in Figure 14-4, making the
|
||||
<code>PrimaryColor</code> and <code>SecondaryColor</code> types and the <code>mix</code> function easier to find.</p>
|
||||
<img alt="Rendered documentation for the `art` crate with the re-exports on the front page" src="../img/trpl14-04.png" class="center" />
|
||||
<p><span class="caption">Figure 14-4: The front page of the documentation for <code>art</code>
|
||||
that lists the re-exports</span></p>
|
||||
<p>The <code>art</code> crate users can still see and use the internal structure from Listing
|
||||
14-3 as demonstrated in Listing 14-4, or they can use the more convenient
|
||||
structure in Listing 14-5, as shown in Listing 14-6.</p>
|
||||
<figure class="listing" id="listing-14-6">
|
||||
<span class="file-name">Filename: src/main.rs</span>
|
||||
<pre><code class="language-rust ignore">use art::PrimaryColor;
|
||||
use art::mix;
|
||||
|
||||
fn main() {
|
||||
// --snip--
|
||||
<span class="boring"> let red = PrimaryColor::Red;
|
||||
</span><span class="boring"> let yellow = PrimaryColor::Yellow;
|
||||
</span><span class="boring"> mix(red, yellow);
|
||||
</span>}</code></pre>
|
||||
<figcaption><a href="#listing-14-6">Listing 14-6</a>: A program using the re-exported items from the <code>art</code> crate</figcaption>
|
||||
</figure>
|
||||
<p>In cases where there are many nested modules, re-exporting the types at the top
|
||||
level with <code>pub use</code> can make a significant difference in the experience of
|
||||
people who use the crate. Another common use of <code>pub use</code> is to re-export
|
||||
definitions of a dependency in the current crate to make that crate’s
|
||||
definitions part of your crate’s public API.</p>
|
||||
<p>Creating a useful public API structure is more an art than a science, and you
|
||||
can iterate to find the API that works best for your users. Choosing <code>pub use</code>
|
||||
gives you flexibility in how you structure your crate internally and decouples
|
||||
that internal structure from what you present to your users. Look at some of
|
||||
the code of crates you’ve installed to see if their internal structure differs
|
||||
from their public API.</p>
|
||||
<h3 id="setting-up-a-cratesio-account"><a class="header" href="#setting-up-a-cratesio-account">Setting Up a Crates.io Account</a></h3>
|
||||
<p>Before you can publish any crates, you need to create an account on
|
||||
<a href="https://crates.io/">crates.io</a><!-- ignore --> and get an API token. To do so,
|
||||
visit the home page at <a href="https://crates.io/">crates.io</a><!-- ignore --> and log
|
||||
in via a GitHub account. (The GitHub account is currently a requirement, but
|
||||
the site might support other ways of creating an account in the future.) Once
|
||||
you’re logged in, visit your account settings at
|
||||
<a href="https://crates.io/me/">https://crates.io/me/</a><!-- ignore --> and retrieve your
|
||||
API key. Then, run the <code>cargo login</code> command and paste your API key when prompted, like this:</p>
|
||||
<pre><code class="language-console">$ cargo login
|
||||
abcdefghijklmnopqrstuvwxyz012345
|
||||
</code></pre>
|
||||
<p>This command will inform Cargo of your API token and store it locally in
|
||||
<em>~/.cargo/credentials.toml</em>. Note that this token is a secret: Do not share
|
||||
it with anyone else. If you do share it with anyone for any reason, you should
|
||||
revoke it and generate a new token on <a href="https://crates.io/">crates.io</a><!-- ignore
|
||||
-->.</p>
|
||||
<h3 id="adding-metadata-to-a-new-crate"><a class="header" href="#adding-metadata-to-a-new-crate">Adding Metadata to a New Crate</a></h3>
|
||||
<p>Let’s say you have a crate you want to publish. Before publishing, you’ll need
|
||||
to add some metadata in the <code>[package]</code> section of the crate’s <em>Cargo.toml</em>
|
||||
file.</p>
|
||||
<p>Your crate will need a unique name. While you’re working on a crate locally,
|
||||
you can name a crate whatever you’d like. However, crate names on
|
||||
<a href="https://crates.io/">crates.io</a><!-- ignore --> are allocated on a first-come,
|
||||
first-served basis. Once a crate name is taken, no one else can publish a crate
|
||||
with that name. Before attempting to publish a crate, search for the name you
|
||||
want to use. If the name has been used, you will need to find another name and
|
||||
edit the <code>name</code> field in the <em>Cargo.toml</em> file under the <code>[package]</code> section to
|
||||
use the new name for publishing, like so:</p>
|
||||
<p><span class="filename">Filename: Cargo.toml</span></p>
|
||||
<pre><code class="language-toml">[package]
|
||||
name = "guessing_game"
|
||||
</code></pre>
|
||||
<p>Even if you’ve chosen a unique name, when you run <code>cargo publish</code> to publish
|
||||
the crate at this point, you’ll get a warning and then an error:</p>
|
||||
<!-- manual-regeneration
|
||||
Create a new package with an unregistered name, making no further modifications
|
||||
to the generated package, so it is missing the description and license fields.
|
||||
cargo publish
|
||||
copy just the relevant lines below
|
||||
-->
|
||||
<pre><code class="language-console">$ cargo publish
|
||||
Updating crates.io index
|
||||
warning: manifest has no description, license, license-file, documentation, homepage or repository.
|
||||
See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info.
|
||||
--snip--
|
||||
error: failed to publish to registry at https://crates.io
|
||||
|
||||
Caused by:
|
||||
the remote server responded with an error (status 400 Bad Request): missing or empty metadata fields: description, license. Please see https://doc.rust-lang.org/cargo/reference/manifest.html for more information on configuring these fields
|
||||
</code></pre>
|
||||
<p>This results in an error because you’re missing some crucial information: A
|
||||
description and license are required so that people will know what your crate
|
||||
does and under what terms they can use it. In <em>Cargo.toml</em>, add a description
|
||||
that’s just a sentence or two, because it will appear with your crate in search
|
||||
results. For the <code>license</code> field, you need to give a <em>license identifier
|
||||
value</em>. The <a href="https://spdx.org/licenses/">Linux Foundation’s Software Package Data Exchange (SPDX)</a>
|
||||
lists the identifiers you can use for this value. For example, to specify that
|
||||
you’ve licensed your crate using the MIT License, add the <code>MIT</code> identifier:</p>
|
||||
<p><span class="filename">Filename: Cargo.toml</span></p>
|
||||
<pre><code class="language-toml">[package]
|
||||
name = "guessing_game"
|
||||
license = "MIT"
|
||||
</code></pre>
|
||||
<p>If you want to use a license that doesn’t appear in the SPDX, you need to place
|
||||
the text of that license in a file, include the file in your project, and then
|
||||
use <code>license-file</code> to specify the name of that file instead of using the
|
||||
<code>license</code> key.</p>
|
||||
<p>Guidance on which license is appropriate for your project is beyond the scope
|
||||
of this book. Many people in the Rust community license their projects in the
|
||||
same way as Rust by using a dual license of <code>MIT OR Apache-2.0</code>. This practice
|
||||
demonstrates that you can also specify multiple license identifiers separated
|
||||
by <code>OR</code> to have multiple licenses for your project.</p>
|
||||
<p>With a unique name, the version, your description, and a license added, the
|
||||
<em>Cargo.toml</em> file for a project that is ready to publish might look like this:</p>
|
||||
<p><span class="filename">Filename: Cargo.toml</span></p>
|
||||
<pre><code class="language-toml">[package]
|
||||
name = "guessing_game"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
description = "A fun game where you guess what number the computer has chosen."
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
</code></pre>
|
||||
<p><a href="https://doc.rust-lang.org/cargo/">Cargo’s documentation</a> describes other
|
||||
metadata you can specify to ensure that others can discover and use your crate
|
||||
more easily.</p>
|
||||
<h3 id="publishing-to-cratesio"><a class="header" href="#publishing-to-cratesio">Publishing to Crates.io</a></h3>
|
||||
<p>Now that you’ve created an account, saved your API token, chosen a name for
|
||||
your crate, and specified the required metadata, you’re ready to publish!
|
||||
Publishing a crate uploads a specific version to
|
||||
<a href="https://crates.io/">crates.io</a><!-- ignore --> for others to use.</p>
|
||||
<p>Be careful, because a publish is <em>permanent</em>. The version can never be
|
||||
overwritten, and the code cannot be deleted except in certain circumstances.
|
||||
One major goal of Crates.io is to act as a permanent archive of code so that
|
||||
builds of all projects that depend on crates from
|
||||
<a href="https://crates.io/">crates.io</a><!-- ignore --> will continue to work. Allowing
|
||||
version deletions would make fulfilling that goal impossible. However, there is
|
||||
no limit to the number of crate versions you can publish.</p>
|
||||
<p>Run the <code>cargo publish</code> command again. It should succeed now:</p>
|
||||
<!-- manual-regeneration
|
||||
go to some valid crate, publish a new version
|
||||
cargo publish
|
||||
copy just the relevant lines below
|
||||
-->
|
||||
<pre><code class="language-console">$ cargo publish
|
||||
Updating crates.io index
|
||||
Packaging guessing_game v0.1.0 (file:///projects/guessing_game)
|
||||
Packaged 6 files, 1.2KiB (895.0B compressed)
|
||||
Verifying guessing_game v0.1.0 (file:///projects/guessing_game)
|
||||
Compiling guessing_game v0.1.0
|
||||
(file:///projects/guessing_game/target/package/guessing_game-0.1.0)
|
||||
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.19s
|
||||
Uploading guessing_game v0.1.0 (file:///projects/guessing_game)
|
||||
Uploaded guessing_game v0.1.0 to registry `crates-io`
|
||||
note: waiting for `guessing_game v0.1.0` to be available at registry
|
||||
`crates-io`.
|
||||
You may press ctrl-c to skip waiting; the crate should be available shortly.
|
||||
Published guessing_game v0.1.0 at registry `crates-io`
|
||||
</code></pre>
|
||||
<p>Congratulations! You’ve now shared your code with the Rust community, and
|
||||
anyone can easily add your crate as a dependency of their project.</p>
|
||||
<h3 id="publishing-a-new-version-of-an-existing-crate"><a class="header" href="#publishing-a-new-version-of-an-existing-crate">Publishing a New Version of an Existing Crate</a></h3>
|
||||
<p>When you’ve made changes to your crate and are ready to release a new version,
|
||||
you change the <code>version</code> value specified in your <em>Cargo.toml</em> file and
|
||||
republish. Use the <a href="https://semver.org/">Semantic Versioning rules</a> to decide what an
|
||||
appropriate next version number is, based on the kinds of changes you’ve made.
|
||||
Then, run <code>cargo publish</code> to upload the new version.</p>
|
||||
<!-- Old headings. Do not remove or links may break. -->
|
||||
<p><a id="removing-versions-from-cratesio-with-cargo-yank"></a>
|
||||
<a id="deprecating-versions-from-cratesio-with-cargo-yank"></a></p>
|
||||
<h3 id="deprecating-versions-from-cratesio"><a class="header" href="#deprecating-versions-from-cratesio">Deprecating Versions from Crates.io</a></h3>
|
||||
<p>Although you can’t remove previous versions of a crate, you can prevent any
|
||||
future projects from adding them as a new dependency. This is useful when a
|
||||
crate version is broken for one reason or another. In such situations, Cargo
|
||||
supports yanking a crate version.</p>
|
||||
<p><em>Yanking</em> a version prevents new projects from depending on that version while
|
||||
allowing all existing projects that depend on it to continue. Essentially, a
|
||||
yank means that all projects with a <em>Cargo.lock</em> will not break, and any future
|
||||
<em>Cargo.lock</em> files generated will not use the yanked version.</p>
|
||||
<p>To yank a version of a crate, in the directory of the crate that you’ve
|
||||
previously published, run <code>cargo yank</code> and specify which version you want to
|
||||
yank. For example, if we’ve published a crate named <code>guessing_game</code> version
|
||||
1.0.1 and we want to yank it, then we’d run the following in the project
|
||||
directory for <code>guessing_game</code>:</p>
|
||||
<!-- manual-regeneration:
|
||||
cargo yank carol-test --version 2.1.0
|
||||
cargo yank carol-test --version 2.1.0 --undo
|
||||
-->
|
||||
<pre><code class="language-console">$ cargo yank --vers 1.0.1
|
||||
Updating crates.io index
|
||||
Yank guessing_game@1.0.1
|
||||
</code></pre>
|
||||
<p>By adding <code>--undo</code> to the command, you can also undo a yank and allow projects
|
||||
to start depending on a version again:</p>
|
||||
<pre><code class="language-console">$ cargo yank --vers 1.0.1 --undo
|
||||
Updating crates.io index
|
||||
Unyank guessing_game@1.0.1
|
||||
</code></pre>
|
||||
<p>A yank <em>does not</em> delete any code. It cannot, for example, delete accidentally
|
||||
uploaded secrets. If that happens, you must reset those secrets immediately.</p>
|
||||
</body>
|
||||
</html>
|
||||
330
ch14/ch14-03-cargo-workspaces.html
Normal file
330
ch14/ch14-03-cargo-workspaces.html
Normal file
@@ -0,0 +1,330 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Cargo Workspaces</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2 id="cargo-workspaces"><a class="header" href="#cargo-workspaces">Cargo Workspaces</a></h2>
|
||||
<p>In Chapter 12, we built a package that included a binary crate and a library
|
||||
crate. As your project develops, you might find that the library crate
|
||||
continues to get bigger and you want to split your package further into
|
||||
multiple library crates. Cargo offers a feature called <em>workspaces</em> that can
|
||||
help manage multiple related packages that are developed in tandem.</p>
|
||||
<h3 id="creating-a-workspace"><a class="header" href="#creating-a-workspace">Creating a Workspace</a></h3>
|
||||
<p>A <em>workspace</em> is a set of packages that share the same <em>Cargo.lock</em> and output
|
||||
directory. Let’s make a project using a workspace—we’ll use trivial code so
|
||||
that we can concentrate on the structure of the workspace. There are multiple
|
||||
ways to structure a workspace, so we’ll just show one common way. We’ll have a
|
||||
workspace containing a binary and two libraries. The binary, which will provide
|
||||
the main functionality, will depend on the two libraries. One library will
|
||||
provide an <code>add_one</code> function and the other library an <code>add_two</code> function.
|
||||
These three crates will be part of the same workspace. We’ll start by creating
|
||||
a new directory for the workspace:</p>
|
||||
<pre><code class="language-console">$ mkdir add
|
||||
$ cd add
|
||||
</code></pre>
|
||||
<p>Next, in the <em>add</em> directory, we create the <em>Cargo.toml</em> file that will
|
||||
configure the entire workspace. This file won’t have a <code>[package]</code> section.
|
||||
Instead, it will start with a <code>[workspace]</code> section that will allow us to add
|
||||
members to the workspace. We also make a point to use the latest and greatest
|
||||
version of Cargo’s resolver algorithm in our workspace by setting the
|
||||
<code>resolver</code> value to <code>"3"</code>:</p>
|
||||
<p><span class="filename">Filename: Cargo.toml</span></p>
|
||||
<pre><code class="language-toml">[workspace]
|
||||
resolver = "3"
|
||||
</code></pre>
|
||||
<p>Next, we’ll create the <code>adder</code> binary crate by running <code>cargo new</code> within the
|
||||
<em>add</em> directory:</p>
|
||||
<!-- manual-regeneration
|
||||
cd listings/ch14-more-about-cargo/output-only-01-adder-crate/add
|
||||
remove `members = ["adder"]` from Cargo.toml
|
||||
rm -rf adder
|
||||
cargo new adder
|
||||
copy output below
|
||||
-->
|
||||
<pre><code class="language-console">$ cargo new adder
|
||||
Created binary (application) `adder` package
|
||||
Adding `adder` as member of workspace at `file:///projects/add`
|
||||
</code></pre>
|
||||
<p>Running <code>cargo new</code> inside a workspace also automatically adds the newly created
|
||||
package to the <code>members</code> key in the <code>[workspace]</code> definition in the workspace
|
||||
<em>Cargo.toml</em>, like this:</p>
|
||||
<pre><code class="language-toml">[workspace]
|
||||
resolver = "3"
|
||||
members = ["adder"]
|
||||
</code></pre>
|
||||
<p>At this point, we can build the workspace by running <code>cargo build</code>. The files
|
||||
in your <em>add</em> directory should look like this:</p>
|
||||
<pre><code class="language-text">├── Cargo.lock
|
||||
├── Cargo.toml
|
||||
├── adder
|
||||
│ ├── Cargo.toml
|
||||
│ └── src
|
||||
│ └── main.rs
|
||||
└── target
|
||||
</code></pre>
|
||||
<p>The workspace has one <em>target</em> directory at the top level that the compiled
|
||||
artifacts will be placed into; the <code>adder</code> package doesn’t have its own
|
||||
<em>target</em> directory. Even if we were to run <code>cargo build</code> from inside the
|
||||
<em>adder</em> directory, the compiled artifacts would still end up in <em>add/target</em>
|
||||
rather than <em>add/adder/target</em>. Cargo structures the <em>target</em> directory in a
|
||||
workspace like this because the crates in a workspace are meant to depend on
|
||||
each other. If each crate had its own <em>target</em> directory, each crate would have
|
||||
to recompile each of the other crates in the workspace to place the artifacts
|
||||
in its own <em>target</em> directory. By sharing one <em>target</em> directory, the crates
|
||||
can avoid unnecessary rebuilding.</p>
|
||||
<h3 id="creating-the-second-package-in-the-workspace"><a class="header" href="#creating-the-second-package-in-the-workspace">Creating the Second Package in the Workspace</a></h3>
|
||||
<p>Next, let’s create another member package in the workspace and call it
|
||||
<code>add_one</code>. Generate a new library crate named <code>add_one</code>:</p>
|
||||
<!-- manual-regeneration
|
||||
cd listings/ch14-more-about-cargo/output-only-02-add-one/add
|
||||
remove `"add_one"` from `members` list in Cargo.toml
|
||||
rm -rf add_one
|
||||
cargo new add_one --lib
|
||||
copy output below
|
||||
-->
|
||||
<pre><code class="language-console">$ cargo new add_one --lib
|
||||
Created library `add_one` package
|
||||
Adding `add_one` as member of workspace at `file:///projects/add`
|
||||
</code></pre>
|
||||
<p>The top-level <em>Cargo.toml</em> will now include the <em>add_one</em> path in the <code>members</code>
|
||||
list:</p>
|
||||
<p><span class="filename">Filename: Cargo.toml</span></p>
|
||||
<pre><code class="language-toml">[workspace]
|
||||
resolver = "3"
|
||||
members = ["adder", "add_one"]
|
||||
</code></pre>
|
||||
<p>Your <em>add</em> directory should now have these directories and files:</p>
|
||||
<pre><code class="language-text">├── Cargo.lock
|
||||
├── Cargo.toml
|
||||
├── add_one
|
||||
│ ├── Cargo.toml
|
||||
│ └── src
|
||||
│ └── lib.rs
|
||||
├── adder
|
||||
│ ├── Cargo.toml
|
||||
│ └── src
|
||||
│ └── main.rs
|
||||
└── target
|
||||
</code></pre>
|
||||
<p>In the <em>add_one/src/lib.rs</em> file, let’s add an <code>add_one</code> function:</p>
|
||||
<p><span class="filename">Filename: add_one/src/lib.rs</span></p>
|
||||
<pre><code class="language-rust noplayground">pub fn add_one(x: i32) -> i32 {
|
||||
x + 1
|
||||
}</code></pre>
|
||||
<p>Now we can have the <code>adder</code> package with our binary depend on the <code>add_one</code>
|
||||
package that has our library. First, we’ll need to add a path dependency on
|
||||
<code>add_one</code> to <em>adder/Cargo.toml</em>.</p>
|
||||
<p><span class="filename">Filename: adder/Cargo.toml</span></p>
|
||||
<pre><code class="language-toml">[dependencies]
|
||||
add_one = { path = "../add_one" }
|
||||
</code></pre>
|
||||
<p>Cargo doesn’t assume that crates in a workspace will depend on each other, so
|
||||
we need to be explicit about the dependency relationships.</p>
|
||||
<p>Next, let’s use the <code>add_one</code> function (from the <code>add_one</code> crate) in the
|
||||
<code>adder</code> crate. Open the <em>adder/src/main.rs</em> file and change the <code>main</code>
|
||||
function to call the <code>add_one</code> function, as in Listing 14-7.</p>
|
||||
<figure class="listing" id="listing-14-7">
|
||||
<span class="file-name">Filename: adder/src/main.rs</span>
|
||||
<pre><code class="language-rust ignore">fn main() {
|
||||
let num = 10;
|
||||
println!("Hello, world! {num} plus one is {}!", add_one::add_one(num));
|
||||
}</code></pre>
|
||||
<figcaption><a href="#listing-14-7">Listing 14-7</a>: Using the <code>add_one</code> library crate from the <code>adder</code> crate</figcaption>
|
||||
</figure>
|
||||
<p>Let’s build the workspace by running <code>cargo build</code> in the top-level <em>add</em>
|
||||
directory!</p>
|
||||
<!-- manual-regeneration
|
||||
cd listings/ch14-more-about-cargo/listing-14-07/add
|
||||
cargo build
|
||||
copy output below; the output updating script doesn't handle subdirectories in paths properly
|
||||
-->
|
||||
<pre><code class="language-console">$ cargo build
|
||||
Compiling add_one v0.1.0 (file:///projects/add/add_one)
|
||||
Compiling adder v0.1.0 (file:///projects/add/adder)
|
||||
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.22s
|
||||
</code></pre>
|
||||
<p>To run the binary crate from the <em>add</em> directory, we can specify which package
|
||||
in the workspace we want to run by using the <code>-p</code> argument and the package name
|
||||
with <code>cargo run</code>:</p>
|
||||
<!-- manual-regeneration
|
||||
cd listings/ch14-more-about-cargo/listing-14-07/add
|
||||
cargo run -p adder
|
||||
copy output below; the output updating script doesn't handle subdirectories in paths properly
|
||||
-->
|
||||
<pre><code class="language-console">$ cargo run -p adder
|
||||
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
|
||||
Running `target/debug/adder`
|
||||
Hello, world! 10 plus one is 11!
|
||||
</code></pre>
|
||||
<p>This runs the code in <em>adder/src/main.rs</em>, which depends on the <code>add_one</code> crate.</p>
|
||||
<!-- Old headings. Do not remove or links may break. -->
|
||||
<p><a id="depending-on-an-external-package-in-a-workspace"></a></p>
|
||||
<h3 id="depending-on-an-external-package"><a class="header" href="#depending-on-an-external-package">Depending on an External Package</a></h3>
|
||||
<p>Notice that the workspace has only one <em>Cargo.lock</em> file at the top level,
|
||||
rather than having a <em>Cargo.lock</em> in each crate’s directory. This ensures that
|
||||
all crates are using the same version of all dependencies. If we add the <code>rand</code>
|
||||
package to the <em>adder/Cargo.toml</em> and <em>add_one/Cargo.toml</em> files, Cargo will
|
||||
resolve both of those to one version of <code>rand</code> and record that in the one
|
||||
<em>Cargo.lock</em>. Making all crates in the workspace use the same dependencies
|
||||
means the crates will always be compatible with each other. Let’s add the
|
||||
<code>rand</code> crate to the <code>[dependencies]</code> section in the <em>add_one/Cargo.toml</em> file
|
||||
so that we can use the <code>rand</code> crate in the <code>add_one</code> crate:</p>
|
||||
<!-- When updating the version of `rand` used, also update the version of
|
||||
`rand` used in these files so they all match:
|
||||
* ch02-00-guessing-game-tutorial.md
|
||||
* ch07-04-bringing-paths-into-scope-with-the-use-keyword.md
|
||||
-->
|
||||
<p><span class="filename">Filename: add_one/Cargo.toml</span></p>
|
||||
<pre><code class="language-toml">[dependencies]
|
||||
rand = "0.8.5"
|
||||
</code></pre>
|
||||
<p>We can now add <code>use rand;</code> to the <em>add_one/src/lib.rs</em> file, and building the
|
||||
whole workspace by running <code>cargo build</code> in the <em>add</em> directory will bring in
|
||||
and compile the <code>rand</code> crate. We will get one warning because we aren’t
|
||||
referring to the <code>rand</code> we brought into scope:</p>
|
||||
<!-- manual-regeneration
|
||||
cd listings/ch14-more-about-cargo/no-listing-03-workspace-with-external-dependency/add
|
||||
cargo build
|
||||
copy output below; the output updating script doesn't handle subdirectories in paths properly
|
||||
-->
|
||||
<pre><code class="language-console">$ cargo build
|
||||
Updating crates.io index
|
||||
Downloaded rand v0.8.5
|
||||
--snip--
|
||||
Compiling rand v0.8.5
|
||||
Compiling add_one v0.1.0 (file:///projects/add/add_one)
|
||||
warning: unused import: `rand`
|
||||
--> add_one/src/lib.rs:1:5
|
||||
|
|
||||
1 | use rand;
|
||||
| ^^^^
|
||||
|
|
||||
= note: `#[warn(unused_imports)]` on by default
|
||||
|
||||
warning: `add_one` (lib) generated 1 warning (run `cargo fix --lib -p add_one` to apply 1 suggestion)
|
||||
Compiling adder v0.1.0 (file:///projects/add/adder)
|
||||
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.95s
|
||||
</code></pre>
|
||||
<p>The top-level <em>Cargo.lock</em> now contains information about the dependency of
|
||||
<code>add_one</code> on <code>rand</code>. However, even though <code>rand</code> is used somewhere in the
|
||||
workspace, we can’t use it in other crates in the workspace unless we add
|
||||
<code>rand</code> to their <em>Cargo.toml</em> files as well. For example, if we add <code>use rand;</code>
|
||||
to the <em>adder/src/main.rs</em> file for the <code>adder</code> package, we’ll get an error:</p>
|
||||
<!-- manual-regeneration
|
||||
cd listings/ch14-more-about-cargo/output-only-03-use-rand/add
|
||||
cargo build
|
||||
copy output below; the output updating script doesn't handle subdirectories in paths properly
|
||||
-->
|
||||
<pre><code class="language-console">$ cargo build
|
||||
--snip--
|
||||
Compiling adder v0.1.0 (file:///projects/add/adder)
|
||||
error[E0432]: unresolved import `rand`
|
||||
--> adder/src/main.rs:2:5
|
||||
|
|
||||
2 | use rand;
|
||||
| ^^^^ no external crate `rand`
|
||||
</code></pre>
|
||||
<p>To fix this, edit the <em>Cargo.toml</em> file for the <code>adder</code> package and indicate
|
||||
that <code>rand</code> is a dependency for it as well. Building the <code>adder</code> package will
|
||||
add <code>rand</code> to the list of dependencies for <code>adder</code> in <em>Cargo.lock</em>, but no
|
||||
additional copies of <code>rand</code> will be downloaded. Cargo will ensure that every
|
||||
crate in every package in the workspace using the <code>rand</code> package will use the
|
||||
same version as long as they specify compatible versions of <code>rand</code>, saving us
|
||||
space and ensuring that the crates in the workspace will be compatible with
|
||||
each other.</p>
|
||||
<p>If crates in the workspace specify incompatible versions of the same
|
||||
dependency, Cargo will resolve each of them but will still try to resolve as
|
||||
few versions as possible.</p>
|
||||
<h3 id="adding-a-test-to-a-workspace"><a class="header" href="#adding-a-test-to-a-workspace">Adding a Test to a Workspace</a></h3>
|
||||
<p>For another enhancement, let’s add a test of the <code>add_one::add_one</code> function
|
||||
within the <code>add_one</code> crate:</p>
|
||||
<p><span class="filename">Filename: add_one/src/lib.rs</span></p>
|
||||
<pre><code class="language-rust noplayground">pub fn add_one(x: i32) -> i32 {
|
||||
x + 1
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
assert_eq!(3, add_one(2));
|
||||
}
|
||||
}</code></pre>
|
||||
<p>Now run <code>cargo test</code> in the top-level <em>add</em> directory. Running <code>cargo test</code> in
|
||||
a workspace structured like this one will run the tests for all the crates in
|
||||
the workspace:</p>
|
||||
<!-- manual-regeneration
|
||||
cd listings/ch14-more-about-cargo/no-listing-04-workspace-with-tests/add
|
||||
cargo test
|
||||
copy output below; the output updating script doesn't handle subdirectories in
|
||||
paths properly
|
||||
-->
|
||||
<pre><code class="language-console">$ cargo test
|
||||
Compiling add_one v0.1.0 (file:///projects/add/add_one)
|
||||
Compiling adder v0.1.0 (file:///projects/add/adder)
|
||||
Finished `test` profile [unoptimized + debuginfo] target(s) in 0.20s
|
||||
Running unittests src/lib.rs (target/debug/deps/add_one-93c49ee75dc46543)
|
||||
|
||||
running 1 test
|
||||
test tests::it_works ... ok
|
||||
|
||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
|
||||
|
||||
Running unittests src/main.rs (target/debug/deps/adder-3a47283c568d2b6a)
|
||||
|
||||
running 0 tests
|
||||
|
||||
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
|
||||
|
||||
Doc-tests add_one
|
||||
|
||||
running 0 tests
|
||||
|
||||
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
|
||||
</code></pre>
|
||||
<p>The first section of the output shows that the <code>it_works</code> test in the <code>add_one</code>
|
||||
crate passed. The next section shows that zero tests were found in the <code>adder</code>
|
||||
crate, and then the last section shows that zero documentation tests were found
|
||||
in the <code>add_one</code> crate.</p>
|
||||
<p>We can also run tests for one particular crate in a workspace from the
|
||||
top-level directory by using the <code>-p</code> flag and specifying the name of the crate
|
||||
we want to test:</p>
|
||||
<!-- manual-regeneration
|
||||
cd listings/ch14-more-about-cargo/no-listing-04-workspace-with-tests/add
|
||||
cargo test -p add_one
|
||||
copy output below; the output updating script doesn't handle subdirectories in paths properly
|
||||
-->
|
||||
<pre><code class="language-console">$ cargo test -p add_one
|
||||
Finished `test` profile [unoptimized + debuginfo] target(s) in 0.00s
|
||||
Running unittests src/lib.rs (target/debug/deps/add_one-93c49ee75dc46543)
|
||||
|
||||
running 1 test
|
||||
test tests::it_works ... ok
|
||||
|
||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
|
||||
|
||||
Doc-tests add_one
|
||||
|
||||
running 0 tests
|
||||
|
||||
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
|
||||
</code></pre>
|
||||
<p>This output shows <code>cargo test</code> only ran the tests for the <code>add_one</code> crate and
|
||||
didn’t run the <code>adder</code> crate tests.</p>
|
||||
<p>If you publish the crates in the workspace to
|
||||
<a href="https://crates.io/">crates.io</a><!-- ignore -->, each crate in the workspace
|
||||
will need to be published separately. Like <code>cargo test</code>, we can publish a
|
||||
particular crate in our workspace by using the <code>-p</code> flag and specifying the
|
||||
name of the crate we want to publish.</p>
|
||||
<p>For additional practice, add an <code>add_two</code> crate to this workspace in a similar
|
||||
way as the <code>add_one</code> crate!</p>
|
||||
<p>As your project grows, consider using a workspace: It enables you to work with
|
||||
smaller, easier-to-understand components than one big blob of code.
|
||||
Furthermore, keeping the crates in a workspace can make coordination between
|
||||
crates easier if they are often changed at the same time.</p>
|
||||
</body>
|
||||
</html>
|
||||
48
ch14/ch14-04-installing-binaries.html
Normal file
48
ch14/ch14-04-installing-binaries.html
Normal file
@@ -0,0 +1,48 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Installing Binaries with cargo install</title>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Old headings. Do not remove or links may break. -->
|
||||
<p><a id="installing-binaries-from-cratesio-with-cargo-install"></a></p>
|
||||
<h2 id="installing-binaries-with-cargo-install"><a class="header" href="#installing-binaries-with-cargo-install">Installing Binaries with <code>cargo install</code></a></h2>
|
||||
<p>The <code>cargo install</code> command allows you to install and use binary crates
|
||||
locally. This isn’t intended to replace system packages; it’s meant to be a
|
||||
convenient way for Rust developers to install tools that others have shared on
|
||||
<a href="https://crates.io/">crates.io</a><!-- ignore -->. Note that you can only install
|
||||
packages that have binary targets. A <em>binary target</em> is the runnable program
|
||||
that is created if the crate has a <em>src/main.rs</em> file or another file specified
|
||||
as a binary, as opposed to a library target that isn’t runnable on its own but
|
||||
is suitable for including within other programs. Usually, crates have
|
||||
information in the README file about whether a crate is a library, has a
|
||||
binary target, or both.</p>
|
||||
<p>All binaries installed with <code>cargo install</code> are stored in the installation
|
||||
root’s <em>bin</em> folder. If you installed Rust using <em>rustup.rs</em> and don’t have any
|
||||
custom configurations, this directory will be <em>$HOME/.cargo/bin</em>. Ensure that
|
||||
this directory is in your <code>$PATH</code> to be able to run programs you’ve installed
|
||||
with <code>cargo install</code>.</p>
|
||||
<p>For example, in Chapter 12 we mentioned that there’s a Rust implementation of
|
||||
the <code>grep</code> tool called <code>ripgrep</code> for searching files. To install <code>ripgrep</code>, we
|
||||
can run the following:</p>
|
||||
<!-- manual-regeneration
|
||||
cargo install something you don't have, copy relevant output below
|
||||
-->
|
||||
<pre><code class="language-console">$ cargo install ripgrep
|
||||
Updating crates.io index
|
||||
Downloaded ripgrep v14.1.1
|
||||
Downloaded 1 crate (213.6 KB) in 0.40s
|
||||
Installing ripgrep v14.1.1
|
||||
--snip--
|
||||
Compiling grep v0.3.2
|
||||
Finished `release` profile [optimized + debuginfo] target(s) in 6.73s
|
||||
Installing ~/.cargo/bin/rg
|
||||
Installed package `ripgrep v14.1.1` (executable `rg`)
|
||||
</code></pre>
|
||||
<p>The second-to-last line of the output shows the location and the name of the
|
||||
installed binary, which in the case of <code>ripgrep</code> is <code>rg</code>. As long as the
|
||||
installation directory is in your <code>$PATH</code>, as mentioned previously, you can
|
||||
then run <code>rg --help</code> and start using a faster, Rustier tool for searching files!</p>
|
||||
</body>
|
||||
</html>
|
||||
23
ch14/ch14-05-extending-cargo.html
Normal file
23
ch14/ch14-05-extending-cargo.html
Normal file
@@ -0,0 +1,23 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Extending Cargo with Custom Commands</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2 id="extending-cargo-with-custom-commands"><a class="header" href="#extending-cargo-with-custom-commands">Extending Cargo with Custom Commands</a></h2>
|
||||
<p>Cargo is designed so that you can extend it with new subcommands without having
|
||||
to modify it. If a binary in your <code>$PATH</code> is named <code>cargo-something</code>, you can
|
||||
run it as if it were a Cargo subcommand by running <code>cargo something</code>. Custom
|
||||
commands like this are also listed when you run <code>cargo --list</code>. Being able to
|
||||
use <code>cargo install</code> to install extensions and then run them just like the
|
||||
built-in Cargo tools is a super-convenient benefit of Cargo’s design!</p>
|
||||
<h2 id="summary"><a class="header" href="#summary">Summary</a></h2>
|
||||
<p>Sharing code with Cargo and <a href="https://crates.io/">crates.io</a><!-- ignore --> is
|
||||
part of what makes the Rust ecosystem useful for many different tasks. Rust’s
|
||||
standard library is small and stable, but crates are easy to share, use, and
|
||||
improve on a timeline different from that of the language. Don’t be shy about
|
||||
sharing code that’s useful to you on <a href="https://crates.io/">crates.io</a><!-- ignore
|
||||
-->; it’s likely that it will be useful to someone else as well!</p>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user