在 Rust 中创建你的第一个 DLL
作为一种具有与 C 和 C++ 类似链接支持的系统编程语言,在 Rust 中构建 DLL 相当简单。然而,Rust 有其自己的库概念,这与 C 和 C++ 的库概念大相径庭,因此这只是找到正确配置以生成所需输出的问题。
与大多数 Rust 项目一样,你可以从 Cargo 开始并获得一个基本模板,但它非常简单,我们这里将手动构建它,以了解其中涉及的内容。让我们创建如下目录结构:
> hello_world
Cargo.toml
> src
lib.rs
只有两个目录和两个文件。有一个 hello_world
目录,其中包含整个项目。在该目录中,我们有一个 Cargo.toml
文件,其中包含项目或包的元数据,以及编译包所需的信息。
[package]
name = "hello_world"
edition = "2021"
[lib]
crate-type = ["cdylib"]
至少,[package]
部分包含包的名称和编译所用的 Rust 版本。
纯 Rust 库通常不包含 [lib]
部分。当你需要专门控制项目如何使用和链接时,这是必需的。在这种情况下,我们使用“cdylib”,它表示一个动态系统库,在 Windows 上映射到 DLL。
src
子目录包含 lib.rs
Rust 源文件,我们可以在其中添加希望从 DLL 导出的任何函数。这是一个简单的例子:
#[no_mangle]
extern "system" fn HelloWorld() -> i32 {
123
}
[no_mangle]
属性只是告诉编译器禁用任何名称混淆,并使用函数名称作为导出的标识符。extern "system"
函数限定符表示函数所需的 ABI 或调用约定。“system”字符串表示系统特定的调用约定,在 Windows 上通常映射到“stdcall”。
就是这样!你现在可以构建包,它将生成一个 DLL。
> cargo build -p hello_world
Cargo 会将生成的二进制文件放到目标目录中,你可以在其中从任何其他编程语言中使用它们。
> dir /b target\debug\hello_world.*
hello_world.d
hello_world.dll
hello_world.dll.exp
hello_world.dll.lib
hello_world.pdb
这是一个简单的 C++ 示例:
#include <stdint.h>
#include <stdio.h>
extern "C" {
int32_t __stdcall HelloWorld();
}
int main() {
printf("%d\n", HelloWorld());
}
你可以使用 MSVC 如下构建:
cl hello_world.cpp hello_world.dll.lib
可以使用 dumpbin 工具进一步检查导入和导出。
> dumpbin /nologo /exports hello_world.dll
Dump of file hello_world.dll
File Type: DLL
Section contains the following exports for hello_world.dll
00000000 characteristics
FFFFFFFF time date stamp
0.00 version
1 ordinal base
1 number of functions
1 number of names
ordinal hint RVA name
1 0 00001000 HelloWorld = HelloWorld
> dumpbin /nologo /imports hello_world.exe
Dump of file hello_world.exe
File Type: EXECUTABLE IMAGE
Section contains the following imports:
hello_world.dll
140017258 Import Address Table
140021200 Import Name Table
0 time date stamp
0 Index of first forwarder reference
0 HelloWorld