mirror of
https://codeberg.org/dnkl/yambar.git
synced 2025-04-24 12:55:41 +02:00
config: dlopen() modules on-demand
TODO: optimizations and proper cleanup * We currently reload the shared library for each *instance* of the module, and we do it twice; once when verifying, and once when instantiating. * The shared libraries are never dlclosed()
This commit is contained in:
parent
731ab848e1
commit
64b77a0efc
4 changed files with 170 additions and 113 deletions
|
@ -1,4 +1,4 @@
|
|||
cmake_minimum_required(VERSION 3.9)
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(f00bar C)
|
||||
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
|
@ -19,11 +19,6 @@ pkg_check_modules(FONTCONFIG REQUIRED fontconfig) # Core
|
|||
pkg_check_modules(CAIRO REQUIRED cairo cairo-xcb cairo-ft) # Core
|
||||
pkg_check_modules(YAML REQUIRED yaml-0.1) # Core (configuration)
|
||||
|
||||
pkg_check_modules(XCB_XKB REQUIRED xcb-xkb) # Module/xkb
|
||||
pkg_check_modules(JSON REQUIRED json-c) # Module/i3
|
||||
pkg_check_modules(UDEV REQUIRED libudev) # Module/battery
|
||||
pkg_check_modules(MPD REQUIRED libmpdclient) # Module/mpd
|
||||
pkg_check_modules(ALSA REQUIRED alsa) # Module/alsa
|
||||
|
||||
add_executable(f00bar
|
||||
bar.c bar.h
|
||||
|
@ -50,32 +45,19 @@ add_executable(f00bar
|
|||
particles/progress-bar.c particles/progress-bar.h
|
||||
particles/ramp.c particles/ramp.h
|
||||
particles/string.c particles/string.h
|
||||
|
||||
modules/alsa/alsa.c modules/alsa/alsa.h
|
||||
modules/backlight/backlight.c modules/backlight/backlight.h
|
||||
modules/battery/battery.c modules/battery/battery.h
|
||||
modules/clock/clock.c modules/clock/clock.h
|
||||
modules/i3/i3.c modules/i3/i3.h
|
||||
modules/label/label.c modules/label/label.h
|
||||
modules/mpd/mpd.c modules/mpd/mpd.h
|
||||
modules/network/network.c modules/network/network.h
|
||||
modules/removables/removables.c modules/removables/removables.h
|
||||
modules/xkb/xkb.c modules/xkb/xkb.h
|
||||
modules/xwindow/xwindow.c modules/xwindow/xwindow.h
|
||||
)
|
||||
|
||||
# TODO: directory global
|
||||
target_compile_definitions(f00bar PRIVATE _GNU_SOURCE)
|
||||
|
||||
# Make global symbols in f00bar visible to dlopen:ed plugins
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -rdynamic")
|
||||
|
||||
target_compile_options(f00bar PRIVATE
|
||||
${XCB_CFLAGS_OTHER}
|
||||
${FONTCONFIG_CFLAGS_OTHER}
|
||||
${CAIRO_CFLAGS_OTHER}
|
||||
${YAML_CFLAGS_OTHER}
|
||||
${XCB_XKB_CFLAGS_OTHER}
|
||||
${JSON_CFLAGS_OTHER}
|
||||
${UDEV_CFLAGS_OTHER}
|
||||
${MPD_CFLAGS_OTHER}
|
||||
${ALSA_CFLAGS_OTHER}
|
||||
)
|
||||
|
||||
target_include_directories(f00bar PRIVATE
|
||||
|
@ -83,22 +65,22 @@ target_include_directories(f00bar PRIVATE
|
|||
${FONTCONFIG_INCLUDE_DIRS}
|
||||
${CAIRO_INCLUDE_DIRS}
|
||||
${YAML_INCLUDE_DIRS}
|
||||
${XCB_XKB_INCLUDE_DIRS}
|
||||
${JSON_INCLUDE_DIRS}
|
||||
${UDEV_INCLUDE_DIRS}
|
||||
${MPD_INCLUDE_DIRS}
|
||||
${ALSA_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
target_link_libraries(f00bar
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${CMAKE_DL_LIBS}
|
||||
|
||||
${XCB_LIBRARIES}
|
||||
${FONTCONFIG_LIBRARIES}
|
||||
${CAIRO_LIBRARIES}
|
||||
${YAML_LIBRARIES}
|
||||
${XCB_XKB_LIBRARIES}
|
||||
${JSON_LIBRARIES}
|
||||
${UDEV_LIBRARIES}
|
||||
${MPD_LIBRARIES}
|
||||
${ALSA_LIBRARIES}
|
||||
)
|
||||
|
||||
add_library(module-sdk INTERFACE)
|
||||
target_compile_definitions(module-sdk INTERFACE _GNU_SOURCE)
|
||||
target_compile_options(module-sdk INTERFACE ${CAIRO_CFLAGS_OTHER})
|
||||
target_include_directories(module-sdk INTERFACE ${CAIRO_INCLUDE_DIRS})
|
||||
target_link_libraries(module-sdk INTERFACE ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
add_subdirectory(modules)
|
||||
|
|
128
config-verify.c
128
config-verify.c
|
@ -3,24 +3,17 @@
|
|||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#define LOG_MODULE "config:verify"
|
||||
#define LOG_ENABLE_DBG 0
|
||||
#include "log.h"
|
||||
#include "tllist.h"
|
||||
|
||||
#include "modules/alsa/alsa.h"
|
||||
#include "modules/backlight/backlight.h"
|
||||
#include "modules/battery/battery.h"
|
||||
#include "modules/clock/clock.h"
|
||||
#include "modules/i3/i3.h"
|
||||
#include "modules/label/label.h"
|
||||
#include "modules/label/label.h"
|
||||
#include "modules/mpd/mpd.h"
|
||||
#include "modules/network/network.h"
|
||||
#include "modules/removables/removables.h"
|
||||
#include "modules/xkb/xkb.h"
|
||||
#include "modules/xwindow/xwindow.h"
|
||||
|
||||
const char *
|
||||
conf_err_prefix(const keychain_t *chain, const struct yml_node *node)
|
||||
{
|
||||
|
@ -441,42 +434,46 @@ verify_module(keychain_t *chain, const struct yml_node *node)
|
|||
return false;
|
||||
}
|
||||
|
||||
/* TODO: this will dlopened later */
|
||||
static const struct {
|
||||
const char *name;
|
||||
const struct module_info *info;
|
||||
} modules[] = {
|
||||
{"alsa", &module_alsa},
|
||||
{"backlight", &module_backlight},
|
||||
{"battery", &module_battery},
|
||||
{"clock", &module_clock},
|
||||
{"i3", &module_i3},
|
||||
{"label", &module_label},
|
||||
{"mpd", &module_mpd},
|
||||
{"network", &module_network},
|
||||
{"removables", &module_removables},
|
||||
{"xkb", &module_xkb},
|
||||
{"xwindow", &module_xwindow},
|
||||
};
|
||||
char path[1024];
|
||||
snprintf(path, sizeof(path), "./modules/lib%s.so", mod_name);
|
||||
|
||||
for (size_t i = 0; i < sizeof(modules) / sizeof(modules[0]); i++) {
|
||||
if (strcmp(modules[i].name, mod_name) != 0)
|
||||
continue;
|
||||
void *lib = dlopen(path, RTLD_LOCAL | RTLD_NOW | RTLD_NOLOAD);
|
||||
|
||||
if (!conf_verify_dict(chain_push(chain, mod_name),
|
||||
values,
|
||||
modules[i].info->attrs,
|
||||
modules[i].info->attr_count))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (lib == NULL)
|
||||
lib = dlopen(path, RTLD_LOCAL | RTLD_NOW);
|
||||
|
||||
chain_pop(chain);
|
||||
return true;
|
||||
if (lib == NULL) {
|
||||
const char *dl_error = dlerror();
|
||||
if (dl_error != NULL)
|
||||
LOG_ERR("%s: dlopen: %s", mod_name, dlerror());
|
||||
else
|
||||
LOG_ERR("%s: invalid module name: %s",
|
||||
conf_err_prefix(chain, module), mod_name);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_ERR("%s: invalid module name: %s", conf_err_prefix(chain, module), mod_name);
|
||||
return false;
|
||||
char sym[1024];
|
||||
snprintf(sym, sizeof(sym), "module_%s", mod_name);
|
||||
|
||||
dlerror(); /* Clear previous error */
|
||||
const struct module_info *info = dlsym(lib, sym);
|
||||
|
||||
const char *dlsym_error = dlerror();
|
||||
if (dlsym_error != NULL) {
|
||||
LOG_ERR("%s: dlsym: %s", mod_name, dlsym_error);
|
||||
dlclose(lib);
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(info != NULL);
|
||||
|
||||
if (!conf_verify_dict(chain_push(chain, mod_name), values,
|
||||
info->attrs, info->attr_count))
|
||||
return false;
|
||||
|
||||
chain_pop(chain);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -515,6 +512,45 @@ verify_bar_location(keychain_t *chain, const struct yml_node *node)
|
|||
return conf_verify_enum(chain, node, (const char *[]){"top", "bottom"}, 2);
|
||||
}
|
||||
|
||||
#if defined(LOG_ENABLE_DBG) && LOG_ENABLE_DBG
|
||||
static void
|
||||
find_modules(void)
|
||||
{
|
||||
int cwd = open(".", O_RDONLY);
|
||||
assert(cwd != -1);
|
||||
|
||||
int modules = openat(cwd, "modules", O_RDONLY);
|
||||
assert(modules != -1);
|
||||
|
||||
DIR *dir = fdopendir(modules);
|
||||
assert(dir != NULL);
|
||||
|
||||
for (struct dirent *e = readdir(dir); e != NULL; e = readdir(dir)) {
|
||||
const size_t len = strlen(e->d_name);
|
||||
|
||||
if (len <= 6) {
|
||||
/* Need at least "libX.so" */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(e->d_name, "lib", 3) != 0)
|
||||
continue;
|
||||
|
||||
if (strcmp(&e->d_name[len - 3], ".so") != 0)
|
||||
continue;
|
||||
|
||||
char *name = malloc(len - 6 + 1);
|
||||
memcpy(name, &e->d_name[3], len - 6);
|
||||
name[len - 6] = '\0';
|
||||
|
||||
LOG_DBG("%s", name);
|
||||
free(name);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
conf_verify_bar(const struct yml_node *bar)
|
||||
{
|
||||
|
@ -523,6 +559,10 @@ conf_verify_bar(const struct yml_node *bar)
|
|||
return false;
|
||||
}
|
||||
|
||||
#if defined(LOG_ENABLE_DBG) && LOG_ENABLE_DBG
|
||||
find_modules();
|
||||
#endif
|
||||
|
||||
keychain_t chain = tll_init();
|
||||
chain_push(&chain, "bar");
|
||||
|
||||
|
|
53
config.c
53
config.c
|
@ -5,6 +5,10 @@
|
|||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
|
||||
#include "color.h"
|
||||
|
||||
#include "decoration.h"
|
||||
|
@ -21,18 +25,6 @@
|
|||
#include "particles/string.h"
|
||||
|
||||
#include "module.h"
|
||||
#include "modules/alsa/alsa.h"
|
||||
#include "modules/backlight/backlight.h"
|
||||
#include "modules/battery/battery.h"
|
||||
#include "modules/clock/clock.h"
|
||||
#include "modules/i3/i3.h"
|
||||
#include "modules/label/label.h"
|
||||
#include "modules/mpd/mpd.h"
|
||||
#include "modules/network/network.h"
|
||||
#include "modules/removables/removables.h"
|
||||
#include "modules/xkb/xkb.h"
|
||||
#include "modules/xwindow/xwindow.h"
|
||||
|
||||
#include "config-verify.h"
|
||||
|
||||
static uint8_t
|
||||
|
@ -452,30 +444,19 @@ conf_to_bar(const struct yml_node *bar)
|
|||
struct yml_dict_iter m = yml_dict_iter(it.node);
|
||||
const char *mod_name = yml_value_as_string(m.key);
|
||||
|
||||
if (strcmp(mod_name, "alsa") == 0)
|
||||
mods[idx] = module_alsa.from_conf(m.value, font);
|
||||
else if (strcmp(mod_name, "backlight") == 0)
|
||||
mods[idx] = module_backlight.from_conf(m.value, font);
|
||||
else if (strcmp(mod_name, "battery") == 0)
|
||||
mods[idx] = module_battery.from_conf(m.value, font);
|
||||
else if (strcmp(mod_name, "clock") == 0)
|
||||
mods[idx] = module_clock.from_conf(m.value, font);
|
||||
else if (strcmp(mod_name, "i3") == 0)
|
||||
mods[idx] = module_i3.from_conf(m.value, font);
|
||||
else if (strcmp(mod_name, "label") == 0)
|
||||
mods[idx] = module_label.from_conf(m.value, font);
|
||||
else if (strcmp(mod_name, "mpd") == 0)
|
||||
mods[idx] = module_mpd.from_conf(m.value, font);
|
||||
else if (strcmp(mod_name, "network") == 0)
|
||||
mods[idx] = module_network.from_conf(m.value, font);
|
||||
else if (strcmp(mod_name, "removables") == 0)
|
||||
mods[idx] = module_removables.from_conf(m.value, font);
|
||||
else if (strcmp(mod_name, "xkb") == 0)
|
||||
mods[idx] = module_xkb.from_conf(m.value, font);
|
||||
else if (strcmp(mod_name, "xwindow") == 0)
|
||||
mods[idx] = module_xwindow.from_conf(m.value, font);
|
||||
else
|
||||
assert(false);
|
||||
char path[1024];
|
||||
snprintf(path, sizeof(path), "./modules/lib%s.so", mod_name);
|
||||
|
||||
void *lib = dlopen(path, RTLD_LOCAL | RTLD_NOW | RTLD_NOLOAD);
|
||||
assert(lib != NULL);
|
||||
|
||||
char sym[1024];
|
||||
snprintf(sym, sizeof(sym), "module_%s", mod_name);
|
||||
|
||||
const struct module_info *info = dlsym(lib, sym);
|
||||
assert(info != NULL);
|
||||
|
||||
mods[idx] = info->from_conf(m.value, font);
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
|
|
54
modules/CMakeLists.txt
Normal file
54
modules/CMakeLists.txt
Normal file
|
@ -0,0 +1,54 @@
|
|||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
pkg_check_modules(ALSA REQUIRED alsa)
|
||||
add_library(alsa MODULE alsa/alsa.c alsa/alsa.h)
|
||||
target_compile_options(alsa PRIVATE ${ALSA_CFLAGS_OTHER})
|
||||
target_include_directories(alsa PRIVATE ${ALSA_INCLUDE_DIRS})
|
||||
target_link_libraries(alsa module-sdk ${ALSA_LIBRARIES})
|
||||
|
||||
pkg_check_modules(UDEV REQUIRED libudev)
|
||||
add_library(backlight MODULE backlight/backlight.c backlight/backlight.h)
|
||||
target_compile_options(backlight PRIVATE ${UDEV_CFLAGS_OTHER})
|
||||
target_include_directories(backlight PRIVATE ${UDEV_INCLUDE_DIRS})
|
||||
target_link_libraries(backlight module-sdk ${UDEV_LIBRARIES})
|
||||
|
||||
add_library(battery MODULE battery/battery.c battery/battery.h)
|
||||
target_compile_options(battery PRIVATE ${UDEV_CFLAGS_OTHER})
|
||||
target_include_directories(battery PRIVATE ${UDEV_INCLUDE_DIRS})
|
||||
target_link_libraries(battery module-sdk ${UDEV_LIBRARIES})
|
||||
|
||||
add_library(clock MODULE clock/clock.c clock/clock.h)
|
||||
target_link_libraries(clock module-sdk)
|
||||
|
||||
pkg_check_modules(JSON REQUIRED json-c)
|
||||
add_library(i3 MODULE i3/i3.c i3/i3.h)
|
||||
target_compile_options(i3 PRIVATE ${JSON_CFLAGS_OTHER})
|
||||
target_include_directories(i3 PRIVATE ${JSON_INCLUDE_DIRS})
|
||||
target_link_libraries(i3 module-sdk ${JSON_LIBRARIES})
|
||||
|
||||
|
||||
add_library(label MODULE label/label.c label/label.h)
|
||||
target_link_libraries(label module-sdk)
|
||||
|
||||
pkg_check_modules(MPD REQUIRED libmpdclient)
|
||||
add_library(mpd MODULE mpd/mpd.c mpd/mpd.h)
|
||||
target_compile_options(mpd PRIVATE ${MPD_CFLAGS_OTHER})
|
||||
target_include_directories(mpd PRIVATE ${MPD_INCLUDE_DIRS})
|
||||
target_link_libraries(mpd module-sdk ${MPD_LIBRARIES})
|
||||
|
||||
add_library(network MODULE network/network.c network/network.h)
|
||||
target_link_libraries(network module-sdk)
|
||||
|
||||
add_library(removables MODULE removables/removables.c removables/removables.h)
|
||||
target_compile_options(removables PRIVATE ${UDEV_CFLAGS_OTHER})
|
||||
target_include_directories(removables PRIVATE ${UDEV_INCLUDE_DIRS})
|
||||
target_link_libraries(removables module-sdk ${UDEV_LIBRARIES})
|
||||
|
||||
pkg_check_modules(XCB_XKB REQUIRED xcb-xkb)
|
||||
add_library(xkb MODULE xkb/xkb.c xkb/xkb.h)
|
||||
target_compile_options(xkb PRIVATE ${XCB_XKB_CFLAGS_OTHER})
|
||||
target_include_directories(xkb PRIVATE ${XCB_XKB_INCLUDE_DIRS})
|
||||
target_link_libraries(xkb module-sdk ${XCB_XKB_LIBRARIES})
|
||||
|
||||
add_library(xwindow MODULE xwindow/xwindow.c xwindow/xwindow.h)
|
||||
target_link_libraries(xwindow module-sdk)
|
Loading…
Add table
Reference in a new issue