I've been trying to get Rust to link with a C library on Windows, but Rust is unable to find the functions I need. It seems like my function signature is wrong, but Rust can find the .lib
file.
I narrowed it down to very simple C and Rust code, but still can't figure out how to get it to work:
test.c -- compiled with 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());
}
}
}
Alternatively 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);
}
}
}
This is the error message I get:
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"
Did you check to see that your .lib
file has any symbols / exported functions?:
> 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
This means that your .lib
file does not have any exported symbols. You might have thought to use __declspec(dllexport)
, but that does not seem to work for static .lib
files.
Visual Studio is a bit of a pain to work with, but here's how you get it working in VS 2015:
Fill in the details:
LIBRARY MyLib
EXPORTS
my_func @1
my_func2 @2
Right click on your project, click on properties, and make sure your project's configurations are correct:
Under Librarian, make sure you set the .def
file:
Build the .lib
file. If you did this correctly, running dumpbin
again should look something like this:
> 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
Copy the generated .lib
file (ensuring you do so from the correct directory; note that 64 bit and 32 bit compile to different folders) to your Rust project's root directory:
+ MyRustProject/
\
+ src/
+ Cargo.toml
+ MyLib.lib
Go back to the build configurations and build a .dll
:
Copy that .dll
in the same place as the .lib
Now when you build your Rust project, it should work. Note that you must build your VS project for the same platform as the Rust one, so, in my case, that meant x64, rather than x86.
For more information on .def
files, see Microsoft's official documentation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With