Rust cdylib机箱,将dll链接到Windows中的C程序



我一直在尝试在windows中编译一个简单的rustcdylib机箱,并将其与一个简单c程序链接。尽管我尽了全力,但还是没能链接到dll文件。

最小示例

首先,我的rustc版本是:

C:UsersUser> 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只声明了一个非常简单的外部hello-world函数:

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

最后,我在build.rs:中通过cdbindgen生成头文件

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");
}

生成的标题如下:

/* 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:UsersUser...testprogram> gcc .main.c -L.mycrate.dll -o .main
c:/mingw/bin/../lib/gcc/mingw32/8.2.0/../../../../mingw32/bin/ld.exe: C:UsersPauAppDataLocalTempcccQGbDk.o:main.c:(.text+0x1b): undefined reference to `test_fn'
collect2.exe: error: ld returned 1 exit status

附加信息

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

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

我在这里错过了什么?我想这只是一个链接问题,但我找不到它的来源。任何帮助都将不胜感激!

编辑

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

编辑2

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

C:UsersUser...testprogram> gcc .main.c -L.mycrate.dll.lib -o .main
c:/mingw/bin/../lib/gcc/mingw32/8.2.0/../../../../mingw32/bin/ld.exe: C:UsersPauAppDataLocalTempccL0sH7B.o:main.c:(.text+0x1b): undefined reference to `test_fn'
collect2.exe: error: ld returned 1 exit status

rustc --version --verbose输出为:

C:UsersUser...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

我认为这里有多个问题。

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

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

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

编译和链接VisualStudio2019的步骤如下:

  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++项目,然后选择"属性">
  7. 选择Configuration=ReleasePlatform=x64
  8. $(SolutionDir)headers;添加到C/C++ -> General -> Additional Include Directories
  9. $(SolutionDir)mycrate.dll.lib;添加到Linker -> Input -> Additional Dependencies
  10. 应用所有更改并关闭属性窗格
  11. 使用x64平台以Release模式构建项目

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

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

正如我所说,如果您喜欢使用MinGW进行构建,则必须按照此处的说明以不同的方式设置Rust。

最新更新