dtolnay / cxx

Safe interop between Rust and C++
https://cxx.rs
Apache License 2.0
5.82k stars 330 forks source link

Compiling cdylib #1331

Open smvoss opened 6 months ago

smvoss commented 6 months ago

Hi,

I am attempting to compile my rust / c++ project into a single .so file that can be dynamically loaded by another application (implementation of a c++ headerfile that uses some rust calls, linked from a c++ app). This seems to generally work when using a static library with only needing to link the top-level library:

-Ltarget/debug -lmylib

(assuming target/debug/libmylib.a)

however when attempting to do the same for a cdylib I need to also link the library created during the build script as such:

-Ltarget/debug -lmylib ${OUT_DIR}/lib-built-by-cxxbuild.a

(assuming targ/debug/libmylib.so)

If I do not explicitly include the static library built as part of build.rs (cxx_build::[..].compile("built-by-cxxbuiild")) I have missing symbols.

Any advice on how to bridge this gap, so that all symbols are exported in the .so. I have attempted to add some linking flags to my build script, such as println!("cargo::rustc-link-lib=static={..}) to no avail.

If it makes a difference, the code exclusively calls from c++ to rust, and not the other way. This is being used as a C++ "shim" to provide a rust implementation of a c++ interface for a shared library.

Thanks!

jwhear commented 5 months ago

I was tinkering with this myself today. My workaround solution at the moment is to build the rust code as a static library. Here's my setup (crate name is sqlite_adaptor).

// Cargo.toml
[lib]
crate-type = ["staticlib"]

This produces target/debug/sqlite_adaptor.a

The next step is to link this static library with the cxxbridge static library built by your build.rs into a shared library:

// Makefile
debug: target/debug/libsqlite_adaptor.so
bridge = $(shell find target/debug/ -name libcppbridge.a)

target/debug/libsqlite_adaptor.so:
    gcc -shared -Wl,--whole-archive target/debug/libsqlite_adaptor.a \
        -Wl,--no-whole-archive $(bridge) \
        -o target/debug/libsqlite_adaptor.so

This is pretty janky right now as I'm still hacking on it, but it produces a shared library with the symbols from Rust library and the needed bridge code in target/debug/libsqlite_adaptor.so

tusooa commented 1 month ago

Having the same issue here. If I set crate-type = cdylib then I will have missing symbols when linking to the dynamic library.

downstream: https://iron.lily-is.land/T128

smvoss commented 1 month ago

I ended up basically doing the exact same thing, doing it as a staticlib and then adding an extra stage in a top-level Makefile that really just converts it to a shared object. It's very awkward and I wish it didn't have to be done that way, but it seems like with the current tooling that's what has to be done.

I tested every rustc / cargo option I could find on this and nothing changed the behavior at all, so an extra toolchain on top pretty much is the solution at this point.

BaxHugh commented 1 month ago

Just to add, that I also have this issue and would love a solution.