I'm working with PROJ, a coordinate transformation library in C. Specifically, I'm working with proj_coord
, a function that constructions a coordinate represented as a union (source code).
Here's an example of usage in a C program:
#include <proj.h>
#include <stdio.h>
int main() {
PJ_COORD coord = proj_coord(1., 2., 3., 4.);
printf("%f %f %f %f", coord.v[0], coord.v[1], coord.v[2], coord.v[3]);
}
$ clang -lproj projcoord.c
$ ./a.out
1.000000 2.000000 3.000000 4.000000
Note that the compilation and execution above was done on my Macbook Air M1 ( aarch64-apple-darwin
).
In the GeoRust ecosystem, there is a proj-sys crate which is a bindgen-powered wrapper around the PROJ C library. And as expected, there is a function proj_sys::proj_coord
which maps to the C function above.
Here is (in theory) a Rust program equivalent to the previous C program:
fn main() {
unsafe {
let coord = proj_sys::proj_coord(1., 2., 3., 4.);
println!("{:#?}", coord.v);
}
}
This is where things get interesting! On x86_64-apple-darwin
, the code above correctly prints out [1.0, 2.0, 3.0, 4.0]
. On my Macbook Air M1, I get random floating point values upon every invocation:
You can try this out yourself by checking out and running cargo run
in this repository.
For reference, this is the Rust code that bindgen generates:
extern "C" {
pub fn proj_coord(x: f64, y: f64, z: f64, t: f64) -> PJ_COORD;
}
#[repr(C)]
#[derive(Copy, Clone)]
pub union PJ_COORD {
pub v: [f64; 4usize],
pub xyzt: PJ_XYZT,
pub uvwt: PJ_UVWT,
pub lpzt: PJ_LPZT,
pub geod: PJ_GEOD,
pub opk: PJ_OPK,
pub enu: PJ_ENU,
pub xyz: PJ_XYZ,
pub uvw: PJ_UVW,
pub lpz: PJ_LPZ,
pub xy: PJ_XY,
pub uv: PJ_UV,
pub lp: PJ_LP,
_bindgen_union_align: [u64; 4usize],
}
What could be going wrong here? Is something wrong with the proj-sys bindgen setup? Or maybe a problem with bindgen itself?
Here's the associated bug in the proj repository. Reaching out here to cast a wider net. Thanks!