diff --git a/src/box2dxt.lcb b/src/box2dxt.lcb index 54a2b6a..cb2a01c 100644 --- a/src/box2dxt.lcb +++ b/src/box2dxt.lcb @@ -442,8 +442,8 @@ private foreign handler _query_normal_y(in pI as CInt) returns CDouble binds to private foreign handler _query_fraction(in pI as CInt) returns CDouble binds to "c:box2dxt>b2lc_query_fraction!cdecl" -- ---- native loader assist (Linux) ---------------------------------- --- The ONLY two bindings that do NOT target the box2dxt shim: they bind to --- the platform's own dynamic loader (dlopen/dlerror), resolved from the +-- The ONLY three bindings that do NOT target the box2dxt shim: they bind to +-- the platform's own loader/libc (dlopen/dlerror/realpath), resolved from the -- host process's global symbol table. That is the whole point -- they must -- be callable BEFORE box2dxt.so is loadable, so a script can preload the -- shim by absolute path. On Linux the engine hands the bare name @@ -459,6 +459,10 @@ private foreign handler _query_fraction(in pI as CInt) returns CDouble binds to -- dlopen still lives in libdl -> "c:libdl.so.2>dlopen!cdecl". private foreign handler _dlopen(in pPath as ZStringNative, in pFlags as CInt) returns optional Pointer binds to "c:>dlopen!cdecl" private foreign handler _dlerror() returns optional ZStringNative binds to "c:>dlerror!cdecl" +-- realpath("/proc/self/exe", nil) -> the running engine's own executable path +-- on Linux; used by the b2LoadNativeLibHere helper below to locate the engine +-- folder. Returns nothing off Linux (no /proc). Only ever called on Linux. +private foreign handler _realpath(in pPath as ZStringNative, in pResolved as optional Pointer) returns optional ZStringNative binds to "c:>realpath!cdecl" -- small bool -> int helper (no foreign call, so no unsafe needed) private handler bi(in pB as Boolean) returns Integer @@ -468,6 +472,57 @@ private handler bi(in pB as Boolean) returns Integer return 0 end handler +-- ---- engine-folder preload (Linux helper) -------------------------- +-- Locate the running engine's OWN folder (realpath /proc/self/exe), strip to +-- its directory, and preload "/box2dxt.so" by absolute path -- so a user +-- can just drop the library beside the OXT engine (or bundle it in a +-- standalone) and a later bare-name bind resolves to it (no /usr/lib, no sudo, +-- no LD_LIBRARY_PATH). Returns 1 if a library was loaded, else 0. +-- +-- LINUX ONLY, and deliberately NOT auto-fired: realpath/dlopen are POSIX, so +-- call this ONLY when the platform is Linux (e.g. the Kit gates it with +-- `the platform is "Linux"`). It is intentionally NOT invoked from +-- b2Version/checkABI -- those run on every platform, and touching the POSIX +-- bindings on Windows/macOS would error (those platforms already load the +-- library from beside the stack/app anyway). Requires the library's soname to +-- be "box2dxt.so" (-DBOX2DXT_BARE_SONAME) or the resident copy will not match +-- the engine's bare-name request. +public handler b2LoadNativeLibHere() returns Integer + variable tExe as optional String + variable tPath as String + variable tLen as Integer + variable tCut as Integer + variable i as Integer + variable tLib as String + variable tHandle as optional Pointer + unsafe + put _realpath("/proc/self/exe", nothing) into tExe + end unsafe + if tExe is nothing then + return 0 + end if + put tExe into tPath + put the number of chars in tPath into tLen + put 0 into tCut + repeat with i from 1 up to tLen + if char i of tPath is "/" then + put i into tCut + end if + end repeat + if tCut is 0 then + return 0 + end if + put char 1 to tCut of tPath into tLib + put tLib & "box2dxt.so" into tLib + unsafe + put _dlopen(tLib, 258) into tHandle + end unsafe + if tHandle is nothing then + return 0 + end if + return 1 +end handler + -- ===================================================================== -- Public API (callable from xTalk / OpenXTalk Script) -- =====================================================================