26_rust_cargo、crates.io

发布时间 2023-11-10 00:53:50作者: 00lab

rust_cargo、crates.io

通过release profile自定义构建

release profile(发布配置):是预定义的,可自定义,可使用不用的配置,对代码编译拥有更多的控制。
每个profile的配置都独立于其它的profile。

cargo主要的两个profile:

  • dev profile:适用于开发,cargo build
  • release profile:适用于发布,cargo build -release

自定义profile

针对每个profile,cargo都提供了默认的配置,如果想自定义xxx profile配置,可在cargo.toml里添加[profile.xxx]区域,在里面覆盖默认配置的子集。

[profile.dev]
opt-level = 0 # 优化等级为0,O0优化

[profile.release]
opt-level = 3

对于每个配置的默认值和完整选项, 请参见: https://doc.rust-lang.org/cargo/

发布create到crates.io

crates.io是提供依赖库的,自己开发的crate也可通过发布包来共享代码。crate的注册表在https://crates.io/:
它会分发已注册的包的源代码,主要托管开源的代码。

创建并设置Crates.io账号

1)发布crate前,需在crates.io创建账号并获得API token,可用github账号登录,
2)运行命令:cargo login [你的API token],通知cargo,你的API token存储在本地~/.cargo/credentials
注:API token可在https://crates.io/进行撤销

为新的crate添加元数据

