Compare commits

...

2 Commits

Author SHA1 Message Date
629cbea79d finished ch14.4
Some checks failed
Test Gitea Actions / first (push) Successful in 15s
Test Gitea Actions / check-code (push) Failing after 13s
Test Gitea Actions / test (push) Has been skipped
Test Gitea Actions / documentation-check (push) Has been skipped
2025-02-26 16:41:39 -07:00
43816205f3 finished ch14.2 2025-02-26 12:04:36 -07:00
6 changed files with 501 additions and 5 deletions

319
Cargo Workspaces.md Normal file
View File

@ -0,0 +1,319 @@
# Cargo Workspaces
As our project developsm 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 *workspaces* that can help manage related packages that are developed at the same time
## Creating a Workspace
A *workspace* is a set of packages that share the same *Cargo.lock* and output directory.
Lets explore this by a making a project using a workspace
Here we will use trivial code so that the focus is on the structure of the workspace.
There are mulitple ways to structure a workspace, here we will just show one common way.
Here we will have a workspace containing a binary and two libraries.
The binary will provide the main functionality, will depend on the two libraries.
One lib will provide an `add_one` function
Another lib will provide an `add_two` function
These three crates will be part of the same workspace.
We will start by creating a new directory for the workspace
```
$ mkdir add
$ cd add
```
Now in the *add* directory, we create the *Cargo.toml* file that will config the entire workspace.
This file wont have a `[package]` section, instead it will start with a `[workspace]` section.
This allows us to add members to the workspace.
We also make it a point to use the latest and greatest version of Cargo's resolver algorithm in our workspace by setting the `resolver` to `"2"`
Here is the written out version of the toml file until this point
```toml
[workspace]
resolver = "2"
```
Next we will create the `adder` binary crate
We do this by running `cargo new` within the *add* directory
```
$ cargo new adder
Creating binary (application) `adder` package
Adding `adder` as member of workspace at `file:///projects/add`
```
By running the `cargo new` command inside a workspace it automatically adds the newly created package to the `members` key in the `[workspace]` definition in the workspace `Cargo.toml`
It will look like this
```toml
[workspace]
resolver = "2"
members = ["adder"]
```
Now at this point we can build the workspace by rnning `cargo build`
The files in the *add* directory should now look like this
```
├── Cargo.lock
├── Cargo.toml
├── adder
│ ├── Cargo.toml
│ └── src
│ └── main.rs
└── target
```
The workspace has one *target* directory at the top level that compled artifacts will be placed into
The `adder` package doesn't have its own *target* directory.
Even if we were to run `cargo build` from inside the *addre* dir, the compiled artifacts would still end up in *add/target* rather than *add/adder/target*
Cargo structs the *target* directory in a workspace like this because the crates in a workspace are meant to depend on each other.
Without this we would have to repeat compiled artifacts and this would cause unnecessary rebuilding.
So we share one *target* directory to avoid this.
## Creating the Second Package in the Wrokspace
Now lets add another package to the workspace, we will call it
First we will change the top level *Cargo.toml* to specify the *add_one* path in the `members` list
Here is the updated toml
```toml
[workspace]
resolver = "2"
members = ["adder", "add_one"]
```
Now lets generate a new library crate named `add_one`
```
$ cargo new add_one --lib
Creating library `add_one` package
Adding `add_one` as member of workspace at `file:///projects/add`
```
Now the *add* directory should look like this
```
├── Cargo.lock
├── Cargo.toml
├── add_one
│ ├── Cargo.toml
│ └── src
│ └── lib.rs
├── adder
│ ├── Cargo.toml
│ └── src
│ └── main.rs
└── target
```
In *add_one/src/lib.rs* lets add the `add_one` function
```rust
pub fn add_one(x: i32) -> i32 {
x + 1
}
```
Now we need to have the `adder` package with our binary depend on the `add_one` package that has our library.
We need to add a path dependency on `add_one` to *adder/Cargo.toml*
```toml
[dependencies]
add_one = { path = "../add_one" }
```
Cargo doesnt assume that crates in a workspace will depend on each other.
We must explicit about the dependency relationships.
Now lets use the `add_one` function in the `adder` crate.
You modify the *adder/src/main.rs* file and change the `main` function to call the `add_one` function
Here is the updated `main` function in the binary crate
```rust
fn main() {
let num = 10;
println!("Hello, world! {num} plus one is {}!", add_one::add_one(num));
}
```
Now we can build the workspace from the top-level *add* directory
```
$ 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
```
In order to run the binary crate from the *add* directory have have to specify which package in the workspace we want to run.
We do this by using the `-p` argument and the package name with `cargo run`
```
$ 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!
```
This runs the `main` function in *adder/src/main.rs*, which depends on the `add_one` crate
### Depending on an External Package in a Wrokspace
Notice that the workspace only has one *Cargo.lock* file at the top level.
This ensure that all crates are using the same version of all dependencies.
If we add the `rand` package to the *adder/Cargo.toml* and *add_one/Cargo.toml* files
Cargo will resolve both of thos to one version of `rand` and record that in the one *Cargo.lock*.
This ensures that all the crates in the workspace use the same dependencies, this also ensures that all crates will always be compatible with each other.
Lets demonstrate how to add the `rand` crate to the `[dependencies]` section in the *add_one/Cargo.toml* file so we can use the `rand` crate in the `add_one` crate
```toml
[dependencies]
rand = "0.8.5"
```
Now we can add `use rand;` to the *add_one/src/lib.rs* file.
Then build the whole workspace in the *add* directory will bring in and compile the `rand` crate.
We will get a warning about a unused `rand` becasue we dont refer to it after we bring it into scope
```
$ 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
```
Now the top level *Cargo.lock* now contains info about the dependency of `add_one` on `rand`
However, even though `rand` is used somewhere in the workspace, we can't use it in other crates in the workspace unless we add `rand` to thier *Cargo.toml* files as well
For example if we add `use rand;` to the *adder/src/main.rs* file for the `adder` package we would get an error
```
$ 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`
```
In order to fix this we need to edit the *Cargo.toml* file for the `adder` package and indicate that `rand` is a dependency for it as well.
Rebuilding the `adder` package with the eidt will now add the `rand` crate to the list of dependencies for `adder` in *Cargo.lock*.
No additional copies of `rand` will be downloaded.
Cargo will ensure that every crate in every package in the workspace using the `rand` package will be using the same version as log as they specify compatible versions of `rand`.
This saves us space and ensures that the crates in the workspace will be compatible with each other.
If crates in the workspace specify incompatible verions of the same dependency, Cargo will attempt to resolve each of them but it will still try to resolve it with as few versions as possible
### Adding a Test to a Workspace
For another enchancement lets add a test of the `add)one::add_one` function within the `add_one` crate
Here is the updated *add_one/src/lib.rs*
```rust
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));
}
}
```
Now if we run `cargo test` in the top level *add* directory in a workspace structured like thisone will run the tests for all the crates in the workspace.
Here is what the output will look like this
```
$ 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-f0253159197f7841)
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-49979ff40686fa8e)
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
```
The first section shows that the `it_works` test in the `add_one` crate pased
The next section shows that zero tests were found in the `adder` crate.
Thhe last section shows zero documentation tests were found in the `add_one` crate.
We can also run tests for a particular crate in a workspace from the top-level directory.
We do this by adding the `-p` flag and specifying th name of the crate we want to test.
Here is an example of this
```
$ 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-b3235fea9a156f74)
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
```
This shows that `cargo test` only ran tests for the `add_one` crate and didn't run the `adder` crate tests.
If you publish the crates in the workspace to [crates.io](https://crates.io), each crate in the workspace will need to be published separately.
Just like `cargo test`, you can publish a particular crate in the workspace by using the `-p` flag and specifying the name of the crate we want to publish.
As your project grows, consider using a workspace.
It makes it easier to understand smaller, individual components than one big blog of code.
Also by keeping the crates in a workspace can make coordination between crates easier if they are often changed at the same time.

View File

@ -7,8 +7,8 @@ Cargo can do so much more
This chapter will go over some more advanced features like:
- [Customize your build](./Custome%20Build%20Profiles.md) through release profiles
- [Publish libraries](./Publishing%20libraries.md) on [crates.io](https://crates.io/)
- Organize large projects with workspaces
- Install binaries from [crates.io](https://crates.io/)
- Organize large projects with [workspaces](./Cargo%20Workspaces.md)
- [Install binaries](./Install%20Binaries.md) from [crates.io](https://crates.io/)
- Extend Cargo using custom commands
Cargo can do even more than what will be covered.

1
Install Binaries.md Normal file
View File

@ -0,0 +1 @@
# Installing Binaries with `cargo install`

View File

@ -274,4 +274,180 @@ Choosing `pub use` gives you flexibility in how you structure your crate interna
Look at some of the code of crates you have used previously to see if their internal struct differs from their public API.
## Setting Up a Crates.io Account
Before being able to create
Before being able to publish creates, you need an account on [crates.io](https://crates.io) and get an API toekn
You can do ths by
1. visit the homepage at [crates.io](https://crates.io)
2. Log in via a Github account (could use any other type that is supported)
3. Once logged in, go to your account settings at [https://crates.io/me/](https://crates.io/me/)
4. Retrieve your API key
5. Run the `cargo login` command nad paste the API key when prompted
Here is an example
```
$ cargo login
abcdefghijklmnopqrstuvwxyz012345
```
This will inform Cargo of your API token and store it locally in *~/.cargo/credentials*
Note that this tken is a *secret*. DO NOT SHARE IT
You can revoke it and generate a new token on [crate.io](https://crates.io) if you do accidentally share it.
## Adding Metadata to a New Crate
Lets say you gave a crate you want ot publish.
Before doing that you need to add some metadata in the `[package] section of the crate's *Cargo.toml* file.
You need a unqiue crate name.
When working locally you can name a crate anything you like.
However crate names on [crates.io](https://crates.io) are allocated on a first-come, first-serverd basis.
Once a crate name is taken, no one else can publish a crate with that same name.
SUPER GOOD ADVICE: 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 `name` field in the *Cargo.toml* file under the `[package]` section to use the new name for publishing.
Here is an example of this
```toml
[package]
name = "guessing_game"
```
Even if you chose a unqiue name when you run `cargo publish` to publish the crate at this point you will get a warning then an error.
Here is an example of this output
```
$ 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 field
```
These errors are caused by missing some crucial information:
- A description
- A license
Both of these are required so people will know what your crate does and under what terms they can use it.
In *Cargo.toml* add a description that that is a sentence or two. This will appear with your crate in search results.
For the `license` field you need to give a *license identifier value*
The [Linux Foundations Software Package Data Exchange (SPDX)](https://spdx.org/licenses/) lists identifers you can use for this value.
For example to specify that you are licensing your crate using the MIT License add the `MIT` identifier
```toml
[package]
name = "guessing_game"
license = "MIT"
```
If you want to use a license that isnt in te SPDX, you will need to plcae the text of that license in a file.
Include that file in your porject and then use `license-file` to specify the name of that file instead of using the `license` key.
Guidance on which license is appropriate for your project is a highly personal and higly techincal.
Please read through the license to pick the most approprate one for your case use with any considerations to dependances.
Many people in the Rust community license their projects in the same way as Rust by using a dual license of `MIT OR Apache-2.0`
This demonstrates that you can also specify multiple license identifiers separated by `OR` to have multiple licenses for your project.
With a unique name, the version, the description and a license added. The *Cargo.toml* file for a project that is ready to publish would look similar to this:
```toml
[package]
name = "guessing_game"
version = "0.1.0"
edition = "2021"
description = "A fun game where you guess what number the computer has chosen."
license = "MIT OR Apache-2.0"
[dependencies]
```
[Cargo's documentation](https://doc.rust-lang.org/cargo/) describes other metadata you can specify to ensure othes can discover and use your crate more easily.
## Publishing to Crates.io
Now that you have an account, cargo has saved your API otken, chosen a name for your crate and specified the required metadata. Yuo are ready to publish.
Publishing a crate uploads a specific version to [crates.io](https://crates.io) for others to use.
A Publish is *PERMANENT*.
The version can never be overwritten and the code cannot be deleted.
One major goal of [crates.io](https://crates.io) is to act as a permanent archive of code so that builds of all projects that depend on crates from [crates.io](https://crates.io) will continue to always work.
Allowing version deletions would make this goal impossible.
There is no limit to the number of crate versions you can publish.
If you run `cargo publish` again it should succeed now.
Here is the output now
```
$ cargo publish
Updating crates.io index
Packaging guessing_game v0.1.0 (file:///projects/guessing_game)
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)
```
This is a successful output and indicates you have successfully shared your code with the Rst community and now anyone can easily add your crate as a dependency of their project.
## Publishing a New Version of an Exisiting Crate
When you made changes to your crate and are ready to release a new version.
First you change the `version` value specified in your *Cargo.toml* file and republish.
Use [Semantic Versioning rules](http://semver.org/) to decide what an appropriate nexxt version based on the kinds of changes made.
Finally run `cargo publish` to upload a new version
### Deprecaitng Versions for mCrates.io with `cargo yank`
Even though you can remove previous versions of a crate, you can prevent any future projects fom adding them as a new dependency.
This is useful when a crate version is broken for some reason.
In such situations, Cargo supports *yanking* a crate version.
Yanking a version prevents new projects form depending on that version while allowing all exisitng projects to continue to depend on that version.
This essentially means a yank won't break any exisiting projects with a *Cargo.lock* with that version will not break. But any new *Cargo.lock* files generated will not be able to use the yanked version.
To yank a version of a create.
1. Go to the directory of the crate that has been previously publish.
2. Run `cargo yank` and specify which version to yank.
For example lets say we have published a create named `guessing_game` version 1.0.1 and we want to yank it.
In the project directory for the `guessing_game` crate we would run
```
$ cargo yank --vers 1.0.1
Updating crates.io index
Yank guessing_game@1.0.1
```
If we wanted to undo that we would add `--undo` to the command.
This would allow prjects to start depending on that version again
```
$ cargo yank --vers 1.0.1 --undo
Updating crates.io index
Unyank guessing_game@1.0.1
```
ONCE AGAIN NOTICE a yank does *NOT* delete any code.
If you accidentally uploaded secrets, you must reset those secrets immediately.

View File

@ -1 +1 @@
{"rustc_fingerprint":4305361489769004817,"outputs":{"17747080675513052775":{"success":true,"status":"","code":0,"stdout":"rustc 1.85.0 (4d91de4e4 2025-02-17)\nbinary: rustc\ncommit-hash: 4d91de4e48198da2e33413efdcd9cd2cc0c46688\ncommit-date: 2025-02-17\nhost: x86_64-unknown-linux-gnu\nrelease: 1.85.0\nLLVM version: 19.1.7\n","stderr":""},"13331785392996375709":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/home/brock/.rustup/toolchains/stable-x86_64-unknown-linux-gnu\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n","stderr":""}},"successes":{}}
{"rustc_fingerprint":4305361489769004817,"outputs":{"2063776225603076451":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/home/brock/.rustup/toolchains/stable-x86_64-unknown-linux-gnu\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n","stderr":""},"17747080675513052775":{"success":true,"status":"","code":0,"stdout":"rustc 1.85.0 (4d91de4e4 2025-02-17)\nbinary: rustc\ncommit-hash: 4d91de4e48198da2e33413efdcd9cd2cc0c46688\ncommit-date: 2025-02-17\nhost: x86_64-unknown-linux-gnu\nrelease: 1.85.0\nLLVM version: 19.1.7\n","stderr":""},"13331785392996375709":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/home/brock/.rustup/toolchains/stable-x86_64-unknown-linux-gnu\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n","stderr":""}},"successes":{}}

View File

@ -1 +1 @@
{"rustc_fingerprint":4305361489769004817,"outputs":{"17747080675513052775":{"success":true,"status":"","code":0,"stdout":"rustc 1.85.0 (4d91de4e4 2025-02-17)\nbinary: rustc\ncommit-hash: 4d91de4e48198da2e33413efdcd9cd2cc0c46688\ncommit-date: 2025-02-17\nhost: x86_64-unknown-linux-gnu\nrelease: 1.85.0\nLLVM version: 19.1.7\n","stderr":""},"13331785392996375709":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/home/brock/.rustup/toolchains/stable-x86_64-unknown-linux-gnu\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n","stderr":""}},"successes":{}}
{"rustc_fingerprint":4305361489769004817,"outputs":{"2063776225603076451":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/home/brock/.rustup/toolchains/stable-x86_64-unknown-linux-gnu\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n","stderr":""},"17747080675513052775":{"success":true,"status":"","code":0,"stdout":"rustc 1.85.0 (4d91de4e4 2025-02-17)\nbinary: rustc\ncommit-hash: 4d91de4e48198da2e33413efdcd9cd2cc0c46688\ncommit-date: 2025-02-17\nhost: x86_64-unknown-linux-gnu\nrelease: 1.85.0\nLLVM version: 19.1.7\n","stderr":""},"13331785392996375709":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/home/brock/.rustup/toolchains/stable-x86_64-unknown-linux-gnu\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n","stderr":""}},"successes":{}}