Skip to content

Commit 16171ed

Browse files
committed
Fix FreeBSD: add dlopen RTLD_GLOBAL support for BSD systems
1 parent 5dac939 commit 16171ed

2 files changed

Lines changed: 25 additions & 10 deletions

File tree

c_src/CMakeLists.txt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,16 @@ if(APPLE)
122122
)
123123
# Add CoreFoundation framework
124124
target_link_libraries(py_nif PRIVATE "-framework CoreFoundation")
125+
elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR
126+
CMAKE_SYSTEM_NAME STREQUAL "NetBSD" OR
127+
CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
128+
# BSD systems
129+
target_link_options(py_nif PRIVATE
130+
-Wl,--export-dynamic
131+
)
132+
# No need to link libdl on BSD - dlopen is in libc
125133
elseif(UNIX)
126-
# Linux/FreeBSD/etc
134+
# Linux
127135
target_link_options(py_nif PRIVATE
128136
-Wl,--export-dynamic
129137
)

c_src/py_nif.c

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@
4141
#include <math.h>
4242
#include <unistd.h>
4343
#include <pthread.h>
44-
#ifdef __linux__
44+
#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
4545
#include <dlfcn.h>
46+
#define NEED_DLOPEN_GLOBAL 1
4647
#endif
4748

4849
/* ============================================================================
@@ -465,18 +466,24 @@ static ERL_NIF_TERM nif_py_init(ErlNifEnv *env, int argc, const ERL_NIF_TERM arg
465466
return ATOM_OK;
466467
}
467468

468-
#ifdef __linux__
469-
/* On Linux, we need to load libpython with RTLD_GLOBAL so that Python
469+
#ifdef NEED_DLOPEN_GLOBAL
470+
/* On Linux/FreeBSD/etc, we need to load libpython with RTLD_GLOBAL so that Python
470471
* extension modules can find Python symbols when dynamically loaded.
471472
* Without this, modules like _socket.so fail with "undefined symbol: PyByteArray_Type" */
472473
{
473474
char libpython[256];
474-
snprintf(libpython, sizeof(libpython), "libpython%d.%d.so.1.0",
475-
PY_MAJOR_VERSION, PY_MINOR_VERSION);
476-
void *handle = dlopen(libpython, RTLD_NOW | RTLD_GLOBAL);
477-
if (!handle) {
478-
/* Try without .1.0 suffix */
479-
snprintf(libpython, sizeof(libpython), "libpython%d.%d.so",
475+
void *handle = NULL;
476+
477+
/* Try various library name patterns */
478+
const char *patterns[] = {
479+
"libpython%d.%d.so.1.0", /* Linux with full version */
480+
"libpython%d.%d.so", /* Linux/FreeBSD */
481+
"libpython%d.%d.so.1", /* Some systems */
482+
NULL
483+
};
484+
485+
for (int i = 0; patterns[i] && !handle; i++) {
486+
snprintf(libpython, sizeof(libpython), patterns[i],
480487
PY_MAJOR_VERSION, PY_MINOR_VERSION);
481488
handle = dlopen(libpython, RTLD_NOW | RTLD_GLOBAL);
482489
}

0 commit comments

Comments
 (0)