Rust 代码无法与 Windows 上编译的 C 库链接,因为存在未解析的外部符号

Jus*_*tin 6 linker compiler-errors ffi visual-studio rust

我一直在尝试让 Rust 与 Windows 上的 C 库链接,但 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
Run Code Online (Sandbox Code Playgroud)

库文件

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());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

或者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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我收到的错误消息:

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());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Cargo.toml

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Jus*_*tin 7

您是否检查过您的.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
Run Code Online (Sandbox Code Playgroud)

这意味着您的.lib文件没有任何导出的符号。您可能想过使用__declspec(dllexport),但这似乎不适用于静态.lib文件。

使用 Visual Studio 有点麻烦,但在 VS 2015 中使用它的方法如下:

  1. 创建一个新的“模块定义文件”(.def)
  2. 填写详细信息:

    LIBRARY MyLib
    EXPORTS
        my_func  @1
        my_func2 @2
    
    Run Code Online (Sandbox Code Playgroud)
  3. 右键单击您的项目,单击属性,并确保您的项目配置正确:

    配置类型:静态库(.lib)

  4. 在 Librarian 下,确保设置文件.def

    模块定义文件名:test.def

  5. 构建.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$2
    003 00000000 SECT3  notype       Static       | .idata$6
    004 C0000040 UNDEF  notype       Section      | .idata$4
    005 C0000040 UNDEF  notype       Section      | .idata$5
    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$2
              14 .idata$3
               8 .idata$4
               8 .idata$5
              12 .idata$6
    
    Run Code Online (Sandbox Code Playgroud)
  6. 将生成的.lib文件(确保从正确的目录执行此操作;请注意,64 位和 32 位编译到不同的文件夹)复制到 Rust 项目的根目录:

    + MyRustProject/
     \
      + src/
      + Cargo.toml
      + MyLib.lib
    
    Run Code Online (Sandbox Code Playgroud)
  7. 返回构建配置并构建.dll

    配置类型:动态库 (.dll)

  8. 将其复制.dll到与.lib

现在,当您构建 Rust 项目时,它应该可以工作。请注意,您必须为与 Rust 相同的平台构建 VS 项目,因此,就我而言,这意味着 x64,而不是 x86。

有关.def文件的更多信息,请参阅微软的官方文档。

  • 嗯,那很痛苦......我希望有人能提出一种简化这个 oO 的方法 (2认同)