From 8b23c20627af5343607e56a43f85770154349a03 Mon Sep 17 00:00:00 2001 From: Tobias Fischer Date: Tue, 15 Sep 2026 17:50:38 +1000 Subject: [PATCH 1/2] Add emscripten guards to shared_library.c's dlopen path (#591) * fix: add emscripten guards to shared_library.c's dlopen path Two related gaps in rcutils_load_shared_library() / rcutils_get_platform_library_name(), found while getting rcl_logging_implementation's dlopen-by-name backend selection working on emscripten-wasm32: - rcutils_get_platform_library_name() had no emscripten branch, so it always fell through with written == 0 ("failed to format library name"), regardless of which RCL_LOGGING_IMPLEMENTATION backend was requested. wasm32 side modules use the same "lib.so" convention as Linux. - The post-dlopen path-resolution code took the _GNU_SOURCE branch (which emscripten's headers define) and called dlinfo(..., RTLD_DI_LINKMAP, ...). Emscripten's dlopen()/dlinfo() are a JS-backed shim, not glibc's, and don't support reading back a real struct link_map -- so a successful dlopen() got treated as a failure once dlinfo() returned -1. The #else branch (reuse the path dlopen() was given) already covers this platform correctly. Verified end-to-end on a ROS 2 rolling + rmw_zenoh_pico + real-pthreads emscripten-wasm32 build: a wasm32 rclpy talker's logging initialization (rcl_logging_configure -> rcl_logging_implementation -> this dlopen path) now succeeds instead of aborting with "failed to load any logging implementations". Co-Authored-By: Claude Sonnet 5 Signed-off-by: Tobias Fischer Signed-off-by: Alejandro Hernandez Cordero Co-authored-by: Alejandro Hernandez Cordero (cherry picked from commit a2d8f50a9b847d0c8aae1f20d9c069f91ec88ef0) # Conflicts: # src/shared_library.c --- src/shared_library.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/shared_library.c b/src/shared_library.c index 0190afcc..f2b625c4 100644 --- a/src/shared_library.c +++ b/src/shared_library.c @@ -127,7 +127,18 @@ rcutils_load_shared_library( goto fail; } lib->library_path = rcutils_strdup(image_name, lib->allocator); +<<<<<<< HEAD #elif defined(_GNU_SOURCE) && !defined(__QNXNTO__) && !defined(__ANDROID__) +======= + // Emscripten defines _GNU_SOURCE but its dlopen()/dlinfo() are a JS-backed + // shim, not glibc's -- RTLD_DI_LINKMAP support (reading back a real + // struct link_map) doesn't exist there. A successful dlopen() would + // otherwise get treated as a failure once dlinfo() returns -1 below; the + // #else branch already covers this correctly (it just reuses the path we + // opened the library from, no introspection needed). +#elif defined(_GNU_SOURCE) && !defined(__QNXNTO__) && !defined(__ANDROID__) && \ + !defined(__OHOS__) && !defined(__EMSCRIPTEN__) +>>>>>>> a2d8f50 (Add emscripten guards to shared_library.c's dlopen path (#591)) struct link_map * map = NULL; if (dlinfo(lib->lib_pointer, RTLD_DI_LINKMAP, &map) != 0) { RCUTILS_SET_ERROR_MSG_WITH_FORMAT_STRING("dlinfo error: %s", dlerror()); @@ -294,7 +305,12 @@ rcutils_get_platform_library_name( int written = 0; -#if defined(__linux__) || defined(__QNXNTO__) + // rcl_logging_implementation dlopens its backend (spdlog or noop) by name + // at runtime via this function -- with no emscripten case it always falls + // through with written == 0 ("failed to format library name"), regardless + // of which backend RCL_LOGGING_IMPLEMENTATION selects. wasm32 side modules + // use the same "lib.so" naming convention as Linux. +#if defined(__linux__) || defined(__QNXNTO__) || defined(__EMSCRIPTEN__) if (debug) { if (buffer_size >= (strlen(library_name) + 8)) { written = rcutils_snprintf( From 1b43b797d2efa0f7027a01e6e1b9a3e15419960e Mon Sep 17 00:00:00 2001 From: Alejandro Hernandez Cordero Date: Tue, 15 Sep 2026 10:13:07 +0200 Subject: [PATCH 2/2] Fix merge Signed-off-by: Alejandro Hernandez Cordero --- src/shared_library.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/shared_library.c b/src/shared_library.c index f2b625c4..39703438 100644 --- a/src/shared_library.c +++ b/src/shared_library.c @@ -127,9 +127,6 @@ rcutils_load_shared_library( goto fail; } lib->library_path = rcutils_strdup(image_name, lib->allocator); -<<<<<<< HEAD -#elif defined(_GNU_SOURCE) && !defined(__QNXNTO__) && !defined(__ANDROID__) -======= // Emscripten defines _GNU_SOURCE but its dlopen()/dlinfo() are a JS-backed // shim, not glibc's -- RTLD_DI_LINKMAP support (reading back a real // struct link_map) doesn't exist there. A successful dlopen() would @@ -137,8 +134,7 @@ rcutils_load_shared_library( // #else branch already covers this correctly (it just reuses the path we // opened the library from, no introspection needed). #elif defined(_GNU_SOURCE) && !defined(__QNXNTO__) && !defined(__ANDROID__) && \ - !defined(__OHOS__) && !defined(__EMSCRIPTEN__) ->>>>>>> a2d8f50 (Add emscripten guards to shared_library.c's dlopen path (#591)) + !defined(__EMSCRIPTEN__) struct link_map * map = NULL; if (dlinfo(lib->lib_pointer, RTLD_DI_LINKMAP, &map) != 0) { RCUTILS_SET_ERROR_MSG_WITH_FORMAT_STRING("dlinfo error: %s", dlerror());