i am testing some C code in Rust, but rust only links to C static libraries on windows.
The problem is that the exported C functions are only exported to a Dynamic Library, and not to a Static one, since I can't use dlls in rust, i can't really link to the library with no exported symbols (if I try to, rust complains about unresolved references).
Some things I tried:
Normal linking: these worked for a compilation one time, but I lost it, and since all the other normal ones go wrong.
Static lib linked with Dynamic lib: sure, but it did not work, nor did the exported symbols appear in
dumpbin /exports
, or did the static lib rely on the dynamic lib.Static linked to Object linked to Dynamic: what
Code:
C:
// Note this is compiled with CMake to generate both a DyLib and a Static Lib.
#define EXPORT __declspec (dllexport)
EXPORT int my_func (void) {
return 3;
}
Rust:
// build.rs:
fn main () {
println!("cargo:rustc-link-search=native=path/to/my/lib");
}
// lib.rs:
#[cfg (test)]
mod tests;
// No *-sys crate for simplicity
pub mod sys {
#[link (name = "my_lib")] // since Windows msvc linking is based on static libs, no matter what it is going to search for a static lib anyway...
extern {
pub fn my_func () -> i32; // libc::c_int is an alias to i32 on my machine
}
}
// tests.rs:
use crate::sys;
#[test]
fn my_func_works () {
assert_eq!(3, unsafe { sys::my_func () });
}
CodePudding user response:
In your build script, you're telling cargo where to look for your library, but you never tell it to actually use the library. You need to add this to your build.rs
:
println!("cargo:rustc-link-lib=native=my_lib.lib");
Note that the cargo docs have this to say about rustc-link-search
(emphasis mine):
The
rustc-link-search
instruction tells Cargo to pass the-L
flag to the compiler to add a directory to the library search path.
and about rustc-link-lib
:
The
rustc-link-lib
instruction tells Cargo to link the given library using the compiler's-l
flag.
CodePudding user response:
It is way out of scope for this answer, but this is why attributes and declspecs are such an anathema to making software work.
If you have a library; that library has some names
which have a global scope. For example, you could have a procedure called ShaveMyBall
for grooming a football pre-game. In a library, ShaveMyBall
might just exist, but you might have some requirements about linking with externals, so that ShaveMyBall
might need to be prefixed with MyHairyBits_
.
This opposing requirements can readily be solved by symbol manipulation utiities rather than a grotesque infrastructure between programming languages. A few simple object file manipulations can change ShaveMyBall
into MyHairyBits_ShaveMyBall
.
But, if you insist on using odd, poorly defined, and even worse, partially defined by a standards committe, you will end up with something that may work on occasion, which outside of setting you up for a microsoft buyout, is typically the death knell for any company.