I have an external C++ library I need to use. Unfortunately the library is provided as C++ header and compiled dynamic library.
Since rust does not have C++ FFI, and this library uses C++ virtual class as interface, I need to write a C gluing layer so that Rust can call into the gluing layer, and then the gluing layer can call into the C++ library.
Although we can use build.rs to build C/C++ source as library to use, and also link specifier at extern C funtion for linking to C/C++ source. I can't find a way to specify linkage the C/C++ source to the provided C++ dynamic library.
To make it concrete, say we have a foo.so and foo.hpp as external C++ library with function foo, and we wrote an gluing layer of bar.hpp and bar.cpp with function C function bar. bar will call foo, and our rust program will call bar through FFI. How can we build the bar.a from bar.cpp and have function bar link to the C++ library?
I'm not sure if I understand your question correctly, but I'd rather load the library dynamically (dlopen) and create an object based on the virtual class from C++, so I can call the needed methods on it.
Some similar tasks I'd once to do on Windows. There I've used LoadLibrary instead of "dlopen" to load the DLL but the strategy is basically the same on Linux: you load the library file at runtime and instantiate objects and/or execute functions as you like. Of course, instantiating objects would be only possible if there are some methods in the target library that instantiate them.
But, this is only a hint from my side, to keep you away from writing too much (unneeded?) glue code.
You want to write C glue layer to bridge Rust and C++, then why you still use bar.hpp and bar.cpp?
I think you should write bar.h and bar.c which wrap procedures in foo.so, and then compile bar.c and bar.h to generate C static or dynamic library, say bar.a or bar.so. And finally you just link to bar.a or bar.so with your Rust project doing normal FFI.
Hope this can help you
To build a static library (.a) from C++ source (.cpp), you need a C++ compiler. The details depend on the OS, but there's nothing Rust-specific about this part. If you're on Linux, AFAIK you'll need to instruct rustc to link both your .a and the third-party .so into the final binary, because static libraries don't include information about what dynamic libraries' symbols they're referencing - or else compile your C++ code into a .so rather than a .a, in which case you'd reference the existing .so when linking your .so, with the usual -l, and the Rust file would mention only your .so. In both cases, you would use the #[link(name = "xxx")] attribute to tell rustc what to link.
(Or you could ask rustc to product object or static library files and do the linking manually, etc. - it's much the same as a C/C++ compiler, with the difference that if it is asked to link an executable or dynamic library itself, the set of libraries to link into it is determined from the .rs files rather than -l command line arguments.)
Also note that if you are not already doing so, you can use bindgen to generate bindings from C-compatible .h files rather than doing it manually, although this is not required. This is separate from linking.
Thanks comex. I am having hard time to find some source for #[link] usage? All I can find is FFI code samples, where #[link] only prefixes function declarations. How do I specify with #[link] or with rustc command-line to let linker find unresolved symbols in my static library in the shared library I provide?
I'm not sure whether bar.hpp is ok with rust. But to link library you either place bar.so in target/debug directory manually and hard-code #[link(name="bar")] in your rust code or write a build.rs file to instruct cargo how to compile c/cpp files and how to link libraries and then run cargo build will automatically compile c/cpp files and link libraries to rust