<!DOCTYPE HTML> <html lang="en"> <head> <meta charset="UTF-8"> <title>Cargo Workspaces - The Rust Programming Language</title> <meta content="text/html; charset=utf-8" http-equiv="Content-Type"> <meta name="description" content=""> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="theme-color" content="#ffffff" /> <base href=""> <link rel="stylesheet" href="book.css"> <link href="https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800" rel="stylesheet" type="text/css"> <link href="https://fonts.googleapis.com/css?family=Source+Code+Pro:500" rel="stylesheet" type="text/css"> <link rel="shortcut icon" href="favicon.png"> <!-- Font Awesome --> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css"> <link rel="stylesheet" href="highlight.css"> <link rel="stylesheet" href="tomorrow-night.css"> <link rel="stylesheet" href="ayu-highlight.css"> <!-- Custom theme --> <!-- Fetch Clipboard.js from CDN but have a local fallback --> <script src="https://cdn.jsdelivr.net/clipboard.js/1.6.1/clipboard.min.js"></script> <script> if (typeof Clipboard == 'undefined') { document.write(unescape("%3Cscript src='clipboard.min.js'%3E%3C/script%3E")); } </script> </head> <body class="light"> <!-- Work around some values being stored in localStorage wrapped in quotes --> <script type="text/javascript"> try { var theme = localStorage.getItem('mdbook-theme'); var sidebar = localStorage.getItem('mdbook-sidebar'); if (theme.startsWith('"') && theme.endsWith('"')) { localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1)); } if (sidebar.startsWith('"') && sidebar.endsWith('"')) { localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1)); } } catch (e) { } </script> <!-- Set the theme before any content is loaded, prevents flash --> <script type="text/javascript"> var theme; try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { } if (theme === null || theme === undefined) { theme = 'light'; } document.body.className = theme; document.querySelector('html').className = theme; </script> <!-- Hide / unhide sidebar before it is displayed --> <script type="text/javascript"> var sidebar = 'hidden'; if (document.body.clientWidth >= 1080) { try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { } sidebar = sidebar || 'visible'; } document.querySelector('html').classList.add("sidebar-" + sidebar); </script> <nav id="sidebar" class="sidebar" aria-label="Table of contents"> <ol class="chapter"><li><a href="ch01-00-introduction.html"><strong aria-hidden="true">1.</strong> Introduction</a></li><li><ol class="section"><li><a href="ch01-01-installation.html"><strong aria-hidden="true">1.1.</strong> Installation</a></li><li><a href="ch01-02-hello-world.html"><strong aria-hidden="true">1.2.</strong> Hello, World!</a></li><li><a href="ch01-03-how-rust-is-made-and-nightly-rust.html"><strong aria-hidden="true">1.3.</strong> How Rust is Made and “Nightly Rust”</a></li></ol></li><li><a href="ch02-00-guessing-game-tutorial.html"><strong aria-hidden="true">2.</strong> Guessing Game Tutorial</a></li><li><a href="ch03-00-common-programming-concepts.html"><strong aria-hidden="true">3.</strong> Common Programming Concepts</a></li><li><ol class="section"><li><a href="ch03-01-variables-and-mutability.html"><strong aria-hidden="true">3.1.</strong> Variables and Mutability</a></li><li><a href="ch03-02-data-types.html"><strong aria-hidden="true">3.2.</strong> Data Types</a></li><li><a href="ch03-03-how-functions-work.html"><strong aria-hidden="true">3.3.</strong> How Functions Work</a></li><li><a href="ch03-04-comments.html"><strong aria-hidden="true">3.4.</strong> Comments</a></li><li><a href="ch03-05-control-flow.html"><strong aria-hidden="true">3.5.</strong> Control Flow</a></li></ol></li><li><a href="ch04-00-understanding-ownership.html"><strong aria-hidden="true">4.</strong> Understanding Ownership</a></li><li><ol class="section"><li><a href="ch04-01-what-is-ownership.html"><strong aria-hidden="true">4.1.</strong> What is Ownership?</a></li><li><a href="ch04-02-references-and-borrowing.html"><strong aria-hidden="true">4.2.</strong> References & Borrowing</a></li><li><a href="ch04-03-slices.html"><strong aria-hidden="true">4.3.</strong> Slices</a></li></ol></li><li><a href="ch05-00-structs.html"><strong aria-hidden="true">5.</strong> Using Structs to Structure Related Data</a></li><li><ol class="section"><li><a href="ch05-01-defining-structs.html"><strong aria-hidden="true">5.1.</strong> Defining and Instantiating Structs</a></li><li><a href="ch05-02-example-structs.html"><strong aria-hidden="true">5.2.</strong> An Example Program Using Structs</a></li><li><a href="ch05-03-method-syntax.html"><strong aria-hidden="true">5.3.</strong> Method Syntax</a></li></ol></li><li><a href="ch06-00-enums.html"><strong aria-hidden="true">6.</strong> Enums and Pattern Matching</a></li><li><ol class="section"><li><a href="ch06-01-defining-an-enum.html"><strong aria-hidden="true">6.1.</strong> Defining an Enum</a></li><li><a href="ch06-02-match.html"><strong aria-hidden="true">6.2.</strong> The match Control Flow Operator</a></li><li><a href="ch06-03-if-let.html"><strong aria-hidden="true">6.3.</strong> Concise Control Flow with if let</a></li></ol></li><li><a href="ch07-00-modules.html"><strong aria-hidden="true">7.</strong> Modules</a></li><li><ol class="section"><li><a href="ch07-01-mod-and-the-filesystem.html"><strong aria-hidden="true">7.1.</strong> mod and the Filesystem</a></li><li><a href="ch07-02-controlling-visibility-with-pub.html"><strong aria-hidden="true">7.2.</strong> Controlling Visibility with pub</a></li><li><a href="ch07-03-importing-names-with-use.html"><strong aria-hidden="true">7.3.</strong> Referring to Names in Different Modules</a></li></ol></li><li><a href="ch08-00-common-collections.html"><strong aria-hidden="true">8.</strong> Common Collections</a></li><li><ol class="section"><li><a href="ch08-01-vectors.html"><strong aria-hidden="true">8.1.</strong> Vectors</a></li><li><a href="ch08-02-strings.html"><strong aria-hidden="true">8.2.</strong> Strings</a></li><li><a href="ch08-03-hash-maps.html"><strong aria-hidden="true">8.3.</strong> Hash Maps</a></li></ol></li><li><a href="ch09-00-error-handling.html"><strong aria-hidden="true">9.</strong> Error Handling</a></li><li><ol class="section"><li><a href="ch09-01-unrecoverable-errors-with-panic.html"><strong aria-hidden="true">9.1.</strong> Unrecoverable Errors with panic!</a></li><li><a href="ch09-02-recoverable-errors-with-result.html"><strong aria-hidden="true">9.2.</strong> Recoverable Errors with Result</a></li><li><a href="ch09-03-to-panic-or-not-to-panic.html"><strong aria-hidden="true">9.3.</strong> To panic! or Not To panic!</a></li></ol></li><li><a href="ch10-00-generics.html"><strong aria-hidden="true">10.</strong> Generic Types, Traits, and Lifetimes</a></li><li><ol class="section"><li><a href="ch10-01-syntax.html"><strong aria-hidden="true">10.1.</strong> Generic Data Types</a></li><li><a href="ch10-02-traits.html"><strong aria-hidden="true">10.2.</strong> Traits: Defining Shared Behavior</a></li><li><a href="ch10-03-lifetime-syntax.html"><strong aria-hidden="true">10.3.</strong> Validating References with Lifetimes</a></li></ol></li><li><a href="ch11-00-testing.html"><strong aria-hidden="true">11.</strong> Testing</a></li><li><ol class="section"><li><a href="ch11-01-writing-tests.html"><strong aria-hidden="true">11.1.</strong> Writing tests</a></li><li><a href="ch11-02-running-tests.html"><strong aria-hidden="true">11.2.</strong> Running tests</a></li><li><a href="ch11-03-test-organization.html"><strong aria-hidden="true">11.3.</strong> Test Organization</a></li></ol></li><li><a href="ch12-00-an-io-project.html"><strong aria-hidden="true">12.</strong> An I/O Project: Building a Command Line Program</a></li><li><ol class="section"><li><a href="ch12-01-accepting-command-line-arguments.html"><strong aria-hidden="true">12.1.</strong> Accepting Command Line Arguments</a></li><li><a href="ch12-02-reading-a-file.html"><strong aria-hidden="true">12.2.</strong> Reading a File</a></li><li><a href="ch12-03-improving-error-handling-and-modularity.html"><strong aria-hidden="true">12.3.</strong> Refactoring to Improve Modularity and Error Handling</a></li><li><a href="ch12-04-testing-the-librarys-functionality.html"><strong aria-hidden="true">12.4.</strong> Developing the Library’s Functionality with Test Driven Development</a></li><li><a href="ch12-05-working-with-environment-variables.html"><strong aria-hidden="true">12.5.</strong> Working with Environment Variables</a></li><li><a href="ch12-06-writing-to-stderr-instead-of-stdout.html"><strong aria-hidden="true">12.6.</strong> Writing Error Messages to Standard Error Instead of Standard Output</a></li></ol></li><li><a href="ch13-00-functional-features.html"><strong aria-hidden="true">13.</strong> Functional Language Features: Iterators and Closures</a></li><li><ol class="section"><li><a href="ch13-01-closures.html"><strong aria-hidden="true">13.1.</strong> Closures: Anonymous Functions that Can Capture Their Environment</a></li><li><a href="ch13-02-iterators.html"><strong aria-hidden="true">13.2.</strong> Processing a Series of Items with Iterators</a></li><li><a href="ch13-03-improving-our-io-project.html"><strong aria-hidden="true">13.3.</strong> Improving Our I/O Project</a></li><li><a href="ch13-04-performance.html"><strong aria-hidden="true">13.4.</strong> Comparing Performance: Loops vs. Iterators</a></li></ol></li><li><a href="ch14-00-more-about-cargo.html"><strong aria-hidden="true">14.</strong> More about Cargo and Crates.io</a></li><li><ol class="section"><li><a href="ch14-01-release-profiles.html"><strong aria-hidden="true">14.1.</strong> Customizing Builds with Release Profiles</a></li><li><a href="ch14-02-publishing-to-crates-io.html"><strong aria-hidden="true">14.2.</strong> Publishing a Crate to Crates.io</a></li><li><a href="ch14-03-cargo-workspaces.html" class="active"><strong aria-hidden="true">14.3.</strong> Cargo Workspaces</a></li><li><a href="ch14-04-installing-binaries.html"><strong aria-hidden="true">14.4.</strong> Installing Binaries from Crates.io with cargo install</a></li><li><a href="ch14-05-extending-cargo.html"><strong aria-hidden="true">14.5.</strong> Extending Cargo with Custom Commands</a></li></ol></li><li><a href="ch15-00-smart-pointers.html"><strong aria-hidden="true">15.</strong> Smart Pointers</a></li><li><ol class="section"><li><a href="ch15-01-box.html"><strong aria-hidden="true">15.1.</strong> Box<T> Points to Data on the Heap and Has a Known Size</a></li><li><a href="ch15-02-deref.html"><strong aria-hidden="true">15.2.</strong> The Deref Trait Allows Access to the Data Through a Reference</a></li><li><a href="ch15-03-drop.html"><strong aria-hidden="true">15.3.</strong> The Drop Trait Runs Code on Cleanup</a></li><li><a href="ch15-04-rc.html"><strong aria-hidden="true">15.4.</strong> Rc<T>, the Reference Counted Smart Pointer</a></li><li><a href="ch15-05-interior-mutability.html"><strong aria-hidden="true">15.5.</strong> RefCell<T> and the Interior Mutability Pattern</a></li><li><a href="ch15-06-reference-cycles.html"><strong aria-hidden="true">15.6.</strong> Creating Reference Cycles and Leaking Memory is Safe</a></li></ol></li><li><a href="ch16-00-concurrency.html"><strong aria-hidden="true">16.</strong> Fearless Concurrency</a></li><li><ol class="section"><li><a href="ch16-01-threads.html"><strong aria-hidden="true">16.1.</strong> Threads</a></li><li><a href="ch16-02-message-passing.html"><strong aria-hidden="true">16.2.</strong> Message Passing</a></li><li><a href="ch16-03-shared-state.html"><strong aria-hidden="true">16.3.</strong> Shared State</a></li><li><a href="ch16-04-extensible-concurrency-sync-and-send.html"><strong aria-hidden="true">16.4.</strong> Extensible Concurrency: Sync and Send</a></li></ol></li><li><a href="ch17-00-oop.html"><strong aria-hidden="true">17.</strong> Is Rust an Object-Oriented Programming Language?</a></li><li><ol class="section"><li><a href="ch17-01-what-is-oo.html"><strong aria-hidden="true">17.1.</strong> What Does Object-Oriented Mean?</a></li><li><a href="ch17-02-trait-objects.html"><strong aria-hidden="true">17.2.</strong> Trait Objects for Using Values of Different Types</a></li><li><a href="ch17-03-oo-design-patterns.html"><strong aria-hidden="true">17.3.</strong> Object-Oriented Design Pattern Implementations</a></li></ol></li><li><a href="ch18-00-patterns.html"><strong aria-hidden="true">18.</strong> Patterns Match the Structure of Values</a></li><li><ol class="section"><li><a href="ch18-01-all-the-places-for-patterns.html"><strong aria-hidden="true">18.1.</strong> All the Places Patterns May be Used</a></li><li><a href="ch18-02-refutability.html"><strong aria-hidden="true">18.2.</strong> Refutability: Whether a Pattern Might Fail to Match</a></li><li><a href="ch18-03-pattern-syntax.html"><strong aria-hidden="true">18.3.</strong> All the Pattern Syntax</a></li></ol></li><li><a href="ch19-00-advanced-features.html"><strong aria-hidden="true">19.</strong> Advanced Features</a></li><li><ol class="section"><li><a href="ch19-01-unsafe-rust.html"><strong aria-hidden="true">19.1.</strong> Unsafe Rust</a></li><li><a href="ch19-02-advanced-lifetimes.html"><strong aria-hidden="true">19.2.</strong> Advanced Lifetimes</a></li><li><a href="ch19-03-advanced-traits.html"><strong aria-hidden="true">19.3.</strong> Advanced Traits</a></li><li><a href="ch19-04-advanced-types.html"><strong aria-hidden="true">19.4.</strong> Advanced Types</a></li><li><a href="ch19-05-advanced-functions-and-closures.html"><strong aria-hidden="true">19.5.</strong> Advanced Functions & Closures</a></li></ol></li><li><a href="ch20-00-final-project-a-web-server.html"><strong aria-hidden="true">20.</strong> Final Project: Building a Multithreaded Web Server</a></li><li><ol class="section"><li><a href="ch20-01-single-threaded.html"><strong aria-hidden="true">20.1.</strong> A Single Threaded Web Server</a></li><li><a href="ch20-02-slow-requests.html"><strong aria-hidden="true">20.2.</strong> How Slow Requests Affect Throughput</a></li><li><a href="ch20-03-designing-the-interface.html"><strong aria-hidden="true">20.3.</strong> Designing the Thread Pool Interface</a></li><li><a href="ch20-04-storing-threads.html"><strong aria-hidden="true">20.4.</strong> Creating the Thread Pool and Storing Threads</a></li><li><a href="ch20-05-sending-requests-via-channels.html"><strong aria-hidden="true">20.5.</strong> Sending Requests to Threads Via Channels</a></li><li><a href="ch20-06-graceful-shutdown-and-cleanup.html"><strong aria-hidden="true">20.6.</strong> Graceful Shutdown and Cleanup</a></li></ol></li><li><a href="appendix-00.html"><strong aria-hidden="true">21.</strong> Appendix</a></li><li><ol class="section"><li><a href="appendix-01-keywords.html"><strong aria-hidden="true">21.1.</strong> A - Keywords</a></li><li><a href="appendix-02-operators.html"><strong aria-hidden="true">21.2.</strong> B - Operators and Symbols</a></li><li><a href="appendix-03-derivable-traits.html"><strong aria-hidden="true">21.3.</strong> C - Derivable Traits</a></li><li><a href="appendix-04-macros.html"><strong aria-hidden="true">21.4.</strong> D - Macros</a></li><li><a href="appendix-05-translation.html"><strong aria-hidden="true">21.5.</strong> E - Translations</a></li><li><a href="appendix-06-newest-features.html"><strong aria-hidden="true">21.6.</strong> F - Newest Features</a></li></ol></li></ol> </nav> <div id="page-wrapper" class="page-wrapper"> <div class="page"> <div id="menu-bar" class="menu-bar"> <div id="menu-bar-sticky-container"> <div class="left-buttons"> <button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar"> <i class="fa fa-bars"></i> </button> <button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list"> <i class="fa fa-paint-brush"></i> </button> <ul id="theme-list" class="theme-popup" aria-label="submenu"> <li><button class="theme" id="light">Light <span class="default">(default)</span></button></li> <li><button class="theme" id="rust">Rust</button></li> <li><button class="theme" id="coal">Coal</button></li> <li><button class="theme" id="navy">Navy</button></li> <li><button class="theme" id="ayu">Ayu</button></li> </ul> </div> <h1 class="menu-title">The Rust Programming Language</h1> <div class="right-buttons"> <a href="print.html" title="Print this book" aria-label="Print this book"> <i id="print-button" class="fa fa-print"></i> </a> </div> </div> </div> <!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM --> <script type="text/javascript"> document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible'); document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible'); Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) { link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1); }); </script> <div id="content" class="content"> <main> <a class="header" href="ch14-03-cargo-workspaces.html#cargo-workspaces" id="cargo-workspaces"><h2>Cargo Workspaces</h2></a> <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 up your package further into multiple library crates. In this situation, Cargo offers a feature called <em>workspaces</em> that can help manage multiple related packages that are developed in tandem.</p> <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 and use trivial code so we can concentrate on the structure of the workspace. There are multiple ways to structure a workspace; we’re going to show a common way. We’ll have a workspace containing a binary and two libraries. The binary will provide the main functionality to be used as a command line tool, and it will depend on the two libraries. One library will provide an <code>add_one</code> function, and a second library will provide 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-text">$ mkdir add $ cd add </code></pre> <p>In the <em>add</em> directory, create a <em>Cargo.toml</em> file. This is the <em>Cargo.toml</em> file that configures the entire workspace. It won’t have a <code>[package]</code> section or metadata we’ve seen in other <em>Cargo.toml</em> files. Instead, we’ll start with a <code>[workspace]</code> section and add a member to the workspace by specifying the path <em>adder</em>, which is where we’ll put our binary crate:</p> <p><span class="filename">Filename: Cargo.toml</span></p> <pre><code class="language-toml">[workspace] members = [ "adder", ] </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> <pre><code class="language-text">$ cargo new --bin adder Created binary (application) `adder` project </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; the <code>adder</code> crate doesn’t have its own <em>target</em> directory. Even if we go into the <em>adder</em> directory and run <code>cargo build</code>, the compiled artifacts end up in <em>add/target</em> rather than <em>add/adder/target</em>. The crates in a workspace are meant to depend on each other. If each crate had its own <em>target</em> directory, each crate in the workspace would have to recompile each of the other crates in the workspace to have the artifacts in its own <em>target</em> directory. By sharing one <em>target</em> directory, the crates in the workspace can avoid rebuilding the other crates in the workspace more than necessary.</p> <a class="header" href="ch14-03-cargo-workspaces.html#creating-the-second-crate-in-the-workspace" id="creating-the-second-crate-in-the-workspace"><h3>Creating the Second Crate in the Workspace</h3></a> <p>Next, let’s specify another member crate in the workspace. This crate will be in the <em>add-one</em> directory, so change the top-level <em>Cargo.toml</em> to have the <em>add-one</em> path as well:</p> <p><span class="filename">Filename: Cargo.toml</span></p> <pre><code class="language-toml">[workspace] members = [ "adder", "add-one", ] </code></pre> <p>Then generate a new library crate named <code>add-one</code>:</p> <pre><code class="language-text">$ cargo new add-one Created library `add-one` project </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><pre class="playpen"><code class="language-rust"> # #![allow(unused_variables)] #fn main() { pub fn add_one(x: i32) -> i32 { x + 1 } #}</code></pre></pre> <p>Now that we have a library crate in the workspace, let’s have the binary crate <code>adder</code> depend on the library crate <code>add-one</code>. 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>Crates in a workspace don’t have to depend on each other, so we still need to be explicit about the dependency relationships between the crates in a workspace.</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 add an <code>extern crate</code> line at the top to bring the new <code>add-one</code> library crate into scope. Then change the <code>main</code> function to call the <code>add_one</code> function, as in Listing 14-7:</p> <p><span class="filename">Filename: adder/src/main.rs</span></p> <pre><code class="language-rust ignore">extern crate add_one; fn main() { let num = 10; println!("Hello, world! {} plus one is {}!", num, add_one::add_one(num)); } </code></pre> <p><span class="caption">Listing 14-7: Using the <code>add-one</code> library crate from the <code>adder</code> crate</span></p> <p>Let’s build the workspace by running <code>cargo build</code> in the <em>add</em> directory!</p> <pre><code class="language-text">$ cargo build Compiling add-one v0.1.0 (file:///projects/add/add-one) Compiling adder v0.1.0 (file:///projects/add/adder) Finished dev [unoptimized + debuginfo] target(s) in 0.68 secs </code></pre> <p>To run the binary crate from the top-level <em>add</em> directory, we need to specify which package in the workspace we want to use by using the <code>-p</code> argument and the package name with <code>cargo run</code>:</p> <pre><code class="language-text">$ cargo run -p adder Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs 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> <a class="header" href="ch14-03-cargo-workspaces.html#depending-on-an-external-crate-in-a-workspace" id="depending-on-an-external-crate-in-a-workspace"><h4>Depending on an External Crate in a Workspace</h4></a> <p>Notice that the workspace has only one <em>Cargo.lock</em> file at the top level of the workspace 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> crate 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 in the workspace 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 to be able to use the <code>rand</code> crate in the <code>add-one</code> crate:</p> <p><span class="filename">Filename: add-one/Cargo.toml</span></p> <pre><code class="language-toml">[dependencies] rand = "0.3.14" </code></pre> <p>We can now add <code>extern crate 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:</p> <pre><code class="language-text">$ cargo build Updating registry `https://github.com/rust-lang/crates.io-index` Downloading rand v0.3.14 --snip-- Compiling rand v0.3.14 Compiling add-one v0.1.0 (file:///projects/add/add-one) Compiling adder v0.1.0 (file:///projects/add/adder) Finished dev [unoptimized + debuginfo] target(s) in 10.18 secs </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>extern crate rand;</code> to the <em>adder/src/main.rs</em> file for the <code>adder</code> crate, we’ll get an error:</p> <pre><code class="language-text">$ cargo build Compiling adder v0.1.0 (file:///projects/add/adder) error: use of unstable library feature 'rand': use `rand` from crates.io (see issue #27703) --> adder/src/main.rs:1:1 | 1 | extern crate rand; </code></pre> <p>To fix this, edit the <em>Cargo.toml</em> file for the <code>adder</code> crate and indicate that <code>rand</code> is a dependency for that crate as well. Building the <code>adder</code> crate 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 has ensured that any crate in the workspace using the <code>rand</code> crate will be using the same version. Using the same version of <code>rand</code> across the workspace saves space because we won’t have multiple copies and ensures that the crates in the workspace will be compatible with each other.</p> <a class="header" href="ch14-03-cargo-workspaces.html#adding-a-test-to-a-workspace" id="adding-a-test-to-a-workspace"><h4>Adding a Test to a Workspace</h4></a> <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><pre class="playpen"><code class="language-rust"> # #![allow(unused_variables)] #fn main() { 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></pre> <p>Now run <code>cargo test</code> in the top-level <em>add</em> directory:</p> <pre><code class="language-text">$ cargo test Compiling add-one v0.1.0 (file:///projects/add/add-one) Compiling adder v0.1.0 (file:///projects/add/adder) Finished dev [unoptimized + debuginfo] target(s) in 0.27 secs Running target/debug/deps/add_one-f0253159197f7841 running 1 test test tests::it_works ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out Running target/debug/deps/adder-f88af9d2cc175a5e running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out Doc-tests add-one running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out </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 0 tests were found in the <code>adder</code> crate, and then the last section shows 0 documentation tests were found in the <code>add-one</code> crate. Running <code>cargo test</code> in a workspace structured like this one will run the tests for all the crates in the workspace.</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> <pre><code class="language-text">$ cargo test -p add-one Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs Running target/debug/deps/add_one-b3235fea9a156f74 running 1 test test tests::it_works ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out Doc-tests add-one running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out </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 <em>https://crates.io/</em>, each crate in the workspace will need to be published separately. The <code>cargo publish</code> command does not have an <code>--all</code> flag or a <code>-p</code> flag, so you must change to each crate’s directory and run <code>cargo publish</code> on each crate in the workspace to publish them.</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’s easier to understand smaller, individual components than one big blob of code. Keeping the crates in a workspace can make coordination between them easier if they are often changed at the same time.</p> </main> <nav class="nav-wrapper" aria-label="Page navigation"> <!-- Mobile navigation buttons --> <a rel="prev" href="ch14-02-publishing-to-crates-io.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left"> <i class="fa fa-angle-left"></i> </a> <a rel="next" href="ch14-04-installing-binaries.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right"> <i class="fa fa-angle-right"></i> </a> <div style="clear: both"></div> </nav> </div> </div> <nav class="nav-wide-wrapper" aria-label="Page navigation"> <a href="ch14-02-publishing-to-crates-io.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left"> <i class="fa fa-angle-left"></i> </a> <a href="ch14-04-installing-binaries.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right"> <i class="fa fa-angle-right"></i> </a> </nav> </div> <!-- Local fallback for Font Awesome --> <script> if (getComputedStyle(document.querySelector(".fa")).fontFamily !== "FontAwesome") { var link = document.createElement('link'); link.rel = 'stylesheet'; link.type = 'text/css'; link.href = '_FontAwesome/css/font-awesome.css'; document.head.insertBefore(link, document.head.firstChild) } </script> <script src="highlight.js"></script> <script src="book.js"></script> <!-- Custom JS script --> </body> </html>