【问题标题】:Rust cdylib crate, linking dll to C program in WindowsRust cdylib crate,将 dll 链接到 Windows 中的 C 程序
【发布时间】:2021-06-08 08:06:24
【问题描述】:

我一直在尝试在 windows 中编译一个简单的 rustcdylib crate 并将其与一个简单的 c 程序链接。尽管我付出了所有努力,我还是无法链接dll 文件。

小例子

首先我的rustc版本是:

C:\Users\User> rustc --version
rustc 1.50.0 (cb75ad5db 2021-02-10)

我有一个基本的Cargo.toml,其中包括一个cbindgen,并设置了箱子类型:

[package]
name = "mycrate"
version = "0.1.0"
authors = ["PauMAVA <--REDACTED-->"]
edition = "2018"

[lib]
name = "mycrate"
crate-type = ["cdylib"]

[build-dependencies]
cbindgen = "0.18.0"

那么lib.rs 只声明了一个非常简单的 extern hello world 函数:

#[no_mangle]
pub extern "C" fn test_fn() {
    println!("Hello world from Rust!")
}

最后,我通过cdbindgenbuild.rs中生成头文件:

extern crate cbindgen;

use std::env;
use std::path::Path;
use cbindgen::{Config, Builder};

fn main() {
    let crate_env = env::var("CARGO_MANIFEST_DIR").unwrap();
    let crate_path = Path::new(&crate_env);
    let config = Config::from_root_or_default(crate_path);
    Builder::new().with_crate(crate_path.to_str().unwrap())
        .with_config(config)
        .generate()
        .expect("Cannot generate header file!")
        .write_to_file("testprogram/headers/mycrate.h");
}

生成的header如下:

/* Generated with cbindgen:0.18.0 */

#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

void test_fn(void);

我的 C 代码是以下简单程序:

#include <stdio.h>
#include "headers/mycrate.h"

int main() {
    printf("Hello world from C!\n");
    test_fn();
}

澄清一下,我的文件结构如下:

testprogram
|-- headers
|    |-- mycrate.h
|
|-- main.c
|-- mycrate.dll

当我尝试编译和链接时,我得到一个链接器错误:

C:\Users\User\...\testprogram> gcc .\main.c -L.\mycrate.dll -o .\main
c:/mingw/bin/../lib/gcc/mingw32/8.2.0/../../../../mingw32/bin/ld.exe: C:\Users\Pau\AppData\Local\Temp\cccQGbDk.o:main.c:(.text+0x1b): undefined reference to `test_fn'
collect2.exe: error: ld returned 1 exit status

其他信息

奇怪的是,在 WSL (Linux) 中编译时,我得到了一个 .so Linux 库,它只是正确链接:

$ gcc main.c -L./mycrate.so -o main
$ ./main
Hello world from C!
Hello world from Rust!

我在这里缺少什么?我想这只是一个链接问题,但我找不到它的来源。任何帮助表示赞赏!

编辑

我也尝试过在链接时使用绝对路径。 我目前正在使用MinGW

编辑 2

还尝试与 cargo 生成的包含库 mycrate.dll.lib 链接:

C:\Users\User\...\testprogram> gcc .\main.c -L.\mycrate.dll.lib -o .\main
c:/mingw/bin/../lib/gcc/mingw32/8.2.0/../../../../mingw32/bin/ld.exe: C:\Users\Pau\AppData\Local\Temp\ccL0sH7B.o:main.c:(.text+0x1b): undefined reference to `test_fn'
collect2.exe: error: ld returned 1 exit status

rustc --version --verbose 输出为:

C:\Users\User\...\testprogram> rustc --version --verbose
rustc 1.50.0 (cb75ad5db 2021-02-10)
binary: rustc
commit-hash: cb75ad5db02783e8b0222fee363c5f63f7e2cf5b
commit-date: 2021-02-10
host: x86_64-pc-windows-msvc
release: 1.50.0

【问题讨论】:

  • 命令不应该是gcc .\main.c -l.\mycrate.dll -o .\main吗? -L and -l are different
  • -l 试过,但我有同样的错误。如果我没记错的话-L 是指定库的路径,而-l 将在PATH 中搜索库。还尝试使用绝对路径但没有运气。
  • 你在 MinGW 或 MSVC 中使用 Rust 吗?
  • 我正在使用MinGW进行编译。
  • 在 Linux 上,程序直接与库链接(.so 文件在构建时和运行时都使用)。在 Windows 上,.dll 文件仅在运行时使用,您应该使用“导入库”(带有 .lib 扩展名)链接。

标签: c gcc rust


【解决方案1】:

我认为这里有多个问题。

  1. 您为 64 位系统编译库(因为 Rust 是 x86_64),但您尝试将其与 32 位系统链接 MinGW
  2. Rust 正在使用 MSVC 工具链,您尝试使用 MinGW 编译 C 程序
  3. 我对此并不完全确定,但我认为您错误地链接了mycrate.dll.lib。根据that answer,你应该在它前面加上l,就像这样:-L -lmycrate.dll.lib

显然有多种方法可以解决这个问题。例如,您可以安装 Rust,以便它使用 MinGW 工具链,如 here 所述。

或者您可以使用 Visual Studio 编译您的 C 代码。这就是我所做的,因为我不想费心重新安装 Rust(如果有错请纠正我,但我认为没有简单的方法来配置 MSVCMinGW 后端,以便可以轻松切换Rust 中的它们之间)。

VisualStudio 2019编译链接步骤如下:

  1. 使用 MSVC 使用 64 位 Rust 安装构建 Rust 项目 cargo build --release
  2. 创建一个新的Empty C++ 项目
  3. 添加main.c 并插入您的代码
  4. 在您的解决方案文件所在的同一目录中放置headers/mycrate.h
  5. mycrate.dllmycrate.dll.lib 复制到您的解决方案 文件所在的同一目录中
  6. 在 VisualStudio 中右键单击 C++ 项目并选择 Properties
  7. 选择Configuration=ReleasePlatform=x64
  8. $(SolutionDir)\headers; 添加到C/C++ -&gt; General -&gt; Additional Include Directories
  9. $(SolutionDir)mycrate.dll.lib; 添加到Linker -&gt; Input -&gt; Additional Dependencies
  10. 应用所有更改并关闭属性窗格
  11. 使用x64 平台以Release 模式构建项目

如果您在调试模式下构建 Rust 项目(例如 cargo build),您将必须对 Debug 模式执行相同的操作。

我知道这是一个复杂的过程,所以请告诉我是否应该制作 Repo 作为该过程的演示......

正如我所说,如果您想使用 MinGW 构建,则必须按照 here 的说明以不同方式设置 Rust。

【讨论】:

  • 非常感谢!像魅力一样工作。使用示例项目制作示例 repo,并在 README 中解释此过程会很棒,因为在文档中找不到此信息。再次感谢您的好评!
  • 很高兴你能成功。我认为在 Rust 方面没有记录的原因是因为有很多不同的构建系统并且它们都以不同的方式工作。让它工作需要一些 VS 特定的知识,但这实际上取决于您使用哪个平台与 rust 代码进行通信......然后您需要确保以兼容的方式编译 Rust 代码。
猜你喜欢
  • 1970-01-01
  • 2023-01-26
  • 2012-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-12
相关资源
最近更新 更多