mirror of
https://github.com/RustyCab/LearnRustEasy.git
synced 2026-11-05 23:08:36 +08:00
Update chapter_3_22_1.md
This commit is contained in:
@@ -37,4 +37,108 @@ fn main() {
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
|
- 构建脚本的生命周期
|
||||||
|
|
||||||
|
在项目构建之前,Cargo会将build.rs编译成可执行文件,然后执行。在执行过程中,脚本可以使用println的方式跟Cargo进行通信,通信内容的格式为:cargo:真正的内容。示例如下:
|
||||||
|
```Rust
|
||||||
|
// build.rs
|
||||||
|
fn main() {
|
||||||
|
println!("cargo:rustc-link-search=/usr/local/lib/");
|
||||||
|
println!("cargo:rustc-link-lib=dylib=pcre2-8");
|
||||||
|
println!("cargo:rerun-if-changed=src/lib.rs");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- 构建脚本的输入
|
||||||
|
|
||||||
|
可以通过环境变量、文件等方式给构建脚本提供一些输入。
|
||||||
|
|
||||||
|
- 构建脚本的输出
|
||||||
|
|
||||||
|
如果构建脚本生成文件,可以指定该文件的输入目录,可以通过设置OUT_DIR环境变量来指定。构建脚本的输出通常是用来告诉Cargo一些信息,以下几个为常用的Cargo能识别的通信指令:
|
||||||
|
- cargo:rerun-if-changed=PATH — 当指定路径的文件发生变化时,Cargo会重新运行脚本;
|
||||||
|
- cargo:rerun-if-env-changed=VAR — 当指定的环境变量发生变化时,Cargo会重新运行脚本;
|
||||||
|
- cargo:rustc-link-lib=[KIND=]NAME — 告诉Cargo通过-l去链接一个指定的库,常用于FFI;
|
||||||
|
- cargo:rustc-link-search=[KIND=]PATH — 告诉Cargo通过-L将一个目录添加到依赖库搜索路径中;
|
||||||
|
- cargo:rustc-env=VAR=VALUE — 设置一个环境变量。
|
||||||
|
|
||||||
|
- 构建脚本的依赖
|
||||||
|
|
||||||
|
构建脚本也可以引入其它基于Cargo的依赖包,依赖方式为在Cargo.toml中添加依赖包,示例如下:
|
||||||
|
```TOML
|
||||||
|
# Cargo.toml
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
cc = "1.0.46" # 可以在build.rs中使用cc相关的功能
|
||||||
|
```
|
||||||
|
|
||||||
可以看到有一个foo.txt文件,该文件就是在build.rs中生成的。
|
可以看到有一个foo.txt文件,该文件就是在build.rs中生成的。
|
||||||
|
|
||||||
|
## 2. 在Rust中调用C代码
|
||||||
|
在Rust中调用c的代码需要使用extern关键字来定义外部函数接口,即用extern块把c提供的函数接口进行封装。
|
||||||
|
|
||||||
|
下面的示例展示如何在Rust中使用c代码,整个项目的目录结构如下:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
c目录中的pass.c为c代码,源码如下:
|
||||||
|
```Rust
|
||||||
|
// c/pass.c
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
void set_err(char *message) { // 提供一个打印错误信息的函数
|
||||||
|
printf("err: %s\n", message);
|
||||||
|
}
|
||||||
|
src目录中为Rust代码,源码如下:
|
||||||
|
// ==================
|
||||||
|
// 封装c函数
|
||||||
|
extern "C" { // 在Rust中调用c的代码需要使用extern关键字,定义外部函数接口,
|
||||||
|
// 实际上就是: 用extern块将c提供的函数接口封装下
|
||||||
|
fn set_err(message: *const libc::c_char);
|
||||||
|
}
|
||||||
|
// ==================
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let err = "some error".to_string();
|
||||||
|
let c_err = std::ffi::CString::new(err).expect("error");
|
||||||
|
unsafe { // 需要unsafe块
|
||||||
|
set_err(c_err.as_ptr()); // 调用封装的c函数
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
build.rs中的内容如下:
|
||||||
|
|
||||||
|
```Rust
|
||||||
|
// build.rs
|
||||||
|
fn main() {
|
||||||
|
// 以下代码告诉 Cargo ,`c/pass.c`发生改变,就重新运行当前的构建脚本
|
||||||
|
println!("cargo:rerun-if-changed=src/hello.c");
|
||||||
|
|
||||||
|
// 使用 `cc` 来构建一个 C 文件,然后进行静态链接
|
||||||
|
cc::Build::new()
|
||||||
|
.file("c/pass.c")
|
||||||
|
.compile("pass");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Cargo.toml中的内容如下:
|
||||||
|
```TOML
|
||||||
|
[package]
|
||||||
|
name = "use-c"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
[build-dependencies]
|
||||||
|
cc = "1.0.46" # build.rs中依赖cc,所以此处需要添加
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
libc = "0.2.139" # src/main.rs中使用了libc这个库
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user