分类

分类: rust

cargo sccache 缓存加速编译过程

默认情况下, cargo 在编译一个项目的第三方依赖时, 会缓存编译好的结果, 以便加速 之后编译速度.

但是, 对于跨工作区(workspace)的项目来说, 并不能很好地缓存这些第三方库编译后生成的 文件; 为此, mozilla 组织开发了 sccache 项目.

安装它也很简单, 分两步. 第一步在终端安装它:

$ cargo install sccache
阅读全文 "cargo sccache 缓存加速编译过程" »

Rust 语言受限的地方

最近半年陆续写了很多的 Rust 代码,跟别的语言相比,它有些地方还是蛮受限的,在表达 一个功能时需要各种弯弯绕,下面就列举几个方面的问题。

struct/union 不支持嵌套

类型嵌套可以将关联的数据结构放在一起,这个在C语言里是很常用的。像内核提供的系统 调用,比如 bpf() 以及 io_uring_setup(),都有大量的使用。它们都是定义了一堆的 操作指令(operation-code, op-code),以及一个公用的 union 联合体,跟据不同的 操作指令来解析 union 为不同的结构。尤其是 bpf() 系统调用,使用一个接口就实现了 内核 BPF 虚拟机的所有操作,相当的强大和复杂。

在使用Rust为类似这样的 C 接口做绑定时,会很麻烦。需要先将嵌套的结构体以及 union 联合体拆成独立的片段,然后再依次组装到一起,这样写的代码,其可读性并不好,也更难 维护。

阅读全文 "Rust 语言受限的地方" »

Rust 中检查是大端还是小端

在网络编程时,需要将 host byte order 转为 network byte order。 rust 本身支持在编译期检查当前的编译工具链是大端还是小端,如下所示:

pub fn is_little_endian() -> bool {
  cfg!(target_endian = "little")
}

当然,也有方法可以在运行期进行检查,这里我们使用 union 类型,为了方便。

pub fn is_little_endian() -> bool {
    union Check {
        l: u16,
        s: [u8; 2],
    }
    unsafe {
        let c = Check { l: 0x0102 };
        return c.s[0] == 2;
    }
}

但要注意的是直接访问 union 中的内部元素是 unsafe 的。

阅读全文 "Rust 中检查是大端还是小端" »

rust 中 string 与其它类型间的互转

Rust 中经常用到的字符串与其它数据类型之间的转换, 可以通过其它类型实现几个预定义的 Trait 来完成.

其中, 包括:

  • std::str::FromStr, 用于从字符串转为指定的类型, 提供了 parse() 方法
  • std::string::ToString, 用于将将指定的类型转为字符串, 提供了 to_string() 方法

在标准库中, 已经实现了基本数据类型(比如bool, i32, u64, f64等)与字符串之间的互转, 举例:

let i = "42".parse::<i32>();
assert_eq!(i, Ok(42));

以及:

let s = 3.14.to_string();
assert_eq!("3.14", s);

下面以 struct Color 为例, 说明一下如何为自定义的类型实现以上两个 Traits.

阅读全文 "rust 中 string 与其它类型间的互转" »

Rust cmp 数值比较模块中的PartialEq, PartialOrd

core::cmp.rs 模块里定义了用于两值之间比较的几个 trait, 分别是:

  • PartialEq
  • Eq
  • PartialOrd
  • Ord

这四个 trait 之间有这样一个关系:

  • Eq 基于 PartialEq, 即 pub trait Eq: PartialEq
  • PartialOrd 基于 PartialEq, 即 pub trait PartialOrd: PartialEq
  • Ord 基于 Eq 和 PartialOrd, pub trait PartialOrd: Eq + PartialOrd<Self>

同时还定义了比较结果 Ordering 这样一个枚举类型:

pub enum Ordering {
    Less = -1,
    Equal = 0,
    Greater = 1,
}
阅读全文 "Rust cmp 数值比较模块中的PartialEq, PartialOrd" »

Cargo 使用 build.rs 动态生成版本号

最近有个需求, 要在生成的可执行文件中包含一个版本号字段, 除了像 0.1.0 这样的 在 Cargo.toml 中定义的版本号之外, 最好还包含一下当前的 git commit id.

这个功能可以用 build.rs 脚本来实现. 大致做法也很简单:

  • 在 build.rs 中读取 Cargo.toml 里定义好的版本号, 以及当前的 git 历史, 并写入到编译目录里的一个文本文件
  • src/ 目录的源代码里, 定义一个字符串常量, 它的值在编译期指定的, 就是这个文件文件的内容
阅读全文 "Cargo 使用 build.rs 动态生成版本号" »

使用 musl 库静态编译 rust 程序

rust 提供了很简单的方式调用外部的 C 库, 但是它默认是以动态链接的方式链到外部库, 这增加了部署时的复杂性.

musl 是一个轻量级的 libc 库, 与 glibc 相比, 它的代码比较简洁, 体积也更小, 更方便 静态编译到程序中.

我们可以将 musl 以及第三方的 C 库静态链接到 rust 程序可执行文件中.

阅读全文 "使用 musl 库静态编译 rust 程序" »