Functions returning structs do not work
Structs defined in c++, such as b2Vec2 seem to cause many problems when they are passed over the FFI by-value. I think the reason is different calling conventions for C vs C++. It seems like functions returning structs as-value or taking structs as input argument as-value cause problems. Take Body::world_point() as example, it does not work and return undefined data or some times crash. (All other demos from the testbed work because they never use any such function).
It is implemented as follows:
pub fn world_point(&self, local: &Vec2) -> Vec2 {
unsafe { ffi::Body_get_world_point(self.ptr(), local) }
}
b2Vec2 Body_get_world_point(const b2Body* self, const b2Vec2* local) {
return self->GetWorldPoint(*local);
}
Here the argument "local" will point to garbage no matter how you call the funcition and the program crashes. This is because the return value is a b2Vec2 as-value and b2Vec2 is compiled as struct/class by c++ code while the function Body_get_world_point is treated as C-code.
@meerik Thanks for the detailed issue,
convention issues between C and C++ would surprise me since I'm using extern "C" so I would at least expect a warning if the result is not C compatible. Although I don't know the details and there may be no checks at all, so it is very possible, are you confident in your explanation ?
This code works fine for me, I guess it doesn't work for you ?
use wrapped2d::b2;
use wrapped2d::user_data::NoUserData;
#[test]
fn get_world_point() {
let gravity = b2::Vec2 { x: 0., y: -10. };
let mut world = b2::World::<NoUserData>::new(&gravity);
let mut ground_body_def = b2::BodyDef::new();
ground_body_def.position = b2::Vec2 { x: 0., y: -10. };
let ground_handle = world.create_body(&ground_body_def);
{
let mut ground = world.body_mut(ground_handle);
let ground_box = b2::PolygonShape::new_box(50., 10.);
ground.create_fast_fixture(&ground_box, 0.);
assert_eq!(ground.world_point(&b2::Vec2 { x: 5., y: 0. }),
b2::Vec2 { x: 5., y: -10. });
}
}
> rustc --print cfg
debug_assertions
target_arch="x86_64"
target_endian="little"
target_env="gnu"
target_family="unix"
target_feature="sse"
target_feature="sse2"
target_has_atomic="16"
target_has_atomic="32"
target_has_atomic="64"
target_has_atomic="8"
target_has_atomic="ptr"
target_os="linux"
target_pointer_width="64"
target_thread_local
target_vendor="unknown"
unix
Thank you for the quick reply. Your test works on Ubuntu with GCC but not on Windows with MSVC.
---- tests::get_world_point stdout ----
thread 'tests::get_world_point' panicked at 'assertion failed: `(left == right)` (left: `Vec2 { x: -0.00000000000000029138696, y: 0.000000000000000000000000000000000000000000912 }`, right: `Vec2 { x: 5, y: -10 }`)', src\lib.rs:22
rustc --print cfg
target_os="windows"
target_family="windows"
target_arch="x86_64"
target_endian="little"
target_pointer_width="64"
target_env="msvc"
windows
debug_assertions
Maybe the problem comes from the use of gcc in build_frontend ?
This may be a case of https://github.com/rust-lang/rfcs/issues/1342, especially since it specifically does not work on Windows.
@retep998 Thanks for the info!
I've seen this too in VS 2015, msvc toolchain.
Quite a few other related issues too. 1) stdc++ cannot be linked in MSVC 2) no luck with 64 bit build, link.exe laments a 32/64 bit mismatch with one of the deps. I'll investigate and post separate issues.
stdc++ cannot be linked in MSVC
Statically linking together MSVC and MinGW code is not supported at all whatsoever and will almost always break.
Yep, I am building with the MSVC toolchain, but rust_box2d causes the linker to attempt to include stdc++ anyway.
Hmmm, it uses the gcc crate to build things, and that should know how to handle MSVC just fine. I'll investigate more later perhaps.
This may have something to do with it (in lib.rs)
#[link(name = "stdc++")] extern "C" {}
EDIT: removing the line above from lib.rs actually fixes the problem in MSVC - I haven't tried other toolchains/platforms though. That may require a #[cfg(...)] annotation for other platforms.
I'll move to another thread though, I've hijacked this enough :)
@norru Since this uses the gcc crate to handle building and linking the C++, that automatically handles linking the C++ standard library. https://github.com/alexcrichton/gcc-rs/blob/master/src/lib.rs#L950-L963 So definitely removing that #[link(name = "stdc++")] is the right thing to do.
For information, the latter has been done.