-
Notifications
You must be signed in to change notification settings - Fork 365
Can't build a working DLL with cargo on Windows #1153
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I have found why println!("cargo:rustc-link-arg=/WHOLEARCHIVE:cxx_msvc_shared.lib"); That gets the Typically these attributes would be defined using a preprocessor command like this: #if defined(_MSC_VER)
# define CXX_DLL_EXPORT __declspec(dllexport)
#else
# define CXX_DLL_EXPORT
#endif If you want to generate the same code for static libs and DLLs you might want to include some other test in there to allow switching between static and DLL mode at compile time rather than generate time. It is also customary to have that My adjusted build.rs looked like this: use std::fs::{read_to_string, write};
const PATH: &str = "C:/Work/experiments/cxx_msvc_shared/target/debug/build/cxx_msvc_shared-9083c676d5a1ba67/out/cxxbridge/sources/cxx_msvc_shared/src/lib.rs.cc";
fn main() {
let mut build = cxx_build::bridge("src/lib.rs");
let cc = read_to_string(PATH).unwrap().replace(
"::std::int32_t add",
"__declspec(dllexport) ::std::int32_t add",
);
write(PATH, cc).unwrap();
build
.flag_if_supported("-std=c++17")
.compile("cxx_msvc_shared");
println!("cargo:rerun-if-changed=src/lib.rs");
println!("cargo:rustc-link-arg=/WHOLEARCHIVE:cxx_msvc_shared.lib");
} |
Trying these same workarounds on slightly more real code, I also found missing symbols with names like I would lean toward putting templates like |
Any news on this topic? I'm facing similar issue with static library on windows. |
Building the Rust FFI C-ABI generated Cpp wrappers in the client application seem to work out for me so far. Documented in great detail here See include_directories(${RUST_TARGET}/cxxbridge/my-cxx/src)
add_executable(my-examples-cpp src/main.cpp ${RUST_TARGET}/cxxbridge/my-cxx/src/lib.rs.cc) |
What I'm trying to do is use CXX and cargo in "cdylib" mode to build my Rust code into a shared library (DLL) that exports the API defined by the
extern "Rust"
block in my Rust code.My Rust code in
lib.rs
looks like this:And my
build.rs
looks like this:All simple and obvious and it compiles correctly. The generated C++ code for the
add
function look like this:So I can see that the base function comes from my Rust code and there is a wrapper defined in the C++ to do the error handling. That all look good.
Then I tried to use this DLL in some C++ code and it failed to link. It turns out that
cxx_msvc_shared::add
is not exported from the DLL, and neither isrust::cxxbridge1::Error::what
. Looking at it withdumpbin.exe
these are the exports that match\badd\b
:That is the the function from the Rust code but where is the C++ wrapper function?
The problem here is that the Windows linker
link.exe
does not export symbols by default. You need to either add the symbols to a*.def
file and pass that (what Rust itself does AFAICT but it deletes that file after compiling), pass each symbol individually with/export:name
, or add__declspec(dllexport)
before the function in the C++ code. CXX does none of those things so the symbols don't get exported and the DLL is unusable.To fix this I first tried to add those
__declspec(dllexport)
attributes to the C++ code after it is generated. I did this with code inbuild.rs
that ran aftercxx_build::bridge
is called but before callingcompile
on the build object. I'm pretty sure I got the right file (C:/Work/experiments/cxx_msvc_shared/target/debug/build/cxx_msvc_shared-9083c676d5a1ba67/out/cxxbridge/sources/cxx_msvc_shared/src/lib.rs.cc
) and I can see the modifications in there but the symbols still don't get exported. I have not been able to work out why. This was the contents ofbuild.rs
with these changes:The second thing I tried was passing extra flags to the linker for each symbol, by adding these lines to my
build.rs
instead:This worked! The problem is that finding the correct names for each symbol and pasting them in here isn't really practical. These two new lines appear in the
dumpbin.exe
output, and these are the functions I'm looking for:So I think the fix is for CXX to either add the
__declspec(dllexport)
attributes to all the functions it generates or output the right mangled names itself as exported symbols from thebuild
function. Ideally the attributes would work; I don't know why they didn't work when I put them in myself. Any ideas?I have also attached my whole test project here, with the hack in
build.rs
to make it work:cxx_msvc_shared.tar.gz
The text was updated successfully, but these errors were encountered: