[Solved] Statically linking rust library yields undefined references

I have a library that's made up of quite a lot of C code and my goal is to migrate it to rust, piece by piece.
In order to start I wanted to create a static rust library, link it with my C library and migrate it piece by piece, however I'm getting unresolved references when trying to link even the most basic rust library.

The rust library contains the following code:

#[no_mangle]
pub extern fn hook() {
    println!("Hello rust!")
}

in the lib section of Cargo.toml I've added crate-type = ["staticlib"], and my target is x86_64-pc-windows-gnu, as my C library uses mingw.

The errors that I'm seeing seem to be WebSocket related and they originate in the static rust library (.a) as reported by ld during link phase:
/rustc/e1884a8e3c3e813aada8254edfa120e85bf5ffca/library\std\src\sys\windows/net.rs:50: undefined reference to `WSAGetLastError'

I have tried adding ws2_32 library to the build in C, but the error remains the same. I have tried finding some other solution to this, even adding a build.rs file to my project (outside src dir), adding it to package section like this: build = "build.rs" with the following contents:

fn main() {
    println!("cargo:rustc-link-lib=ws2_32");
}

but the error still persists. What must I do to resolve the undefined references?

Static libraries are not linked with anything. They're just an archive of unlinked object files. Linker directives don't apply to them. Every project that uses the static library will do linking itself, and has to add link-time dependencies itself. Static libraries can't provide that.

Your rustc-link-lib doesn't do anything, because the linker is not used at all when making a static library.

ok, so that means that the C artifact should be linking the ws2_32, is that correct? I have it to that target, however is makes no difference whether or not the library is present in target_link_libraries

Yes, final users of the static library need to be linking with ws2_32 and all other dependencies it needs. As a provider of the static library I don't think you can do any better than just documenting what is required.

thing is, as I've mentioned in the original post, I am linking the C program with the static library as well as ws2_32 (which is present in the target_link_libraries directive of CMAKE, and appears before my rust library) and I'm still getting the same errors

Just tried manually creating and using winsock objects, to make sure that the C project links to it properly, and it does in fact compile and work (as long as the rust static library is not included), meaning ws2_32 is linked correctly, but is for some reason not working when changing nothing but adding the static library to link

You can use cargo rustc -- --print native-static-libs to get a list of all libraries you need to link against. For example for an empty crate this is:

$ rustc --print native-static-libs --crate-type staticlib -
note: Link against the following native artifacts when linking against this static library. The order and any duplication can be significant on some platforms.

note: native-static-libs: -lgcc_s -lc -lm -lrt -lpthread -lutil -ldl -lutil

note: due to -Wl,--no-whole-archive being the default, no object files in a static lib are linked against unless they define symbols that are used by other object files. This also means that most of the time, you can omit some of the libraries rustc says you need to link against.

1 Like

Thanks, that helped! The output of the command was:

note: Link against the following native artifacts when linking against this static library. The order and any duplication can be significant on some platforms.

note: native-static-libs: -ladvapi32 -lws2_32 -luserenv

Which gave me the list of libraries that need to be used, however, what solved my issue was the first line, chainging the order; I was listing other libraries before the rust static library, moving these three after the static library makes it link successfuly.

So my cmake now looks something like:

target_link_libraries(target.dll user32 winhttp shlwapi version ${CMAKE_SOURCE_DIR}/rusty.a ws2_32 advapi32 userenv)
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.