我一直在尝试在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)中编译时,我得到了一个.so
Linux库,它只是正确链接:
$ 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
我认为这里有多个问题。
- 您为64位系统编译库(因为Rust是
x86_64
),但您试图将其与32位MinGW
链接 - Rust使用
MSVC
工具链,您尝试使用MinGW
编译C程序 - 我不完全确定,但我认为你把
mycrate.dll.lib
联系错了。根据这个答案,你应该在它前面加上l
,就像这样:-L -lmycrate.dll.lib
显然有多种方法可以解决这个问题。例如,您可以安装Rust,以便它使用MinGW
工具链,如下所述。
或者,您可以使用Visual Studio来编译C代码。这就是我所做的,因为我不想麻烦重新安装Rust(如果错误,请纠正我,但我认为没有简单的方法来配置MSVC
和MinGW
后端,这样就可以在Rust中轻松地在它们之间切换)。
编译和链接VisualStudio2019的步骤如下:
- 使用MSVC使用64位Rust安装构建Rust项目
cargo build --release
- 创建新的
Empty C++
项目 - 添加
main.c
并插入您的代码 - 在放置解决方案文件的同一目录中放入
headers/mycrate.h
- 将
mycrate.dll
和mycrate.dll.lib
复制到解决方案文件所在的同一目录中 - 右键单击VisualStudio中的C++项目,然后选择"属性">
- 选择
Configuration=Release
和Platform=x64
- 将
$(SolutionDir)headers;
添加到C/C++ -> General -> Additional Include Directories
- 将
$(SolutionDir)mycrate.dll.lib;
添加到Linker -> Input -> Additional Dependencies
- 应用所有更改并关闭属性窗格
- 使用
x64
平台以Release
模式构建项目
如果在调试模式(例如cargo build
)下构建Rust项目,则必须在Debug
模式下执行同样的操作。
我知道这是一个复杂的过程,所以让我知道我是否应该制作Repo,作为该过程的演示。。。
正如我所说,如果您喜欢使用MinGW
进行构建,则必须按照此处的说明以不同的方式设置Rust。