Rust 代码不能 link 编译在 Windows 上的 C 库,因为有一个未解析的外部符号
Rust code cannot link with a C library compiled on Windows because there is an unresolved external symbol
我一直在尝试通过 Windows 上的 C 库使 Rust 达到 link,但 Rust 无法找到我需要的函数。看起来我的函数签名是错误的,但是 Rust 可以找到 .lib
文件。
我将它缩小到非常简单的 C 和 Rust 代码,但仍然无法弄清楚如何让它工作:
test.c -- 用 Visual Studio 2015
编译
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdint.h>
typedef struct MyStruct {
int32_t i;
} MyStruct;
MyStruct my_func(const MyStruct *s) {
MyStruct result;
result.i = s->i + 1;
return result;
}
int32_t my_func2() {
return 42;
}
#ifdef __cplusplus
}
#endif
lib.rs
extern crate libc;
use libc::int32_t;
#[link(name = "MyLib")]
extern {
pub fn my_func2() -> int32_t;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
unsafe {
assert_eq!(42, my_func2());
}
}
}
或者lib.rs:
extern crate libc;
use libc::int32_t;
#[repr(C)]
pub struct MyStruct {
i: int32_t
}
#[link(name = "MyLib")]
extern {
pub fn my_func(s: *mut MyStruct) -> MyStruct;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
unsafe {
let mut s = MyStruct{ i: 10 };
let s = my_func(&mut s as *mut MyStruct);
assert_eq!(11, s.i);
}
}
}
这是我收到的错误消息:
Compiling test v0.1.0
error: linking with `link.exe` failed: exit code: 1120
|
// snip (but the MyLib.lib is in here)
= note: test-01aaa83d15a1dde3.0.o : error LNK2019: unresolved external symbol my_func referenced in function _ZN8test5tests8it_works17h52c29448f9d86a1aE
C:\<--omitted-->-01aaa83d15a1dde3.exe : fatal error LNK1120: 1 unresolved externals
error: aborting due to previous error
error: Could not compile `test`.
Cargo.toml
[package]
name = "test"
version = "0.1.0"
authors = ["<-- omitted -->"]
[dependencies]
libc = "0.2.17"
您是否检查过您的 .lib
文件是否有任何符号/导出函数?:
> dumpbin /exports /symbols MyLib.lib
Microsoft (R) COFF/PE Dumper Version 14.00.24215.1
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file MyLib.lib
File Type: LIBRARY
这意味着您的 .lib
文件没有任何导出的符号。您可能想过使用 __declspec(dllexport)
,但这似乎不适用于静态 .lib
文件。
Visual Studio 使用起来有点麻烦,但这是在 VS 2015 中使用它的方法:
- 新建 "Module-Definition File" (.def)
填写详细信息:
LIBRARY MyLib
EXPORTS
my_func @1
my_func2 @2
右键单击您的项目,单击属性,并确保您的项目配置正确:
在 Librarian 下,确保设置 .def
文件:
构建 .lib
文件。如果你这样做正确,运行 dumpbin
应该看起来像这样:
> dumpbin /exports /symbols MyLib.lib
Microsoft (R) COFF/PE Dumper Version 14.00.24215.1
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file MyLib.lib
File Type: LIBRARY
COFF SYMBOL TABLE
000 01015E97 ABS notype Static | @comp.id
001 00000000 SECT2 notype External | __IMPORT_DESCRIPTOR_MyLib
002 C0000040 SECT2 notype Section | .idata
003 00000000 SECT3 notype Static | .idata
004 C0000040 UNDEF notype Section | .idata
005 C0000040 UNDEF notype Section | .idata
006 00000000 UNDEF notype External | __NULL_IMPORT_DESCRIPTOR
007 00000000 UNDEF notype External | MyLib_NULL_THUNK_DATA
String Table Size = 0x5C bytes
COFF SYMBOL TABLE
000 01015E97 ABS notype Static | @comp.id
001 00000000 SECT2 notype External | __NULL_IMPORT_DESCRIPTOR
String Table Size = 0x1D bytes
COFF SYMBOL TABLE
000 01015E97 ABS notype Static | @comp.id
001 00000000 SECT2 notype External | MyLib_NULL_THUNK_DATA
String Table Size = 0x22 bytes
Exports
ordinal name
1 my_func
2 my_func2
Summary
D2 .debug$S
14 .idata
14 .idata
8 .idata
8 .idata
12 .idata
复制生成的 .lib
文件(确保你从正确的目录这样做;注意 64 位和 32 位编译到不同的文件夹)到你的 Rust 项目的根目录:
+ MyRustProject/
\
+ src/
+ Cargo.toml
+ MyLib.lib
返回构建配置并构建一个 .dll
:
将 .dll
复制到与 .lib
相同的位置
现在,当您构建 Rust 项目时,它应该可以工作了。请注意,您必须为与 Rust 相同的平台构建 VS 项目,因此,在我的例子中,这意味着 x64,而不是 x86。
有关 .def
个文件的详细信息,请参阅 Microsoft's official documentation.
我一直在尝试通过 Windows 上的 C 库使 Rust 达到 link,但 Rust 无法找到我需要的函数。看起来我的函数签名是错误的,但是 Rust 可以找到 .lib
文件。
我将它缩小到非常简单的 C 和 Rust 代码,但仍然无法弄清楚如何让它工作:
test.c -- 用 Visual Studio 2015
编译#ifdef __cplusplus
extern "C"
{
#endif
#include <stdint.h>
typedef struct MyStruct {
int32_t i;
} MyStruct;
MyStruct my_func(const MyStruct *s) {
MyStruct result;
result.i = s->i + 1;
return result;
}
int32_t my_func2() {
return 42;
}
#ifdef __cplusplus
}
#endif
lib.rs
extern crate libc;
use libc::int32_t;
#[link(name = "MyLib")]
extern {
pub fn my_func2() -> int32_t;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
unsafe {
assert_eq!(42, my_func2());
}
}
}
或者lib.rs:
extern crate libc;
use libc::int32_t;
#[repr(C)]
pub struct MyStruct {
i: int32_t
}
#[link(name = "MyLib")]
extern {
pub fn my_func(s: *mut MyStruct) -> MyStruct;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
unsafe {
let mut s = MyStruct{ i: 10 };
let s = my_func(&mut s as *mut MyStruct);
assert_eq!(11, s.i);
}
}
}
这是我收到的错误消息:
Compiling test v0.1.0
error: linking with `link.exe` failed: exit code: 1120
|
// snip (but the MyLib.lib is in here)
= note: test-01aaa83d15a1dde3.0.o : error LNK2019: unresolved external symbol my_func referenced in function _ZN8test5tests8it_works17h52c29448f9d86a1aE
C:\<--omitted-->-01aaa83d15a1dde3.exe : fatal error LNK1120: 1 unresolved externals
error: aborting due to previous error
error: Could not compile `test`.
Cargo.toml
[package]
name = "test"
version = "0.1.0"
authors = ["<-- omitted -->"]
[dependencies]
libc = "0.2.17"
您是否检查过您的 .lib
文件是否有任何符号/导出函数?:
> dumpbin /exports /symbols MyLib.lib
Microsoft (R) COFF/PE Dumper Version 14.00.24215.1
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file MyLib.lib
File Type: LIBRARY
这意味着您的 .lib
文件没有任何导出的符号。您可能想过使用 __declspec(dllexport)
,但这似乎不适用于静态 .lib
文件。
Visual Studio 使用起来有点麻烦,但这是在 VS 2015 中使用它的方法:
- 新建 "Module-Definition File" (.def)
填写详细信息:
LIBRARY MyLib EXPORTS my_func @1 my_func2 @2
右键单击您的项目,单击属性,并确保您的项目配置正确:
在 Librarian 下,确保设置
.def
文件:构建
.lib
文件。如果你这样做正确,运行dumpbin
应该看起来像这样:> dumpbin /exports /symbols MyLib.lib Microsoft (R) COFF/PE Dumper Version 14.00.24215.1 Copyright (C) Microsoft Corporation. All rights reserved. Dump of file MyLib.lib File Type: LIBRARY COFF SYMBOL TABLE 000 01015E97 ABS notype Static | @comp.id 001 00000000 SECT2 notype External | __IMPORT_DESCRIPTOR_MyLib 002 C0000040 SECT2 notype Section | .idata 003 00000000 SECT3 notype Static | .idata 004 C0000040 UNDEF notype Section | .idata 005 C0000040 UNDEF notype Section | .idata 006 00000000 UNDEF notype External | __NULL_IMPORT_DESCRIPTOR 007 00000000 UNDEF notype External | MyLib_NULL_THUNK_DATA String Table Size = 0x5C bytes COFF SYMBOL TABLE 000 01015E97 ABS notype Static | @comp.id 001 00000000 SECT2 notype External | __NULL_IMPORT_DESCRIPTOR String Table Size = 0x1D bytes COFF SYMBOL TABLE 000 01015E97 ABS notype Static | @comp.id 001 00000000 SECT2 notype External | MyLib_NULL_THUNK_DATA String Table Size = 0x22 bytes Exports ordinal name 1 my_func 2 my_func2 Summary D2 .debug$S 14 .idata 14 .idata 8 .idata 8 .idata 12 .idata
复制生成的
.lib
文件(确保你从正确的目录这样做;注意 64 位和 32 位编译到不同的文件夹)到你的 Rust 项目的根目录:+ MyRustProject/ \ + src/ + Cargo.toml + MyLib.lib
返回构建配置并构建一个
.dll
:将
.dll
复制到与.lib
相同的位置
现在,当您构建 Rust 项目时,它应该可以工作了。请注意,您必须为与 Rust 相同的平台构建 VS 项目,因此,在我的例子中,这意味着 x64,而不是 x86。
有关 .def
个文件的详细信息,请参阅 Microsoft's official documentation.