I have a project which is working perfectly fine when compiled with cross and segfaulting (or bus error) when compiled with zigbuild. It is always working with cross and always segfaulting (or bus error) with zigbuild. The target is aarch64-unknown-linux-gnu.
My project is using an external library (programmed in C++). I only have the header files and the *.so libraries.
I am using cxx to interface my rust code with the library.
Here is some (simplified) sample of what I have in my cpp file (for cxx) :
namespace whatever {
void my_callback(Something *p) {}
std::unique_ptr<ExternalClass> create_internal()
{
auto some_object = std::make_unique<ExternalClass>();
some_object->setCallBack(my_callback); // commenting this line => no segfault / no bus error
return some_object;
}
std::unique_ptr<MyClass> create()
{
auto some_object= std::make_unique<MyClass>();
return some_object;
}
class MyClass::impl {
friend MyClass;
std::unique_ptr<ExternalClass> some_object;
};
MyClass::MyClass(): impl(new class MyClass::impl) {
this->impl->some_object = create_internal();
}
}
ExternalClass is a class declared in the external lib.
in my header file:
namespace whatever {
class MyClass{
public :
MyClass();
private:
class impl;
std::shared_ptr<impl> impl;
};
std::unique_ptr<MyClass> create();
}
my rust code for cxx:
#[cxx::bridge(namespace = "whatever")]
pub(crate) mod ffi {
extern "Rust" {
fn some_function(id: u8);
}
unsafe extern "C++" {
include!("project/include/header.h");
type MyClass;
fn create() -> Result<UniquePtr<MyClass>>;
}
}
unsafe impl Send for ffi::MyClass{}
unsafe impl Sync for ffi::MyClass{}
And then, I am creating my object in my rust code using ffi::create() and putting it inside a OnceLock<> to use it from anywhere.
Not sure where to look. A lot of these stuff feels like black magic to me.
The included C/C++ header is parsed by a different compiler/compiler version, or with different #defines set, or different include path, than what the external library has been compiled with, which affects struct sizes or function argument types. When C/C++ code is linked, nothing checks that the ABI is compatible. It just connects the symbols and hopes for the best, and crashes if there was a mismatch between the .h interpretation and the .so/dylib/.a linked.
Unfortunately ABI issues are hard to debug. Sprinkle the path leading to the crashing code with printf("%z\n", sizeof(Type)) for every type involved and look for differences.
Are you perhaps mixing libc++ and libstdc++? Zig probably uses libc++ as standard library for C++ it builds, while most distros use libstdc++ as standard library. They are not ABI compatible.
I have no idea, I am just using the cargo cross command or the cargo zigbuild command.
So if under the hood they are using different and incompatible lib, that would be the reason of the crash.
If this is the case, is there a way to use libstdc++ with zigbuild?
To use stdlibc++, zig must be called with something like (command from the github issue): zig c++ base.cc $(pkg-config gtkmm-4.0 --cflags --libs) -o gtk_test /usr/lib/libstdc++.so /usr/lib/libgcc_s.so -I/usr/include/c++/13.2.1/x86_64-pc-linux-gnu -I/usr/include/c++/13.2.1 -nostdinc++ -nostdlib++ -L/usr/lib/gcc/x86_64-pc-linux-gnu/13.2.1 -lgcc
Now the question is: is there a possibility to gives zigbuild the rights flags to make it work ^^
Maybe with some "cargo::rustc-xxxxx" stuff. I have to investigate this.