Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Look for backend implementations in a specific directory #64

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 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)
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