From 0a65e85aaaf9817c4bc444147abe550c0f8c5b87 Mon Sep 17 00:00:00 2001 From: Mathew Verdouw Date: Thu, 5 Mar 2026 08:37:19 +1000 Subject: [PATCH 1/2] Fix aarch64 compatibility: use c_char instead of hardcoded i8 On aarch64 (ARM64/Graviton), c_char is u8 (unsigned), not i8 (signed) as on x86_64. All FFI buffers in safe.rs and lib.rs were hardcoded as [0i8; N], causing type mismatches when compiling for ARM targets. Replace every [0i8; N] with [0 as c_char; N] so the correct type is used regardless of target architecture. Also adds Meridian ('X') and Horizontal ('H') house system variants to the HouseSystem enum. Made-with: Cursor --- crates/swiss-eph/src/lib.rs | 4 ++-- crates/swiss-eph/src/safe.rs | 42 +++++++++++++++++++----------------- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/crates/swiss-eph/src/lib.rs b/crates/swiss-eph/src/lib.rs index a216e85..c1cf42d 100644 --- a/crates/swiss-eph/src/lib.rs +++ b/crates/swiss-eph/src/lib.rs @@ -707,10 +707,10 @@ mod tests { #[test] fn test_version() { unsafe { - let mut buf = [0i8; 256]; + let mut buf = [0 as c_char; 256]; swe_version(buf.as_mut_ptr()); // Version should start with a digit - assert!(buf[0] >= b'0' as i8 && buf[0] <= b'9' as i8); + assert!(buf[0] >= b'0' as c_char && buf[0] <= b'9' as c_char); } } } diff --git a/crates/swiss-eph/src/safe.rs b/crates/swiss-eph/src/safe.rs index 357a824..31281c5 100644 --- a/crates/swiss-eph/src/safe.rs +++ b/crates/swiss-eph/src/safe.rs @@ -4,7 +4,7 @@ use crate::*; use std::ffi::{CStr, CString}; -use std::os::raw::c_int; +use std::os::raw::{c_char, c_int}; /// Error returned by Swiss Ephemeris calculations #[derive(Debug, Clone)] @@ -223,6 +223,8 @@ pub enum HouseSystem { Morinus = b'M', Topocentric = b'T', Vehlow = b'V', + Meridian = b'X', + Horizontal = b'H', } impl HouseSystem { @@ -405,7 +407,7 @@ pub fn close() { /// Get Swiss Ephemeris version #[cfg_attr(target_arch = "wasm32", wasm_bindgen::prelude::wasm_bindgen)] pub fn version() -> String { - let mut buf = [0i8; 256]; + let mut buf = [0 as c_char; 256]; unsafe { swe_version(buf.as_mut_ptr()); CStr::from_ptr(buf.as_ptr()).to_string_lossy().into_owned() @@ -451,7 +453,7 @@ pub fn sidereal_time(jd_ut: f64) -> f64 { /// * `Err(SwissEphError)` - If calculation fails pub fn calc(jd: f64, planet: Planet, flags: CalcFlags) -> Result { let mut xx = [0.0f64; 6]; - let mut serr = [0i8; 256]; + let mut serr = [0 as c_char; 256]; let ret = unsafe { swe_calc(jd, planet.to_int(), flags.raw(), xx.as_mut_ptr(), serr.as_mut_ptr()) @@ -505,7 +507,7 @@ pub fn calc_ut(jd_ut: f64, planet: i32, flags: i32) -> std::result::Result std::result::Result Result<(String, Position)> { let mut xx = [0.0f64; 6]; - let mut serr = [0i8; 256]; - let mut star_buf = [0i8; 512]; + let mut serr = [0 as c_char; 256]; + let mut star_buf = [0 as c_char; 512]; let c_star = CString::new(star).map_err(|e| SwissEphError { message: format!("Invalid star name: {}", e), @@ -584,10 +586,10 @@ pub fn rise_trans( flags: RiseTransFlags, ) -> Result { let mut tret = 0.0f64; - let mut serr = [0i8; 256]; + let mut serr = [0 as c_char; 256]; let mut dgeo = [geopos.longitude, geopos.latitude, geopos.altitude]; - let mut star_buf = [0i8; 512]; + let mut star_buf = [0 as c_char; 512]; if let Some(name) = star_name { let c_star = CString::new(name).map_err(|e| SwissEphError { message: format!("Invalid star name: {}", e), @@ -638,7 +640,7 @@ pub fn rise_trans( pub fn solar_eclipse_where(jd: f64, flags: i32) -> Result<(f64, f64, f64, f64)> { let mut geopos = [0.0; 10]; let mut attr = [0.0; 20]; - let mut serr = [0i8; 256]; + let mut serr = [0 as c_char; 256]; let ret = unsafe { swe_sol_eclipse_where(jd, flags, geopos.as_mut_ptr(), attr.as_mut_ptr(), serr.as_mut_ptr()) @@ -663,7 +665,7 @@ pub fn solar_eclipse_when_loc( ) -> Result<(f64, EclipseAttributes)> { let mut tret = [0.0; 10]; let mut attr = [0.0; 20]; - let mut serr = [0i8; 256]; + let mut serr = [0 as c_char; 256]; let mut dgeo = [geopos.longitude, geopos.latitude, geopos.altitude]; let ret = unsafe { @@ -711,14 +713,14 @@ pub fn heliacal_event( flags: i32 ) -> Result { let mut dret = [0.0; 50]; - let mut serr = [0i8; 256]; + let mut serr = [0 as c_char; 256]; let mut dgeo = [geopos.longitude, geopos.latitude, geopos.altitude]; let mut datm_mut = datm; // pressure, temp, humid, vis_limit let mut dobs_mut = dobs; // age, snellen, etc let c_obj = CString::new(object).unwrap(); // Copy into mutable buffer as C API expects char* (though acts as const for name) - let mut obj_buf = [0i8; 256]; + let mut obj_buf = [0 as c_char; 256]; let bytes = c_obj.as_bytes_with_nul(); unsafe { std::ptr::copy_nonoverlapping(bytes.as_ptr(), obj_buf.as_mut_ptr() as *mut u8, bytes.len()); @@ -784,7 +786,7 @@ pub fn lunar_eclipse_when_loc( ) -> Result<(f64, EclipseAttributes)> { let mut tret = [0.0; 10]; let mut attr = [0.0; 20]; - let mut serr = [0i8; 256]; + let mut serr = [0 as c_char; 256]; let mut dgeo = [geopos.longitude, geopos.latitude, geopos.altitude]; let ret = unsafe { @@ -825,7 +827,7 @@ pub fn lunar_eclipse_when_loc( /// Returns (jd_et, jd_ut) pub fn utc_to_jd(year: i32, month: i32, day: i32, hour: i32, min: i32, sec: f64, gregflag: i32) -> Result<(f64, f64)> { let mut dret = [0.0; 2]; - let mut serr = [0i8; 256]; + let mut serr = [0 as c_char; 256]; let ret = unsafe { swe_utc_to_jd(year, month, day, hour, min, sec, gregflag, dret.as_mut_ptr(), serr.as_mut_ptr()) @@ -892,7 +894,7 @@ pub fn coordinate_transform(position: Position, obliquity: f64) -> Position { /// `hsys`: House system char (e.g. 'P' for Placidus) /// `xpin`: Body position [longitude, latitude] pub fn house_pos(armc: f64, geolat: f64, eps: f64, hsys: char, xpin: [f64; 2]) -> Result { - let mut serr = [0i8; 256]; + let mut serr = [0 as c_char; 256]; let mut xpin_mut = xpin; // copy array let ret = unsafe { @@ -930,10 +932,10 @@ pub fn gauquelin_sector( attemp: f64 ) -> Result { let mut dgsect = [0.0; 5]; - let mut serr = [0i8; 256]; + let mut serr = [0 as c_char; 256]; let mut geopos_arr = [geopos.longitude, geopos.latitude, geopos.altitude]; - let mut star_buf = [0i8; 256]; + let mut star_buf = [0 as c_char; 256]; if let Some(name) = star_name { let c_star = CString::new(name).map_err(|e| SwissEphError { message: format!("Invalid star name: {}", e), @@ -991,7 +993,7 @@ pub fn nodes_apsides(jd: f64, planet: Planet, flags: CalcFlags, method: i32) -> let mut xndsc = [0.0; 6]; let mut xperi = [0.0; 6]; let mut xaphe = [0.0; 6]; - let mut serr = [0i8; 256]; + let mut serr = [0 as c_char; 256]; let ret = unsafe { swe_nod_aps( @@ -1025,7 +1027,7 @@ pub fn nodes_apsides(jd: f64, planet: Planet, flags: CalcFlags, method: i32) -> /// Calculate planetary phenomena pub fn phenomena(jd: f64, planet: Planet, flags: CalcFlags) -> Result { let mut attr = [0.0; 20]; - let mut serr = [0i8; 256]; + let mut serr = [0 as c_char; 256]; let ret = unsafe { swe_pheno(jd, planet.to_int(), flags.raw(), attr.as_mut_ptr(), serr.as_mut_ptr()) @@ -1097,7 +1099,7 @@ pub fn houses(jd_ut: f64, latitude: f64, longitude: f64, system: HouseSystem) -> /// Get planet name pub fn get_planet_name(planet: Planet) -> String { - let mut buf = [0i8; 256]; + let mut buf = [0 as c_char; 256]; unsafe { swe_get_planet_name(planet.to_int(), buf.as_mut_ptr()); CStr::from_ptr(buf.as_ptr()).to_string_lossy().into_owned() From 294029fd72503d15a497eb89cb2049be8beb7595 Mon Sep 17 00:00:00 2001 From: Mathew Verdouw Date: Thu, 5 Mar 2026 09:04:23 +1000 Subject: [PATCH 2/2] Fix musl libc linker errors for cross-compilation When cross-compiling for musl targets (e.g. aarch64-unknown-linux-musl), the glibc cross-compiler injects _FORTIFY_SOURCE which replaces standard functions with fortified variants (__strcpy_chk, __sprintf_chk, etc.) that musl doesn't provide. Additionally, fseeko64/ftello64 are glibc-specific aliases not present in musl. Fix by disabling _FORTIFY_SOURCE and mapping fseeko64/ftello64 to their standard equivalents (fseeko/ftello) when the target contains "musl". musl uses 64-bit off_t by default so no precision is lost. Made-with: Cursor --- crates/swiss-eph/build.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/crates/swiss-eph/build.rs b/crates/swiss-eph/build.rs index 1c749a3..07b63b7 100644 --- a/crates/swiss-eph/build.rs +++ b/crates/swiss-eph/build.rs @@ -37,8 +37,19 @@ fn main() { .opt_level(3) .warnings(false); - // If targeting WASM, we need the WASI SDK (compiler + sysroot) for C compilation let target = std::env::var("TARGET").unwrap_or_default(); + + // musl libc doesn't provide glibc-specific fortified functions (__strcpy_chk, + // __sprintf_chk, __memcpy_chk) or the fseeko64/ftello64 aliases. + // Disable _FORTIFY_SOURCE and map 64-bit file ops to their standard equivalents + // (musl uses 64-bit off_t by default). + if target.contains("musl") { + build.define("_FORTIFY_SOURCE", "0"); + build.define("fseeko64", "fseeko"); + build.define("ftello64", "ftello"); + } + + // If targeting WASM, we need the WASI SDK (compiler + sysroot) for C compilation if target.contains("wasm32") { let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();