| 361 | } |
| 362 | |
| 363 | static int try_load_python(void) { |
| 364 | /* 1. Prefer libpython already loaded into the process (this is |
| 365 | * the typical case when LeanPy runs inside a Python host — |
| 366 | * using a different libpython would cause two independent |
| 367 | * CPython VMs and immediate crashes). */ |
| 368 | py_handle = dlopen(NULL, RTLD_LAZY); |
| 369 | if (py_handle && dlsym(py_handle, "Py_Initialize")) return 1; |
| 370 | py_handle = NULL; |
| 371 | |
| 372 | /* 2. Honour LEANPY_LIBPYTHON if set. */ |
| 373 | const char *override = getenv("LEANPY_LIBPYTHON"); |
| 374 | if (override && *override) { |
| 375 | py_handle = dlopen(override, RTLD_NOW | RTLD_GLOBAL); |
| 376 | if (py_handle) return 1; |
| 377 | } |
| 378 | |
| 379 | /* 3. Ask python3 / python on PATH for its libpython. Catches |
| 380 | * pyenv, uv, and framework installs whose lib dir isn't in |
| 381 | * the dyld search path. */ |
| 382 | if (try_python_subprocess("python3")) return 1; |
| 383 | if (try_python_subprocess("python")) return 1; |
| 384 | |
| 385 | /* 4. Fall back to common sonames (relies on dyld search path). */ |
| 386 | for (int i = 0; PY_CANDIDATES[i]; i++) { |
| 387 | py_handle = dlopen(PY_CANDIDATES[i], RTLD_NOW | RTLD_GLOBAL); |
| 388 | if (py_handle) return 1; |
| 389 | } |
| 390 | return 0; |
| 391 | } |
| 392 | |
| 393 | LEAN_EXPORT lean_obj_res lean_py_initialize(lean_obj_arg unit, lean_obj_arg world) { |
| 394 | (void)world; |
no test coverage detected