I was working on the module loading system for TuxClocker when I realized the methods I knew were unsatisfactory for the hierarchical module system:

tc_module_t *tc_module_find(enum tc_module_category category, const char *name) { char abs_path[128]; const char *env_module_path = getenv(TC_MODULE_PATH_ENV); switch (category) { case TC_CATEGORY_ASSIGNABLE: snprintf(abs_path, 128, "%s/%s/%s", env_module_path, "assignable", name); break; ... } void *handle = tc_dlopen(abs_path); ...

As you can see, different directories are used to separate modules by category in case some with different categories have the same name. This method requires setting an environment variable on startup though, so it’s not a good way to do configuration. Let’s take a look at some example code for a similar loading system using rpath.

lib.c:

int getnum() { return 1; }

Compilation: gcc lib.c -shared -fpic -o lib.so

main.c:

#include <stdio.h> #include <dlfcn.h> int main() { void *lib = dlopen("lib.so", RTLD_LAZY); int (*getnum)() = dlsym(lib, "getnum"); if (getnum != NULL) { printf("%d

", getnum()); } return 0; }

Compilation: gcc main.c -ldl -Wl,-rpath,’${ORIGIN}’ -o main

Result:

$ ./main 1

We can use the rpath flag for specifying the module directory root during compilation according to configuration options so there won’t be need to specify the path at every start.