使用MSVC编译的静态库链接问题

6
我正在尝试在Windows上链接一个简单的C库与Rust库。我的库是.h文件。
extern "C" {
    void say_hello(const char* s);
}

.cpp

#include <stdio.h>

void say_hello(const char* s) {
    printf("hello world");
}

我的Rust文件

#[link(name="CDbax", kind="static")]
extern "C" {
    fn say_hello(s: *const libc::c_char) -> () ;
}

连接失败,因为其中一个数据符号出现错误。
error: linking with `gcc` failed: exit code: 1
note: "gcc" "-Wl,--enable-long-section-names" "-fno-use-linker-plugin" "-Wl,--nxcompat" "-Wl,--large-address-aware" "-shared-libgcc" "-L" "C:\Program Files (x86)\Rust 1.2\bin\rustlib\i686-pc-windows-gnu\lib" "e:\Rust\DBTools\DBAnalytics\target\debug\DBAnalytics.o" "-o" "e:\Rust\DBTools\DBAnalytics\target\debug\DBAnalytics.dll" "e:\Rust\DBTools\DBAnalytics\target\debug\DBAnalytics.metadata.o" "C:\Program Files (x86)\Rust 1.2\bin\rustlib\i686-pc-windows-gnu\lib\libstd-11582ce5.rlib" "C:\Program Files (x86)\Rust 1.2\bin\rustlib\i686-pc-windows-gnu\lib\libcollections-11582ce5.rlib" "C:\Program Files (x86)\Rust 1.2\bin\rustlib\i686-pc-windows-gnu\lib\librustc_unicode-11582ce5.rlib" "C:\Program Files (x86)\Rust 1.2\bin\rustlib\i686-pc-windows-gnu\lib\librand-11582ce5.rlib" "C:\Program Files (x86)\Rust 1.2\bin\rustlib\i686-pc-windows-gnu\lib\liballoc-11582ce5.rlib" "C:\Program Files (x86)\Rust 1.2\bin\rustlib\i686-pc-windows-gnu\lib\liblibc-11582ce5.rlib" "C:\Program Files (x86)\Rust 1.2\bin\rustlib\i686-pc-windows-gnu\lib\libcore-11582ce5.rlib" "-L" "e:\Rust\DBTools\DBAnalytics\target\debug" "-L" "e:\Rust\DBTools\DBAnalytics\target\debug\deps" "-L" "C:\Program Files (x86)\Rust 1.2\bin\rustlib\i686-pc-windows-gnu\lib" "-L" "e:\Rust\DBTools\DBAnalytics\.rust\bin\i686-pc-windows-gnu" "-L" "e:\Rust\DBTools\DBAnalytics\bin\i686-pc-windows-gnu" "-Wl,-Bstatic" "-Wl,--whole-archive" "-l" "CDbax" "-Wl,--no-whole-archive" "-Wl,-Bdynamic" "-l" "ws2_32" "-l" "userenv" "-l" "advapi32" "-shared" "-l" "compiler-rt"
note: Warning: corrupt .drectve at end of def file
Cannot export ??_C@_0M@LACCCNMM@hello?5world?$AA@: symbol not found

该库是使用MSVC2013作为简单静态库构建的。字符串“hello world”位于数据段中,因此我不会期望它引起链接错误。在Windows上链接C库时,是否有一些特定的设置需要注意?顺便说一下,这是32位MSVC库。

如果您尝试使用GCC构建dll怎么办? - Paolo M
Rust几天前获得了MSVC支持,但我认为还没有任何MSVC-nightlies,并且我不知道这种支持有多远。您可以尝试通过使用./configure --target x86_64-pc-windows-msvc来构建自己的mvsc-rustc,让我们知道它的效果如何!相关PR:https://github.com/rust-lang/rust/pull/25848 - oli_obk
1个回答

10

首先,"静态DLL"这种东西是不存在的:DLL是一个动态链接库。

其次,Rust使用MinGW工具链和运行时。混用MSVC和MinGW运行时可能会导致奇怪的问题,所以最好尽可能避免。Rust最近才刚刚支持使用MSVC运行时进行构建。

然而,你可以让这个特定的例子正常工作,而且似乎没有任何不良影响。只需要改变一些东西:

  • 你需要使用一个动态库;据我了解,这样可以使坏的交互减少一些。
  • 你需要实际使用C链接,而不是C++链接来编译say_hello。你在头文件中做到了这一点,但在源文件中没有。
  • 你需要从库中公开导出say_hello

因此:

hello.rs

#[link(name="hello", kind="dylib")]
extern {
    fn say_hello();
}

fn main() {
    unsafe { say_hello(); }
}

hello.h:

#ifndef HELLO_H
#define HELLO_H

extern "C" {
    __declspec(dllexport) void say_hello();
}

#endif

hello.cpp:

#include <cstdio>

#include "hello.h"

void say_hello() {
    printf("hello world\n");
}

build.cmd

cl /LD hello.cpp
rustc -L. hello.rs

在我的电脑上,这将生成hello.exehello.dll;运行时,hello.exe将输出hello world


我指的是静态库,而不是动态链接库。 遗憾的是,我们的“公司”库都是使用MSVC编写的,所以我不能改变它们。我会尝试上面的方法。 - Delta_Fore
2
@Ronnie,如果你指的是静态库而不是DLL,你应该更新你的问题以反映这一点。目前它多次说明它是一个DLL。 - Vladimir Matveev
完美地运作。谢谢你,你是我的英雄。搜索工作表明需要类似FFI、libloaderapi或winapi之类的库,但完整的代码示例并未出现。有了您的答案,使用 Rust 中的 Windows .dll 变得轻而易举,并得到了核心支持。 - MichaelsonBritt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接