1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
//! Raw FFI bindings to `libempyrean`, the C shared library for empyrean's
//! astrodynamics engine.
//!
//! Prefer the safe wrapper crate [`empyrean`](https://docs.rs/empyrean)
//! unless you need direct access to the C ABI.
//!
//! # How `libempyrean` is loaded
//!
//! The library is opened at run time with [`libloading`] — there is **no**
//! link-time native dependency and no `install_name_tool` / `patchelf` / rpath /
//! `LD_LIBRARY_PATH` setup. Its path is resolved on first use, in order:
//!
//! 1. `EMPYREAN_LIB` — an explicit path to the library, passed straight to
//! `dlopen` (override / offline use / a locally built engine). A bare name
//! defers to the OS loader search; pass a full path for an exact file.
//! 2. A `libempyrean.{dylib,so}` sitting next to the **currently loaded module**
//! — the `.so`/`.dylib`/executable that statically links this crate — located
//! via `dladdr`. This makes prebuilt, relocatable artifacts self-contained:
//! a Python wheel can bundle the engine beside its extension and it is found
//! with no build-machine path baked in.
//! 3. The absolute path recorded at build time (`LIB_PATH`): a sibling
//! `../target/release` build, an `EMPYREAN_LIB_DIR` override, or a
//! version-matched, checksum-pinned prebuilt downloaded (in pure Rust — no
//! `curl`/`tar`) into `~/.cache/empyrean`. This covers `cargo add empyrean`,
//! where the build script runs on the consumer's own machine.
//!
//! The bindings are pre-generated and committed, so building needs no C header
//! and no `libclang` / `bindgen`. Callers use the free `empyrean_*` functions
//! exactly as with a statically linked library; each delegates to the loaded
//! [`EmpyreanLib`].
// The generated dynamic-loading methods call the loaded fn pointers directly in
// their (unsafe) bodies; this is generated FFI, so allow the 2024 granularity lint.
// The generated bindings and the free-function shims are `pub unsafe fn`s without
// per-function `# Safety` sections, and mirror the C ABI's wide argument lists;
// they are generated FFI, not hand-authored API.
use ;
use OnceLock;
// Dynamic-loading bindings: `struct EmpyreanLib` + per-function methods + the
// shared type/const definitions.
include!;
// Absolute path to libempyrean recorded by the build script — resolution
// fallback #3 (see the module docs).
include!;
static LIB: = new;
/// Platform file name of the engine library.
const LIB_FILENAME: &str = if cfg! else if cfg! else ;
// A data symbol whose address lands in *this* module, so `dladdr` reports the
// shared object / executable that statically links empyrean-sys.
static SELF_MARKER: u8 = 0;
/// Directory of the currently loaded module — the `.so`/`.dylib`/executable that
/// links this crate — via `dladdr`. `None` if it cannot be determined.
/// Resolve the engine library path at run time (see the module docs for the
/// full resolution order).
/// The loaded `libempyrean`, opened lazily on first use.
///
/// Panics if the library cannot be opened, or if the library that opened is
/// built to a different [`EMPYREAN_ABI_VERSION`] than this crate. The path is
/// resolved from the host environment and the build, so a failure here means a
/// broken or incomplete install (e.g. a prebuilt artifact missing its bundled
/// engine, or a stale `libempyrean` picked up from `EMPYREAN_LIB` or a leftover
/// `target/release`) — surfaced loudly rather than papered over.
///
/// # The version handshake
///
/// `dlsym` matches on symbol **name** only, so a mismatched engine resolves
/// every symbol and then reads the caller's arguments through the wrong
/// signature. The check is an equality: [`EMPYREAN_ABI_VERSION`] carries
/// the distribution release that built this crate and advances with every
/// release, so a different value is a different release and nothing about
/// the layouts behind the shared names can be assumed.
///
/// The damage a tolerated mismatch does has grown with the ABI. Under the
/// retired counter, up to its version 2, it could only ever produce wrong
/// values, because every bump appended struct fields; version 3 changed the
/// parameter lists of `empyrean_transform_coordinates` and
/// `empyrean_get_observers` in place, where the same mismatch writes through
/// an integer the caller passed by value; the 0.10.0 ABI shrinks
/// `EmpyreanSolveFor` and shifts the tail of the `EmpyreanODConfig` that
/// embeds it. Checking [`empyrean_abi_version`] the moment the library opens
/// is what that accessor exists for, and it is cheap — one call, once per
/// process.
pub use *;
// The header/prebuilt pin the build script enforces. Compiled only for
// tests here — at build time `build.rs` pulls the same file in directly,
// so the parse the tests cover is the parse the guard runs.