From 4c32a6a9328dd6938c009a77ffbc7b2e14948d5d Mon Sep 17 00:00:00 2001 From: Adrian Perez de Castro Date: Tue, 25 Feb 2020 14:45:04 +0200 Subject: [PATCH] Look for backend implementations in a specific directory Make the backend loader search for implementations in the /wpe- directory (typically /usr/lib/wpe-1.0) when a relative path is passed to wpe_loader_init(). Fixes #59 --- CMakeLists.txt | 3 +- docs/backend-implementing.md | 24 ++++++++++++ docs/sitemap.txt | 1 + include/wpe/loader.h | 17 ++++++-- src/loader.c | 75 ++++++++++++++++++++---------------- wpe.pc.cmake | 1 + 6 files changed, 83 insertions(+), 38 deletions(-) create mode 100644 docs/backend-implementing.md diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b82f8a1..7b4fd738 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,7 @@ CALCULATE_LIBRARY_VERSIONS_FROM_LIBTOOL_TRIPLE(LIBWPE 5 0 4) project(libwpe VERSION "${PROJECT_VERSION}") set(WPE_BACKEND "" CACHE STRING - "Name of the backend library to load, instead of libWPEBackend-default.so") + "Path of a fixed backend library to load, instead of libWPEBackend-default.so") include(CheckCCompilerFlag) include(CheckCXXCompilerFlag) @@ -86,6 +86,7 @@ target_include_directories(wpe PRIVATE ) target_compile_definitions(wpe PRIVATE WPE_COMPILATION + WPE_BACKENDS_DIR=\"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/wpe-${WPE_API_VERSION}\" $ ) if (WPE_BACKEND) diff --git a/docs/backend-implementing.md b/docs/backend-implementing.md new file mode 100644 index 00000000..899fd71c --- /dev/null +++ b/docs/backend-implementing.md @@ -0,0 +1,24 @@ +# Implementing Backends + +## Installation + +Backend implementations must be installed to a specific directory. The +location is determined at build time to be `/lib/wpe-`, +with `` being the base directory where *libwpe* is installed, and +`` the public API version. + +The `pkg-config` tool can be used to query the `backendsdir` variable, +which contains the location where backend implementations will be searched +for: + +```sh +pkg-config wpe-1.0 --variable=backendsdir +``` + +For example, the following Make snippet will install a backend in the +correct location: + +```make +install: libMyBackend.so + install -Dm755 -t "$$(pkg-config wpe-1.0 --variable=backendsdir)" $< +``` diff --git a/docs/sitemap.txt b/docs/sitemap.txt index 047dd866..9a9d3cbc 100644 --- a/docs/sitemap.txt +++ b/docs/sitemap.txt @@ -1,2 +1,3 @@ index.md + backend-implementing.md c-index diff --git a/include/wpe/loader.h b/include/wpe/loader.h index 53a4c4cd..f33169c3 100644 --- a/include/wpe/loader.h +++ b/include/wpe/loader.h @@ -69,7 +69,15 @@ struct wpe_loader_interface { * @impl_library_name: (transfer none): Name of the shared library object * to load as WPE backend implementation. * - * Initializes the `libwpe` object loader + * Initializes the `libwpe` object loader. If the @impl_library_name is a + * full path it will be used as-is, while a relative path will cause the + * backend implementation library to be searched for in a fixed location. + * + * The backends location is determined at build time, and typically will + * be `/lib/wpe-`, where `` is the installation + * prefix and `` is the libwpe API version being used. See the + * [backend implementation + * documentation](backend-implementing.md#Installation) for more. * * Returns: Whether initialization succeeded. */ @@ -81,10 +89,11 @@ wpe_loader_init(const char* impl_library_name); * wpe_loader_get_loaded_implementation_library_name: * * Obtain the name of the shared library object loaded as WPE backend - * implementation. Note that in general this will return the value passed - * to wpe_loader_init(), but that is not guaranteed. + * implementation. Note that in general this will return the actual location + * of the backend being used, which may not be the same value passed to + * wpe_loader_init(). * - * Returns: (transfer none): Name of the shared library object for the + * Returns: (transfer none): Path of the shared library object for the * backend implementation. */ WPE_EXPORT diff --git a/src/loader.c b/src/loader.c index 2db6abeb..e127e86c 100644 --- a/src/loader.c +++ b/src/loader.c @@ -31,38 +31,37 @@ #include #include +#define LENGTHOF(array) (sizeof(array) / sizeof(array[0])) + static void* s_impl_library = 0; static struct wpe_loader_interface* s_impl_loader = 0; #ifndef WPE_BACKEND -#define IMPL_LIBRARY_NAME_BUFFER_SIZE 512 -static char* s_impl_library_name; -static char s_impl_library_name_buffer[IMPL_LIBRARY_NAME_BUFFER_SIZE]; +static char* s_impl_library_path = NULL; +static char s_impl_library_path_buffer[512]; #endif #ifndef WPE_BACKEND static void -wpe_loader_set_impl_library_name(const char* impl_library_name) +wpe_loader_set_impl_library_path(const char* impl_library_path) { - size_t len; - - if (!impl_library_name) + if (!impl_library_path) return; - len = strlen(impl_library_name) + 1; + size_t len = strlen(impl_library_path) + 1; if (len == 1) return; - if (len > IMPL_LIBRARY_NAME_BUFFER_SIZE) - s_impl_library_name = (char *)malloc(len); + if (len > LENGTHOF(s_impl_library_path_buffer)) + s_impl_library_path = malloc(len); else - s_impl_library_name = s_impl_library_name_buffer; - memcpy(s_impl_library_name, impl_library_name, len); + s_impl_library_path = s_impl_library_path_buffer; + memcpy(s_impl_library_path, impl_library_path, len); } -#endif +#endif /* !WPE_BACKEND */ void -load_impl_library() +load_impl_library(void) { #ifdef WPE_BACKEND s_impl_library = dlopen(WPE_BACKEND, RTLD_NOW); @@ -70,29 +69,29 @@ load_impl_library() fprintf(stderr, "wpe: could not load compile-time defined WPE_BACKEND: %s\n", dlerror()); abort(); } -#else +#else /* !WPE_BACKEND */ #ifndef NDEBUG // Get the impl library from an environment variable, if available. - char* env_library_name = getenv("WPE_BACKEND_LIBRARY"); - if (env_library_name) { - s_impl_library = dlopen(env_library_name, RTLD_NOW); + const char* env_library_path = getenv("WPE_BACKEND_LIBRARY"); + if (env_library_path) { + s_impl_library = dlopen(env_library_path, RTLD_NOW); if (!s_impl_library) { fprintf(stderr, "wpe: could not load specified WPE_BACKEND_LIBRARY: %s\n", dlerror()); abort(); } - wpe_loader_set_impl_library_name(env_library_name); + wpe_loader_set_impl_library_path(env_library_path); } -#endif +#endif /* !NDEBUG */ if (!s_impl_library) { // Load libWPEBackend-default.so by ... default. - s_impl_library = dlopen("libWPEBackend-default.so", RTLD_NOW); + s_impl_library = dlopen(WPE_BACKENDS_DIR "/libWPEBackend-default.so", RTLD_NOW); if (!s_impl_library) { fprintf(stderr, "wpe: could not load the impl library. Is there any backend installed?: %s\n", dlerror()); abort(); } - wpe_loader_set_impl_library_name("libWPEBackend-default.so"); + wpe_loader_set_impl_library_path(WPE_BACKENDS_DIR "/libWPEBackend-default.so"); } -#endif +#endif /* WPE_BACKEND */ s_impl_loader = dlsym(s_impl_library, "_wpe_loader_interface"); } @@ -101,31 +100,41 @@ bool wpe_loader_init(const char* impl_library_name) { #ifndef WPE_BACKEND - if (!impl_library_name) { + if (!(impl_library_name && impl_library_name[0] != '\0')) { fprintf(stderr, "wpe_loader_init: invalid implementation library name\n"); abort(); } + const bool relative_path = (impl_library_name[0] != '/'); + + size_t len = strlen(impl_library_name) + 1 + (relative_path ? LENGTHOF(WPE_BACKENDS_DIR) : 0); + char impl_library_path[len]; + + if (relative_path) + snprintf(impl_library_path, len, WPE_BACKENDS_DIR "/%s", impl_library_name); + else + strncpy(impl_library_path, impl_library_name, len); + if (s_impl_library) { - if (!s_impl_library_name || strcmp(s_impl_library_name, impl_library_name) != 0) { + if (!s_impl_library_path || strcmp(s_impl_library_path, impl_library_path) != 0) { fprintf(stderr, "wpe_loader_init: already initialized\n"); return false; } return true; } - s_impl_library = dlopen(impl_library_name, RTLD_NOW); + s_impl_library = dlopen(impl_library_path, RTLD_NOW); if (!s_impl_library) { - fprintf(stderr, "wpe_loader_init could not load the library '%s': %s\n", impl_library_name, dlerror()); + fprintf(stderr, "wpe_loader_init could not load the library '%s': %s\n", impl_library_path, dlerror()); return false; } - wpe_loader_set_impl_library_name(impl_library_name); + wpe_loader_set_impl_library_path(impl_library_path); s_impl_loader = dlsym(s_impl_library, "_wpe_loader_interface"); return true; -#else +#else /* WPE_BACKEND */ return false; -#endif +#endif /* !WPE_BACKEND */ } const char* @@ -133,9 +142,9 @@ wpe_loader_get_loaded_implementation_library_name(void) { #ifdef WPE_BACKEND return s_impl_library ? WPE_BACKEND : NULL; -#else - return s_impl_library_name; -#endif +#else /* !WPE_BACKEND */ + return s_impl_library_path; +#endif /* WPE_BACKEND */ } void* diff --git a/wpe.pc.cmake b/wpe.pc.cmake index 87771b5a..f7294227 100644 --- a/wpe.pc.cmake +++ b/wpe.pc.cmake @@ -2,6 +2,7 @@ prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=${prefix} includedir=${prefix}/include libdir=${exec_prefix}/lib +backendsdir=${libdir}/wpe-@WPE_API_VERSION@ Name: wpe-@WPE_API_VERSION@ Description: The wpe library