master ohmu/fastfetch-openbsd / src / common / library.h
ohmu  ·  2026-10-15
  1#pragma once
  2
  3#include "fastfetch.h" // IWYU pragma: keep
  4
  5#ifndef FF_DISABLE_DLOPEN
  6
  7    #if defined(_WIN32)
  8        #define FF_DLOPEN_FLAGS 0
  9[[nodiscard]] void* dlopen(const char* path, int mode);
 10[[nodiscard]] void* dlsym(void* handle, const char* symbol);
 11int dlclose(void* handle);
 12    #else
 13        #include <dlfcn.h>
 14    #endif
 15
 16    #ifdef _WIN32
 17        #define FF_LIBRARY_EXTENSION ".dll"
 18    #elif defined(__APPLE__)
 19        #define FF_LIBRARY_EXTENSION ".dylib"
 20    #else
 21        #define FF_LIBRARY_EXTENSION ".so"
 22    #endif
 23
 24[[gnu::nonnull(1)]] static inline void ffLibraryUnload(void** handle) {
 25    if (*handle) {
 26        dlclose(*handle);
 27    }
 28}
 29
 30    #define FF_LIBRARY_SYMBOL(symbolName) \
 31        typeof(&symbolName) ff##symbolName;
 32
 33    #define FF_LIBRARY_LOAD(libraryObjectName, returnValue, libraryFileName, maxVersion, ...)                                          \
 34        [[gnu::cleanup(ffLibraryUnload)]] void* libraryObjectName = ffLibraryLoadSingle(libraryFileName, maxVersion);                      \
 35        __VA_OPT__(if (__builtin_expect(libraryObjectName == nullptr, false)) libraryObjectName = ffLibraryLoadMulti(__VA_ARGS__, nullptr);) \
 36        if (__builtin_expect(libraryObjectName == nullptr, false))                                                                        \
 37            return returnValue;
 38
 39    #define FF_LIBRARY_LOAD_MESSAGE(libraryObjectName, libraryFileName, maxVersion, ...) \
 40        FF_LIBRARY_LOAD(libraryObjectName, "dlopen(" libraryFileName ") failed", libraryFileName, maxVersion, ##__VA_ARGS__)
 41
 42    #define FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, symbolMapping, symbolName, returnValue) \
 43        symbolMapping = (typeof(&symbolName)) dlsym(library, #symbolName);              \
 44        if (__builtin_expect(symbolMapping == nullptr, false))                                 \
 45            return returnValue;
 46
 47    #define FF_LIBRARY_LOAD_SYMBOL(library, symbolName, returnValue) \
 48        auto FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, ff##symbolName, symbolName, returnValue);
 49
 50    #define FF_LIBRARY_LOAD_SYMBOL_LAZY(library, symbolName) \
 51        auto ff##symbolName = (typeof(&symbolName)) dlsym(library, #symbolName);
 52
 53    #define FF_LIBRARY_LOAD_SYMBOL_MESSAGE(library, symbolName) \
 54        auto FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, ff##symbolName, symbolName, "dlsym " #symbolName " failed");
 55
 56    #define FF_LIBRARY_LOAD_SYMBOL_VAR(library, varName, symbolName, returnValue) \
 57        FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, (varName).ff##symbolName, symbolName, returnValue);
 58
 59    #define FF_LIBRARY_LOAD_SYMBOL_VAR_LAZY(library, varName, symbolName) \
 60        (varName).ff##symbolName = (typeof(&symbolName)) dlsym(library, #symbolName);
 61
 62    #define FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(library, varName, symbolName) \
 63        FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, (varName).ff##symbolName, symbolName, "dlsym " #symbolName " failed");
 64
 65    #define FF_LIBRARY_LOAD_SYMBOL_PTR(library, varName, symbolName, returnValue) \
 66        FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, (varName)->ff##symbolName, symbolName, returnValue);
 67
 68[[gnu::nonnull(1), nodiscard]] void* ffLibraryLoadSingle(const char* path, int maxVersion);
 69[[gnu::nonnull(1), nodiscard]] void* ffLibraryLoadMulti(const char* path, int maxVersion, ...);
 70
 71#else
 72
 73    #define FF_LIBRARY_EXTENSION ""
 74
 75    #define FF_LIBRARY_SYMBOL(symbolName) \
 76        typeof(&symbolName) ff##symbolName;
 77
 78    #define FF_LIBRARY_LOAD(libraryObjectName, returnValue, ...) \
 79        [[maybe_unused]] void* libraryObjectName = nullptr; // Placeholder
 80
 81    #define FF_LIBRARY_LOAD_MESSAGE(libraryObjectName, libraryFileName, maxVersion, ...) \
 82        FF_LIBRARY_LOAD(libraryObjectName, , libraryFileName, maxVersion, ##__VA_ARGS__)
 83
 84    #define FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, symbolMapping, symbolName, returnValue) \
 85        symbolMapping = (typeof(&symbolName)) &symbolName;
 86
 87    #define FF_LIBRARY_LOAD_SYMBOL(library, symbolName, returnValue) \
 88        [[maybe_unused]] auto FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, ff##symbolName, symbolName, returnValue);
 89
 90    #define FF_LIBRARY_LOAD_SYMBOL_LAZY(library, symbolName) \
 91        [[maybe_unused]] auto ff##symbolName = (typeof(&symbolName)) &symbolName;
 92
 93    #define FF_LIBRARY_LOAD_SYMBOL_MESSAGE(library, symbolName) \
 94        [[maybe_unused]] auto FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, ff##symbolName, symbolName, "dlsym " #symbolName " failed");
 95
 96    #define FF_LIBRARY_LOAD_SYMBOL_VAR(library, varName, symbolName, returnValue) \
 97        FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, (varName).ff##symbolName, symbolName, returnValue);
 98
 99    #define FF_LIBRARY_LOAD_SYMBOL_VAR_LAZY(library, varName, symbolName) \
100        (varName).ff##symbolName = (typeof(&symbolName)) &symbolName;
101
102    #define FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(library, varName, symbolName) \
103        FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, (varName).ff##symbolName, symbolName, "dlsym " #symbolName " failed");
104
105    #define FF_LIBRARY_LOAD_SYMBOL_PTR(library, varName, symbolName, returnValue) \
106        FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, (varName)->ff##symbolName, symbolName, returnValue);
107
108#endif
109
110#if _WIN32
111[[gnu::nonnull(1), nodiscard]] void* ffLibraryGetModule(const wchar_t* libraryFileName);
112#endif
113
114// Return false to stop iterating, true to continue
115typedef bool (*FFLibraryIterateCallback)(const char* name, void* userData);
116// Iterate over all loaded dynamic libraries. Returns true on success, false on failure.
117[[nodiscard]] bool ffLibraryIterateDynamicLibs(FFLibraryIterateCallback callback, void* userData);