blog icon indicating copy to clipboard operation
blog copied to clipboard

Cargo

Open anjia opened this issue 6 years ago • 2 comments

概述

Cargo 做了4件事情:

  1. 引入两个包含项目的各种信息元数据文件
  2. 拉取、构建项目的依赖(默认从crates.io上拉)
  3. 构建项目,使用正确的参数调用rustc或其它构建工具
  4. 生成约定俗成的文件目录,以便轻松入门 Rust 项目
cargo new hello_test --bin  # --bin 意思是 binary,即二进制项目,比如库文件
cd hello_test
tree .

cargo build # 获取依赖及其子依赖,编译它们,更新 Cargo.lock
./target/debug/hello_test  # hello_test 是个二进制文件

cargo run # 和以上2条命令等价。会自动检测-如果已编译过&文件未改变,则就不重新编译了

cargo build --release  # 会放在文件夹 ./target/release 下

cargo check  # 快速(检查)编译,但不生成可执行文件

cargo update  # 更新所有依赖
cargo update -p rand # 仅更新"rand"依赖

eg.

  • Cargo.toml 描述项目的依赖
  • Cargo.lock 由Cargo自动生成,不用手动修改
    • 如果构建其它项目依赖的库,那可将Cargo.lock放在.gitignore
    • 如果构建一个可执行的应用程序或者命令行工具,记得把Cargo.lock放在git的版本仓库里

eg. 来自 crates.io

  • semver 语义的版本解析和比较
  • semver-parser 解析semver规范
  • rustc_version 查询已安装的rustc编译器版本
  • libc 类型和绑定到本地C函数的库,通常是在libc或其他通用平台的库中

eg. 生成的目录结构

  • Cargo.tomlCargo.lock在项目的根目录
  • src放源码
    • src/lib.rs 默认的库文件
    • src/main.rc 默认的可执行文件
    • src/bin/*.rs 其它的可执行文件
  • test
  • examples
  • benches

eg. 关于测试的

cargo test # 会寻找两个地方,每个`src`文件和`tests/`目录
cargo test foo  # 将会运行名字里带有foo的所有测试
# 更多见 https://doc.rust-lang.org/book/testing.html

命令“cargo test”运行测试用例,寻找两个地方的:

  • 每个src文件,单元测试
  • tests/目录下的,集成测试
    • 可以用 Travis CI,.travis.yml
    • 也可以用 GitLab CI,.gitlab-ci.yml

eg.构建缓存

  • 在单个工作区里,Cargo 会在诸多包之间共享构建工件
  • 在不同的工作区里,Cargo不共享
    • 若还想共享,则可以用第三方工具sccache

https://doc.rust-lang.org/cargo/guide/index.html

补充

  • 绝大多数 Rust 项目都使用 Cargo。当项目变大时,需要控制各个方面,单纯的rustc编译就不方便了
  • cargo 还有个好处,可以抹平不同操作系统的差异,都用一样的命令
cargo build  # 开发-快速构建
cargo build --realease  # 发布-快速运行

.toml, Tom's Obvious, Minimal Language, 作者是 Tom Preston-Werner toml

anjia avatar Aug 16 '18 05:08 anjia

依赖的来源

  1. crates.io
  2. git 仓库
  3. 覆盖依赖,eg.调试bug,临时覆盖依赖项的位置
  4. 覆盖仓库的url,eg.发布之前
  5. 本地文件夹,路径依赖,路径相对于Cargo.toml

eg.

[dependencies]
time = "0.1.12"
rand = { git = "https://github.com/rust-lang-nursery/rand" }

## 先把那个crate的仓库clone到本地。比如 uuid
[patch.crates-io]
uuid = { path = "../path/to/uuid" }

[patch."https://github.com/your/repository"]
my-library = { path = "../my-library/path" }
  • [patch.crates-io] 声明我们用新的依赖项修补源crates-io,这将把uuid添加到本项目的crates.io注册表中
  • 签出的>=之前指定的就行:本地签出的版本号很重要,将会影响是否使用patch(不定)
    • 运行cargo build则会看到file://... 说明则已经用了本地的副本了
    • 否则,需要运行cargo update -p uuid --precise $version $version是本地签出的版本

eg. 本地文件夹,用.cargo/config而不是Cargo.toml

paths = ["/path/to/uuid"]

版本指定

比如 ~ * >= <= = 等,符合 semver 要求,详见 Caret requirements

灵活适配

# 针对不同平台,[target.]
[target.'cfg(windows)'.dependencies]
winhttp = "0.4.0"

[target.'cfg(unix)'.dependencies]
openssl = "1.0.1"

[target.'cfg(target_arch = "x86")'.dependencies]
native = { path = "native/i686" }

[target.'cfg(target_arch = "x86_64")'.dependencies]
native = { path = "native/x86_64" }

[target.x86_64-pc-windows-gnu.dependencies]
winhttp = "0.4.0"

[target.i686-unknown-linux-gnu.dependencies]
openssl = "1.0.1"

# 开发依赖
[dev-dependencies]
tempdir = "0.3"

# 构建依赖
[build-dependencies]
cc = "1.0.3"

# 选择功能 [features],如果依赖的包提供条件功能
[dependencies.awesome]
version = "1.3.5"
default-features = false
features = ["secure-password", "civet"]

指定依赖项:https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html

anjia avatar Aug 16 '18 07:08 anjia

Manifest 格式

  • [package] 基本信息
    • build 根目录下的文件,构建项目的构建脚本。详见 Build Scripts
    • publish 可防止包被错误地发布到包注册表,比如 crates.io
    • workspace 配置 workspace。若没指定,则会向上找,直到找到第一个 Cargo.toml
  • [lib]
    • name 要生成的库名称
      • 所有的破折号-都会替换成下划线_
      • 必须是有效的 Rust 标识符,因为extern crate引用的就是它
    • path 即 crate 所在的位置,相对于 Cargo.toml
    • doctest 布尔值,是否启动文档测试
      • 仅适用于库,对其它部分(section)没影响
      • cargo test时,会用它
  • [features]
    • 条件编译选项,会用到cfg属性
    • 可选的依赖项

https://doc.rust-lang.org/cargo/reference/manifest.html

anjia avatar Aug 16 '18 10:08 anjia