Rustc: windows: How to specify dllexport for staticlib functions

I have this simple rust example code that exports a C symbol:

#[repr(C)]
pub struct Adder {
  pub number: i32
}

#[no_mangle]
pub fn adder_add(a: &Adder, number: i32) -> i32 {
    return a.number + number;
}

It is cross compiled for Windows by Meson (not cargo) using that command line:

[3/6] rustc --target x86_64-pc-windows-gnu -C linker=/usr/bin/x86_64-w64-mingw32-gcc --color=always -C debug-assertions=yes -C overflow-checks=no --crate-type staticlib -g --crate-name radder --emit dep-info=radder.d --emit link -o libradder.a ../adder.rs

That libradder.a static library is later linked into a normal C DLL which needs to expose adder_add symbol. When using that DLL I get the error undefined reference to __imp_adder_add'`. This is because my C code uses dllimport for that symbol, but rustc probably did not use dllexport.

Is there a way to explicitly tell to use dllexport in Rust code?

I think you need to declare the function as:
pub extern "C" fn adder_add(a: &Adder, number: i32) -> i32
to tell the compiler that you want this to actually be an exported symbol with the C calling convention (in addition to using #[no_mangle] to prevent name mangling); see extern - Rust

(but I haven't used Rust on Windows myself)

Tried that already, does not seems to make a difference unfortunately.

you need to check the linker options for that "C DLL". the rust code compiles to a static library, which is just an archive of object files, it has nothing to do with export.

the __imp_xxxx prefix is msvc specific. it is generated if you use the __declspec(dllimport) attributes. try get rid of it and use plain extern "C". but it still depends on how your "C DLL" is linked and might not work.

it'd be more helpful if you can share how the DLL is being built, and how the DLL is being used by executable.

For more context, that's from a Meson unit test that is currently skipped on Windows because if this issue: https://github.com/mesonbuild/meson/tree/master/test%20cases/rust/15%20polyglot%20sharedlib.

Complete command lines generated to compile that project:

[1/7] "cl" "-Iadder-1.dll.p" "-I." "-I.." "/MDd" "/nologo" "/showIncludes" "/utf-8" "/W2" "/Od" "/Zi" "-DBUILDING_ADDER" "/Fdadder-1.dll.p\adder.c.pdb" /Foadder-1.dll.p/adder.c.obj "/c" ../adder.c
[2/7] "cl" "-Iaddertest.exe.p" "-I." "-I.." "/MDd" "/nologo" "/showIncludes" "/utf-8" "/W2" "/Od" "/Zi" "/Fdaddertest.exe.p\addertest.c.pdb" /Foaddertest.exe.p/addertest.c.obj "/c" ../addertest.c
[3/7] "rustc" "-C" "linker=link" "--color=always" "--crate-type" "cdylib" "-g" "-C" "relocation-model=pic" "--crate-name" "radder" "--emit" "dep-info=radder.d" "--emit" "link" "-o" "radder.dll" ../adder.rs
[4/7] "C:\Python38\python.exe" "C:\Users\Collabora\xclaesse\meson\meson.py" "--internal" "symbolextractor" "C:\Users\Collabora\xclaesse\meson\test cases\rust\15 polyglot sharedlib\builddir" radder.dll "radder.dll.lib" radder.dll.p/radder.dll.symbols
[5/7] "link"  /MACHINE:x64 /OUT:adder-1.dll adder-1.dll.p/adder.c.obj "/nologo" "/release" "/nologo" "/DEBUG" "/PDB:adder-1.pdb" "/DLL" "/IMPLIB:adder.lib" "radder.dll.lib" "-Wl,-u,adder_add" "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "comdlg32.lib" "advapi32.lib"
LINK : warning LNK4044: unrecognized option '/Wl,-u,adder_add'; ignored
   Creating library adder.lib and object adder.exp
[6/7] "C:\Python38\python.exe" "C:\Users\Collabora\xclaesse\meson\meson.py" "--internal" "symbolextractor" "C:\Users\Collabora\xclaesse\meson\test cases\rust\15 polyglot sharedlib\builddir" adder-1.dll "adder.lib" adder-1.dll.p/adder-1.dll.symbols
[7/7] "link"  /MACHINE:x64 /OUT:addertest.exe addertest.exe.p/addertest.c.obj "/nologo" "/release" "/nologo" "/DEBUG" "/PDB:addertest.pdb" "adder.lib" "/SUBSYSTEM:CONSOLE" "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "comdlg32.lib" "advapi32.lib"
FAILED: addertest.exe addertest.pdb
"link"  /MACHINE:x64 /OUT:addertest.exe addertest.exe.p/addertest.c.obj "/nologo" "/release" "/nologo" "/DEBUG" "/PDB:addertest.pdb" "adder.lib" "/SUBSYSTEM:CONSOLE" "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "comdlg32.lib" "advapi32.lib"
addertest.c.obj : error LNK2019: unresolved external symbol __imp_adder_add referenced in function main
addertest.exe : fatal error LNK1120: 1 unresolved externals
ninja: build stopped: subcommand failed.

the __imp_xxxx prefix is msvc specific. it is generated if you use the __declspec(dllimport) attributes.

Removing dllimport makes it complain that adder_add symbol is missing. But it is not desired to remove dllimport AFAIK, usually a DLL would expose 2 symbols: adder_add and __impl_adder_add, the former calls the latter, using dllimport ensures that we call the latter to avoid that extra call redirection.

Wait... I did not notice that -Wl,-u,adder_add that is not supported by msvc... I think that's the issue actually!

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.