class: center, middle ### Rust's Package Manager #Cargo ### 2016/5/18 ### Shing Lyu <shing.lyu@gmail.com> ??? top, middle, bottom left, center, right --- class: center, middle #What is Cargo? --- ### Cargo * Help you manage your project * Create * Dependencies * Build * Run * Test * Help shape a common workflow --- ### Why External Dependencies? * Don't reinvent the wheel * Prevent strong coupling * Create a healthy community --- ### Dependency Management Nightmare * Discovery * Re-build * Cross-platform build * Debug build v.s. release build * Upstream change * Updating/Upgrading dependency --- class: center, middle # Predictability --- ### Solutions * "`vendor`"ing: copy everything * Package manager * `apt-get` * `npm` * `pip` * `cargo` --- ###crates.io  --- ### Crates and Modules * Crate == library, package * Crate contains modules * Module can contain submodules * .footnote[ref: https://doc.rust-lang.org/book/crates-and-modules.html] --- ### Pillars of Cargo * Predictable build, test, and run across environment and time * Invisible indirect dependencies * Shared workflow for the Rust ecosystem --- class: center, middle # Workflow --- ### Workflow * `cargo new [--bin]` * `cargo build [--release]` * `cargo run` * `cargo test` * `cargo bench` * `cargo update` * `cargo publish` * `cargo install` --- class: center, middle # Predictability --- class: middle ### Predictability * If I can successfully build today, I should be able to compile on any machine/environment _with the same source code_ later --- ### Cargo's solution for predictability * `Cargo.lock` * Controls the whole workflow * Controls global configurations like `--debug`/`--release`, static/dynamic linking --- ### `cargo new` * `--bin`: binary program, `main.rs` * `(no arg)`: library, `lib.rs` ``` . ├── Cargo.toml ├── .git ├── .gitignore └── src └── lib.rs OR main.rs ``` --- ### Cargo.toml ``` [package] name = "datetime" version = "0.1.0" authors = ["Shing Lyu
"] [dependencies] time = "0.1.35" ``` --- ### Build * Build artifacts are in `target/debug/` * `--release` => `target/release/` ``` % cargo build Updating registry `https://github.com/rust-lang/crates.io-index` Downloading winapi v0.2.7 Downloading libc v0.2.11 Downloading kernel32-sys v0.2.2 Downloading time v0.1.35 Compiling winapi-build v0.1.1 Compiling winapi v0.2.7 Compiling libc v0.2.11 Compiling kernel32-sys v0.2.2 Compiling time v0.1.35 Compiling datetime v0.1.0 (file:///home/shinglyu/Dropbox/0.work/talks/cargo/demo/datetime) ``` --- ### Cargo.lock * Exact snapshot of the whole dependency tree * Do NOT check into VCS if building a library * Check into VCS is building a binary * Common dependencies can be shared --- ### Cargo.lock example ``` % cat Cargo.lock [root] name = "datetime" version = "0.1.0" dependencies = [ "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "kernel32-sys" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] ``` --- ### Cargo.lock example (cont'd) ``` [[package]] name = "libc" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "time" version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] ``` --- ### Cargo.lock example (cont'd) ``` [[package]] name = "winapi" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi-build" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" ``` --- ### Reuse ``` % cargo build --verbose Fresh winapi v0.2.7 Fresh libc v0.2.11 Fresh winapi-build v0.1.1 Fresh kernel32-sys v0.2.2 Fresh time v0.1.35 Fresh datetime v0.1.0 (file:///home/shinglyu/Dropbox/0.work/talks/cargo/demo/datetime) ``` --- ### Git/Local dependencies * Git ``` [dependencies] color = { git = "https://github.com/bjz/color-rs.git" } ``` * Local, in `.cargo/config` ``` path = ["/path/to/local/color-rs"] ``` --- ### Run * Run (build + run) ``` cargo run ``` * Examples ``` cargo run --example
``` --- ### Testing * Write test with `#[test]` decorator ``` #[test] fn test_ok() { assert!("3" == add(1,1)); } ``` * `cargo test` ``` running 1 test test test_now ... FAILED ... test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured ``` --- ### Benchmarking * Need nightly ``` #[bench] fn bench_add_two(b: &mut Bencher) { b.iter(|| add_two(2)); } ``` * `cargo bench` ``` test tests::bench_add_two ... bench: 1 ns/iter (+/- 0) ``` * .footnote[ref: https://doc.rust-lang.org/book/benchmark-tests.html] --- ### Documentation .float-right-half[] * `cargo doc` * Write doc using `///`. * In `target/doc/` --- ### Optimization Level * `cargo build`: debug mode (`target/debug/`) * `cargo build --release`: release mode (`target/release/`) * All dependencies are built in the same mode * `cargo bench` implies release mode --- ### Static and Dynamic Linking * Pure-Rust dependencies are statically linked * System dependencies (e.g. `libc`, `libm`) are dynamically linked. ``` % ldd target/debug/examples/date libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f7369095000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f7368d8f000) ... ``` * You can override the behavior using [build scripts](http://doc.crates.io/build-script.html) --- ### Not covered * Updating dependencies * Path dependencies * Publish to crates.io ??? * TODO: extern crate and use http://stackoverflow.com/questions/29403920/whats-the-difference-between-use-and-extern --- ### Reference * [Cargo: predictable dependency management](http://blog.rust-lang.org/2016/05/05/cargo-pillars.html) * [crates.io](https://crates.io/) --- class: center, middle # Thank You ### Questions?