Skip to content

Commit

Permalink
Look for backend implementations in a specific directory
Browse files Browse the repository at this point in the history
Make the backend loader search for implementations in the
<libdir>/wpe-<apiversion> directory (typically /usr/lib/wpe-1.0)
when a relative path is passed to wpe_loader_init().

Fixes #59
  • Loading branch information
aperezdc committed Feb 25, 2020
1 parent b191f14 commit 57e313a
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 38 deletions.
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ CALCULATE_LIBRARY_VERSIONS_FROM_LIBTOOL_TRIPLE(LIBWPE 4 0 3)
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)
Expand Down Expand Up @@ -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}\"
$<TARGET_PROPERTY:GL::egl,INTERFACE_COMPILE_DEFINITIONS>
)
if (WPE_BACKEND)
Expand Down
24 changes: 24 additions & 0 deletions docs/backend-implementing.md
Original file line number Diff line number Diff line change
@@ -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 `<prefix>/lib/wpe-<apiversion>`,
with `<prefix>` being the base directory where *libwpe* is installed, and
`<apiversion>` 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)" $<
```
1 change: 1 addition & 0 deletions docs/sitemap.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
index.md
backend-implementing.md
c-index
17 changes: 13 additions & 4 deletions include/wpe/loader.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 `<prefix>/lib/wpe-<apiversion>`, where `<prefix>` is the installation
* prefix and `<apiversion>` is the libwpe API version being used. See the
* [backend implementation
* documentation](backend-implementing.md#Installation) for more.
*
* Returns: Whether initialization succeeded.
*/
Expand All @@ -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
Expand Down
75 changes: 42 additions & 33 deletions src/loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,68 +31,67 @@
#include <stdlib.h>
#include <string.h>

#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);
if (!s_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");
}
Expand All @@ -101,41 +100,51 @@ 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*
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*
Expand Down
1 change: 1 addition & 0 deletions wpe.pc.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 57e313a

Please sign in to comment.