From 579299f16e94914a3793000523421f92c6b81b0b Mon Sep 17 00:00:00 2001 From: bcasale Date: Fri, 31 Oct 2025 19:32:11 +0100 Subject: [PATCH] feat: add build_tag attribute to model struct to identify different module version --- .clang-format | 14 +++++++++ examples/advanced/loader.cpp | 27 +++++++++-------- examples/advanced/loader.hpp | 7 +++-- examples/advanced/main.cpp | 19 +++++++----- examples/advanced/modules/default_lib.cpp | 28 ++++++++++-------- examples/advanced/modules/external_module.cpp | 15 ++++++---- examples/advanced/modules/modules.cpp | 26 +++++++++++------ examples/advanced/modules/modules.hpp | 23 ++++++++------- examples/advanced/modules/wrong.cpp | 15 ++++++---- examples/basic/main.cpp | 16 ++++++---- examples/basic/modules/default_lib.cpp | 24 ++++++++++----- examples/basic/modules/external_module.cpp | 17 ++++++++--- examples/basic/modules/modules.hpp | 8 ++--- examples/basic/modules/wrong.cpp | 17 ++++++++--- meson.build | 2 +- public/dynlib/dyn_module.hpp | 14 +++++---- public/dynlib/dynlib.hpp | 29 ++++++++++--------- 17 files changed, 187 insertions(+), 114 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..c3e769a --- /dev/null +++ b/.clang-format @@ -0,0 +1,14 @@ +BasedOnStyle: llvm +BraceWrapping: + AfterFunction: true +AllowShortFunctionsOnASingleLine: None +BinPackArguments: false +BinPackParameters: false +NamespaceIndentation: All +IndentPPDirectives: AfterHash +ColumnLimit: 80 # Disables column limit to prevent unwanted line wrapping. +CommentPragmas: true # Properly formats comments with pragmas. +SpaceBeforeParens: ControlStatements # Space before parentheses for control statements. +UseTab: Never # Use spaces for indentation instead of tabs. +PointerAlignment: Left +BreakBeforeBraces: Allman diff --git a/examples/advanced/loader.cpp b/examples/advanced/loader.cpp index fb416c2..bcfac8e 100644 --- a/examples/advanced/loader.cpp +++ b/examples/advanced/loader.cpp @@ -1,15 +1,18 @@ -#include "loader.hpp" #include "modules/modules.hpp" +#include #include - -namespace UnsafeUDF { -[[nodiscard]] std::shared_ptr init_lib(std::string_view path) { - auto _handle = DynamicLibrary::getLib(path); - auto _mod = DynamicLibrary::getModule(_handle); - - make_udf = _mod._make_udf_m; - init_udf = _mod._init_udf_m; - delete_udf = _mod._delete_udf_m; - return _handle; -} +#include +namespace UnsafeUDF +{ + [[nodiscard]] std::shared_ptr init_lib(std::string_view path) + { + auto _handle = DynamicLibrary::getLib(path); + const auto _mod = + DynamicLibrary::getModule(_handle, &default_module); + std::printf("build tag: %lld\r\n", _mod.build_tag); + make_udf = _mod._make_udf_m; + init_udf = _mod._init_udf_m; + delete_udf = _mod._delete_udf_m; + return _handle; + } } // namespace UnsafeUDF diff --git a/examples/advanced/loader.hpp b/examples/advanced/loader.hpp index 51134b6..ff43c49 100644 --- a/examples/advanced/loader.hpp +++ b/examples/advanced/loader.hpp @@ -1,12 +1,13 @@ #ifndef LOADER_HPP #define LOADER_HPP -#include #include +#include #include -namespace UnsafeUDF { - [[nodiscard]] std::shared_ptr init_lib(std::string_view path); +namespace UnsafeUDF +{ + [[nodiscard]] std::shared_ptr init_lib(std::string_view path); } #endif diff --git a/examples/advanced/main.cpp b/examples/advanced/main.cpp index a8dda0e..b354c06 100644 --- a/examples/advanced/main.cpp +++ b/examples/advanced/main.cpp @@ -1,30 +1,35 @@ +#include "loader.hpp" #include "modules/modules.hpp" #include #include #include #include -#include "loader.hpp" #define LOAD_LIB(name) auto _ = UnsafeUDF::init_lib(name); -int exec() { +int exec() +{ Model m; - m.init(42); return 0; } -int main(int argc, char **argv) { +int main(int argc, char** argv) +{ std::string_view arg0; - if (argc == 2) { + if (argc == 2) + { arg0 = argv[1]; - try { + try + { LOAD_LIB(arg0); return exec(); - } catch (...) { + } + catch (...) + { std::cerr << "Not default provided and library is not available: early return " << std::endl; diff --git a/examples/advanced/modules/default_lib.cpp b/examples/advanced/modules/default_lib.cpp index 74e4a38..8a6ac6d 100644 --- a/examples/advanced/modules/default_lib.cpp +++ b/examples/advanced/modules/default_lib.cpp @@ -1,27 +1,31 @@ #include "modules.hpp" #include -struct impl { - +struct impl +{ }; +static void _init_udf(impl&, int a) +{ + std::cout << "a=" << a << std::endl; +} -static void _init_udf(impl &, int a) { std::cout << "a=" << a << std::endl; } - -static void _make_udf(Model &model) { model.pimpl = new impl; } +static void _make_udf(Model& model) +{ + model.pimpl = new impl; +} -static void _delete_udf(impl **pimpl) { - if (pimpl != nullptr) { +static void _delete_udf(impl** pimpl) +{ + if (pimpl != nullptr) + { delete *pimpl; *pimpl = nullptr; } } - #ifdef DEFAULT_MODULE -EXPORT_MODULE(default_module,&_init_udf, &_make_udf, - &_delete_udf); +EXPORT_MODULE(default_module, &_init_udf, &_make_udf, &_delete_udf); #else -EXPORT_MODULE(module,&_init_udf, &_make_udf, - &_delete_udf); +EXPORT_MODULE(module, &_init_udf, &_make_udf, &_delete_udf); #endif diff --git a/examples/advanced/modules/external_module.cpp b/examples/advanced/modules/external_module.cpp index b75a64b..12b08eb 100644 --- a/examples/advanced/modules/external_module.cpp +++ b/examples/advanced/modules/external_module.cpp @@ -1,23 +1,26 @@ #include "modules.hpp" #include -struct impl { +struct impl +{ int a; }; -void _init_udf(impl &pimpl, int a) { +void _init_udf(impl& pimpl, int a) +{ std::cout << "Hello from dynamically loaded object" << std::endl; std::cout << "internal data: " << pimpl.a << std::endl; } -void _make_udf(Model &model) { +void _make_udf(Model& model) +{ model.pimpl = new impl; model.pimpl->a = 11272024; } -// This macro can be used for trivial desctruction -// This declare de _delete_udf function +// This macro can be used for trivial destruction +// This declare _delete_udf function DECLARE_DELETER(impl) // Don't forget to export the module (and deleter). -EXPORT_MODULE(module,&_init_udf, &_make_udf, &_delete_udf); +EXPORT_MODULE_WITH_TAG(module, 1, &_init_udf, &_make_udf, &_delete_udf); diff --git a/examples/advanced/modules/modules.cpp b/examples/advanced/modules/modules.cpp index 280e6f9..942c062 100644 --- a/examples/advanced/modules/modules.cpp +++ b/examples/advanced/modules/modules.cpp @@ -1,20 +1,28 @@ #include "modules.hpp" -namespace UnsafeUDF { -void (*make_udf)(Model &) = nullptr; // Define the pointers -void (*init_udf)(impl &, int) = nullptr; -void (*delete_udf)(impl **) = nullptr; +namespace UnsafeUDF +{ + void (*make_udf)(Model&) = nullptr; // Define the pointers + void (*init_udf)(impl&, int) = nullptr; + void (*delete_udf)(impl**) = nullptr; } // namespace UnsafeUDF -Model::Model() { UnsafeUDF::make_udf(*this); } +Model::Model() +{ + UnsafeUDF::make_udf(*this); +} -void Model::init(int a) { - if (pimpl != nullptr) { +void Model::init(int a) +{ + if (pimpl != nullptr) + { return UnsafeUDF::init_udf(*pimpl, a); } } -Model::~Model() { - if (pimpl != nullptr) { +Model::~Model() +{ + if (pimpl != nullptr) + { UnsafeUDF::delete_udf(&pimpl); } } diff --git a/examples/advanced/modules/modules.hpp b/examples/advanced/modules/modules.hpp index 98085e2..574a38e 100644 --- a/examples/advanced/modules/modules.hpp +++ b/examples/advanced/modules/modules.hpp @@ -5,17 +5,19 @@ struct impl; struct Model; -namespace UnsafeUDF { -extern void (*make_udf)(Model &); -extern void (*init_udf)(impl &, int); -extern void (*delete_udf)(impl **); -} // namespace UsafeUDF - -struct Model { - Model() ; +namespace UnsafeUDF +{ + extern void (*make_udf)(Model&); + extern void (*init_udf)(impl&, int); + extern void (*delete_udf)(impl**); +} // namespace UnsafeUDF + +struct Model +{ + Model(); void init(int a); - ~Model() ; - impl *pimpl = nullptr; + ~Model(); + impl* pimpl = nullptr; }; using init_udf_ptr = decltype(UnsafeUDF::init_udf); @@ -27,5 +29,4 @@ DEFINE_MODULE(MODULE_ITEM(init_udf) MODULE_ITEM(make_udf) EXPORT_DEFAULT - #endif diff --git a/examples/advanced/modules/wrong.cpp b/examples/advanced/modules/wrong.cpp index 9f08a71..655bead 100644 --- a/examples/advanced/modules/wrong.cpp +++ b/examples/advanced/modules/wrong.cpp @@ -2,21 +2,26 @@ #include "modules.hpp" #include -struct impl { +struct impl +{ int a; }; -void _init_udf(impl &pimpl, int a) { +void _init_udf(impl& pimpl, int a) +{ std::cout << "A=" << pimpl.a << std::endl; } -void _make_udf(Model &model) { +void _make_udf(Model& model) +{ model.pimpl = new impl; model.pimpl->a = 56; } -void _delete_udf(impl **pimpl) { - if (pimpl != nullptr) { +void _delete_udf(impl** pimpl) +{ + if (pimpl != nullptr) + { delete *pimpl; *pimpl = nullptr; } diff --git a/examples/basic/main.cpp b/examples/basic/main.cpp index 82d08f3..30f3f76 100644 --- a/examples/basic/main.cpp +++ b/examples/basic/main.cpp @@ -2,7 +2,8 @@ #include #include -int exec(std::shared_ptr handle) { +int exec(std::shared_ptr handle) +{ // Try to retrieve the module from the loaded library. // If the module is not found, use the default module provided by // default_module. @@ -13,11 +14,12 @@ int exec(std::shared_ptr handle) { foo_ptr f = _mod._foo_m; // Print the addresses of the current function and the default function. - std::cout << "Current function address " << (void *)f << std::endl; - std::cout << "Default function address " << (void *)default_module._foo_m + std::cout << "Current function address " << (void*)f << std::endl; + std::cout << "Default function address " << (void*)default_module._foo_m << std::endl; - if (f == default_module._foo_m) { + if (f == default_module._foo_m) + { std::cout << "Using default implementation" << std::endl; } // Call the function pointer "f" with arguments 1234 and 1 and print the @@ -26,11 +28,13 @@ int exec(std::shared_ptr handle) { return (f(1, 1) == 20) ? 0 : -1; } -int main(int argc, char **argv) { +int main(int argc, char** argv) +{ std::shared_ptr _handle; - if (argc == 2) { + if (argc == 2) + { std::cout << "Loading " << argv[1] << std::endl; _handle = DynamicLibrary::getLib(argv[1]); } diff --git a/examples/basic/modules/default_lib.cpp b/examples/basic/modules/default_lib.cpp index 2dd3b92..ce823f6 100644 --- a/examples/basic/modules/default_lib.cpp +++ b/examples/basic/modules/default_lib.cpp @@ -1,16 +1,24 @@ -#include "modules.hpp" +#include "modules.hpp" #include -// Declaration and implementation of default_foo function which returns the sum of its two arguments. -int default_foo(int a, int b) { return a + b; } +// Declaration and implementation of default_foo function which returns the sum +// of its two arguments. +int default_foo(int a, int b) +{ + return a + b; +} -// Declaration and implementation of default_bar function which returns the product of its argument and 16. -int default_bar(int a) { return a * 16; } +// Declaration and implementation of default_bar function which returns the +// product of its argument and 16. +int default_bar(int a) +{ + return a * 16; +} #ifdef DEFAULT_MODULE // If DEFAULT_MODULE is defined, create a Module object named default_module // containing pointers to default_foo and default_bar functions. -EXPORT_MODULE(default_module,&default_foo, &default_bar); +EXPORT_MODULE(default_module, &default_foo, &default_bar); #else -EXPORT_MODULE(module,&default_foo, &default_bar); -#endif +EXPORT_MODULE(module, &default_foo, &default_bar); +#endif diff --git a/examples/basic/modules/external_module.cpp b/examples/basic/modules/external_module.cpp index be30587..4f1f186 100644 --- a/examples/basic/modules/external_module.cpp +++ b/examples/basic/modules/external_module.cpp @@ -1,13 +1,22 @@ -#include "dynlib/dyn_module.hpp" #include "modules.hpp" +#include // It's possible to declare "private" functions. -int baz() { return 10; } +int baz() +{ + return 10; +} // Declaration and implementation of the function to be exported. -int foo(int a, int b) { return baz() * (a + b); } +int foo(int a, int b) +{ + return baz() * (a + b); +} -int bar(int a) { return a * 16 * 2; } +int bar(int a) +{ + return a * 16 * 2; +} // Don't forget to export the module. EXPORT_MODULE(module, ._foo_m = &foo, ._bar_m = &bar); diff --git a/examples/basic/modules/modules.hpp b/examples/basic/modules/modules.hpp index 6e581de..f6c00b8 100644 --- a/examples/basic/modules/modules.hpp +++ b/examples/basic/modules/modules.hpp @@ -6,12 +6,8 @@ using foo_ptr = int (*)(int, int); using bar_ptr = int (*)(int); +DEFINE_MODULE(MODULE_ITEM(foo) MODULE_ITEM(bar)) -DEFINE_MODULE( - MODULE_ITEM(foo) - MODULE_ITEM(bar) -) - -EXPORT_DEFAULT +EXPORT_DEFAULT #endif diff --git a/examples/basic/modules/wrong.cpp b/examples/basic/modules/wrong.cpp index ebebd4a..b433d65 100644 --- a/examples/basic/modules/wrong.cpp +++ b/examples/basic/modules/wrong.cpp @@ -1,11 +1,20 @@ #include "modules.hpp" // It's possible to declare "private" functions. -int baz() { return 10; } +int baz() +{ + return 10; +} // Declaration and implementation of the function to be exported. -int foo(int a, int b) { return baz() * (a + b); } +int foo(int a, int b) +{ + return baz() * (a + b); +} -int bar(int a) { return a * 16 * 2; } +int bar(int a) +{ + return a * 16 * 2; +} -//function defined but not exported \ No newline at end of file +// function defined but not exported \ No newline at end of file diff --git a/meson.build b/meson.build index b1c5c53..7eefbec 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'dynamic-library', 'cpp', - version: '1.0', + version: '1.1', default_options: ['warning_level=3', 'cpp_std=gnu++20'], ) compiler = meson.get_compiler('cpp') diff --git a/public/dynlib/dyn_module.hpp b/public/dynlib/dyn_module.hpp index b192c6c..398a8e3 100644 --- a/public/dynlib/dyn_module.hpp +++ b/public/dynlib/dyn_module.hpp @@ -16,16 +16,17 @@ template using FuncPtr = Func *; } #if defined(WIN32) || defined(WIN64) - #define _EXPOSE_CST_SYMBOL_FROM_SO \ - extern const __declspec(dllexport) +#define _EXPOSE_CST_SYMBOL_FROM_SO extern const __declspec(dllexport) #else - #define _EXPOSE_CST_SYMBOL_FROM_SO \ +#define _EXPOSE_CST_SYMBOL_FROM_SO \ extern const __attribute__((visibility("default"))) -#endif +#endif +#define EXPORT_MODULE_WITH_TAG(__name__, __tag__, ...) \ + _EXPOSE_CST_SYMBOL_FROM_SO Module __name__ = {__VA_ARGS__, __tag__}; #define EXPORT_MODULE(__name__, ...) \ - _EXPOSE_CST_SYMBOL_FROM_SO Module __name__ = {__VA_ARGS__} + EXPORT_MODULE_WITH_TAG(__name__, , __VA_ARGS__) // Macro to define a pointer to a module item (function or variable). #define MODULE_ITEM(name) name##_ptr _##name##_m = nullptr; @@ -36,12 +37,13 @@ template using FuncPtr = Func *; #define EXPORT_DEFAULT #endif -#define DECLARE_MODULE(__name__) _EXPOSE_CST_SYMBOL_FROM_SO Module __name__ +#define DECLARE_MODULE(__name__) _EXPOSE_CST_SYMBOL_FROM_SO Module __name__; // Macro to define a module structure containing provided items. #define DEFINE_MODULE(...) \ typedef struct Module { \ __VA_ARGS__ \ + long long build_tag = 0; \ } *ImportedModule; #endif diff --git a/public/dynlib/dynlib.hpp b/public/dynlib/dynlib.hpp index 72e66b7..a90c83d 100644 --- a/public/dynlib/dynlib.hpp +++ b/public/dynlib/dynlib.hpp @@ -34,14 +34,14 @@ class DynamicLibrary { * @param fname The name of the item. * @return T The retrieved item. */ - template T* getItem(std::string_view fname); + template T *getItem(std::string_view fname); // Destructor ~DynamicLibrary() = default; - DynamicLibrary(DynamicLibrary&&) = delete; - DynamicLibrary(const DynamicLibrary&) = delete; - DynamicLibrary& operator=(const DynamicLibrary&)=delete; - DynamicLibrary& operator=(DynamicLibrary&&)=delete; + DynamicLibrary(DynamicLibrary &&) = delete; + DynamicLibrary(const DynamicLibrary &) = delete; + DynamicLibrary &operator=(const DynamicLibrary &) = delete; + DynamicLibrary &operator=(DynamicLibrary &&) = delete; /** * @brief Retrieves a dynamic library object given its path. @@ -117,9 +117,9 @@ class DynamicLibrary::Impl { * @param fname The name of the function. * @return T The retrieved function. */ - template T* getFunction(std::string_view fname) { + template T *getFunction(std::string_view fname) { void *symbol = dlsym(handle, std::string(fname).c_str()); - T* f = static_cast(symbol); + T *f = static_cast(symbol); return f; } @@ -162,9 +162,9 @@ class DynamicLibrary::Impl { * @param fname The name of the function. * @return T The retrieved function. */ - template T* getFunction(std::string_view fname) { + template T *getFunction(std::string_view fname) { FARPROC symbol = GetProcAddress(handle, fname.data()); - return reinterpret_cast(symbol); + return reinterpret_cast(symbol); } // Destructor @@ -183,11 +183,12 @@ class DynamicLibrary::Impl { // Implementation of getModule for DynamicLibrary class template ModuleType DynamicLibrary::getModule(std::shared_ptr lib_handle, - ModuleType* _def, + ModuleType *_def, std::string_view modulename) { if (!lib_handle) { if (!_def) { - throw std::runtime_error("Library is not loaded correctly and no default one is provided"); + throw std::runtime_error( + "Library is not loaded correctly and no default one is provided"); } std::cerr << "Library not loaded, using default module" << std::endl; return *_def; // Return default module @@ -195,14 +196,14 @@ ModuleType DynamicLibrary::getModule(std::shared_ptr lib_handle, auto sym = lib_handle->getItem(modulename); - if (sym) { return *sym; // Return the module found in the library } // Handle case where symbol is not found if (!_def) { - throw std::runtime_error("Cannot find required symbol and no default one is provided"); + throw std::runtime_error( + "Cannot find required symbol and no default one is provided"); } std::cerr << "Symbol not found, using default implementation" << std::endl; @@ -210,7 +211,7 @@ ModuleType DynamicLibrary::getModule(std::shared_ptr lib_handle, } // Implementation of getItem for DynamicLibrary class -template T* DynamicLibrary::getItem(std::string_view fname) { +template T *DynamicLibrary::getItem(std::string_view fname) { if (!_impl) { throw std::runtime_error("DynamicLibrary is not initialized properly"); }