在发布crate前,需要在Cargo.toml的package]区域为crate添加一些元数据:

  • crate需要唯一的名称:name
  • description;一两句描述,后会出现在crate搜索的结果里
  • license:需提供许可标识值(可到http://spdx.org/licenses/ 查找),可指定多个license,用OR隔开
  • version
  • author

发布到Crates.io

然后发布:cargo publish命令
crate一旦发布,就是永久性的,该版本无法覆盖,代码无法删除,目的是依赖于该版本的项目可继续正常工作。

发布已存在的crate新版本

修改crate后,需要先修改Cargo.toml里的version值,再重新发布。参照http://semver.org/ 使用你的语义版本。再执行cargo publish命令发布。

使用cargo yank撤回版本

使用cargo yank从Crates.io撤回版本:

  • 不可删除crate之前的版本
  • 但可防止其它项目把它作为新的依赖,yank(撤回)一个crate版本后,可防止新项目依赖于该版本,已存在项目可继续使用和依赖(并可下载)
  • yank意味着所有已产生的Cargo.lock的项目都不会中断,任何将来生成的Cargo.lock文件都不会使用被yank的版本。
  • 命令:yank一个版本,不会删除任何代码,cargo yank --vers 1.0.1
  • 取消yank:cargo yank --vers 1.0.1 --undo

文档注释

在函数或方法前,添加文档注释,用于生成帮助文档:

  • 生成HTML文档
  • 显示公共API的文档注释,如何使用API
  • 使用///来注释
  • 支持Markdown语法
  • 放置在被说明条目之前

生成HTML文档的命令
cargo doc命令

  • 它会运行rustdoc工具(rust安装包时自带的工具)
  • 把生成的HTML文档放在target/doc目录下

cargo doc --open命令

  • 构建当前crate的文档(也包含crate依赖项的文档)
  • 并在浏览器中打开文档

例子:创建lib.rs文件,内容:

/// add function api
/// # Example
/// ```rust
/// let a = 5;
/// let b = 6;
/// let ret = hello_cargo::add_func(a, b);
/// assert_eq!(11, ret);
/// ```
pub fn add_func(a: i32, b: i32) -> i32 {
    a + b
}

执行cargo doc --open即可打开文档

常用章节
比如代码中的# Examples章节,其他常用章节:

  • Panics:函数可能发生panic的场景
  • Errors:如果函数返回Result,描述可能的错误种类,以及可导致错误的条件
  • Safety:如果函数处于unsafe调用,应解释函数unsafe的原因,以及调用者确保的使用前提

文档注释作为测试
示例代码块的附加值:运行cargo test的时候,会把文档注释中的示例代码作为测试来运行
如创建hello_cargo项目,创建src/lib.rs文件,内容:

/// add function api
/// # Example
/// ```
/// let a = 5;
/// let b = 6;
/// let ret = hello_cargo::add_func(a, b);
/// assert_eq!(11, ret);
/// ```
pub fn add_func(a: i32, b: i32) -> i32 {
    a + b
}

执行cargo test命令,打印:

   Doc-tests hello_cargo

running 1 test
test src\lib.rs - add_func (line 3) ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.32s

为包含注释的项添加文档注释
使用符号://!,这类注释通常用于描述crate和模块,crate root(按惯例src/lib.rs),或者一个模块内,将crate或模块作为一个整体进行记录。

//! # hello_cargo crate
//! 
//! `hello_cargo` is test crate
//! 
/// add function api
/// # Example
/// ```
/// let a = 5;
/// let b = 6;
/// let ret = hello_cargo::add_func(a, b);
/// assert_eq!(11, ret);
/// ```
pub fn add_func(a: i32, b: i32) -> i32 {
    a + b
}

再次执行cargo doc --open后,打开的文档最上方多出了内容:

hello_cargo crate
hello_cargo is test crate

pub use

使用pub use导出方便使用的公共API。
在实际项目中,会存在如下的问题:
crate的程序结构在开发时对于开发者很合理, 但对于它的使用者不够方便,开发者会把程序结构分为很多层,使用者想找到这种深层结构中的某个类型很费劲。
比如:开发的库中有定义my_crate:some_module::another_module:UsefulType这种层次关系,使用者要使用UsefulType就得访问很多层,而实际希望的使用方法是my_crate::UsefulType,能够直接使用。

解决办法: 不需要重新组织内部代码结构,使用pub use: 可以重新导出,创建一个与内部私有结构不同的对外公共结构。
比如例子hello_cargo:
main.rs内容:

use hello_cargo::modu1::EnumColor;
use hello_cargo::utils_modu::mix; // 使用者引入很深
fn main() {
    let r = EnumColor::Blue;
    mix(r);
}

lib.rs内容:

//! # test_crate
//! 
//! A test library
//! 
pub mod modu1 {
    /// test enum 1
    pub enum EnumColor {
        Red,
        Blue,
    }
    /// test enum 2
    pub enum Enum2 {
        Aaa,
        Bbb,
    }
}

pub mod utils_modu {
    use crate::modu1::*;
    /// a test function for pub use
    pub fn mix(c1: EnumColor) -> Enum2 {
        Enum2::Aaa
    }
}

使用cargo doc --open生成的文档如下图,也是比较深,不直观。只能看到两个muduler,点进去才能看到enum和函数。

Crate hello_cargoCopy item path
source · [−]
test_crate
A test library

Modules 只能看到两个muduler,点进去才能看到enum和函数
modu1
utils_modu

但将lib.rs改成如下导出模式:

//! # test_crate
//! 
//! A test library
//!

pub use self::modu1::EnumColor;
pub use self::modu1::Enum2;
pub use self::utils_modu::mix;

pub mod modu1 {
    /// test enum 1
    pub enum EnumColor {
        Red,
        Blue,
    }
    /// test enum 2
    pub enum Enum2 {
        Aaa,
        Bbb,
    }
}

pub mod utils_modu {
    use crate::modu1::*;
    /// a test function for pub use
    pub fn mix(c1: EnumColor) -> Enum2 {
        Enum2::Aaa
    }
}

再执行cargo doc --open,内容变成如下模式,用户能够直接看到导出的关键信息。

Crate hello_cargoCopy item path
source · [−]
test_crate
A test library

Re-exports
pub use self::modu1::EnumColor;
pub use self::modu1::Enum2;
pub use self::utils_modu::mix; 能直接看到函数接口
Modules
modu1
utils_modu

main.rs里的引入也可改成如下写法:

// use hello_cargo::modu1::EnumColor;
// use hello_cargo::utils_modu::mix; // 使用者引入很深
use hello_cargo::EnumColor;
use hello_cargo::mix; //直接引入
fn main() {
    let r = EnumColor::Blue;
    mix(r);
}