diff --git a/.github/workflows/cpp.yml b/.github/workflows/cpp.yml
index df761b2..fc018c5 100644
--- a/.github/workflows/cpp.yml
+++ b/.github/workflows/cpp.yml
@@ -41,4 +41,5 @@ jobs:
make
make external_module
cd build
- ./main
+ ./main external_module.so
+
diff --git a/.gitignore b/.gitignore
index 6f46744..19c02f1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,7 @@
-**/build
\ No newline at end of file
+**/build
+
+**/builddir
+
+# LSP
+.cache/
+compile_commands.json
diff --git a/README.md b/README.md
index 8014d7e..8eab38d 100644
--- a/README.md
+++ b/README.md
@@ -1,30 +1,46 @@
# Dynamic Library Loader
+
- [](LICENSE)
+[](LICENSE)
+
This repository provides a dynamic library loader, serving as a header-only library. It offers a wrapper around OS-specific API shared object loading, enabling seamless integration into your projects. Additionally, it includes a header file to establish a standardized method for defining modules using macros.
-# Features
+
+
+- [Dynamic Library Loader](#dynamic-library-loader)
+- [Features](#features)
+- [Usage](#usage)
+ - [For Module Definition](#for-module-definition)
+ - [For the External Library](#for-the-external-library)
+ - [Example](#example)
+- [License](#license)
+
+
+# Features
- OS-Specific API Wrapper: Simplifies the process of loading shared objects by providing a unified interface across different operating systems.
- Standardized Module Definition: The included header file enables developers to define modules using macros, ensuring consistency and ease of use.
-- Cross-Platform Compatibility: Works seamlessly across various operating systems, allowing developers to write code without worrying about platform-specific nuances.
-
+- Cross-Platform Compatibility: Works seamlessly across various operating systems,
+ allowing developers to write code without worrying about platform-specific nuances.
# Usage
-An example is provided in "../examples"
+An example is provided in "./examples"
-## For Module Definition:
+## For Module Definition
-1. **Include Header:** Include the `` header file to access macro definitions.
+1. **Include Header:**
+ Include the `` header file to access macro definitions.
-2. **Define Module Header:** Define a header for your module, outlining the signature of the functions that need to be exported to the application. Create a "module" structure containing function pointers corresponding to the defined function signatures.
+2. **Define Module Header:**
+ Define a header for your module, outlining the signature of the functions that need to be exported to the application.
+ Create a "module" structure containing function pointers corresponding to the defined function signatures.
-## For the External Library:
+## For the External Library
1. **Include Module Header:** Include the header file of your module.
@@ -32,7 +48,10 @@ An example is provided in "../examples"
3. **Create Global Variable:** Create a global variable named `module` with function pointers pointing to the functions you've implemented and need to export. You can include "private" functions within the module that are not included in the module definition.
-## Example:
+IMPORTANT: External modules should, by default, be compiled with the -fvisibility=hidden flag (or its equivalent). This flag prevents symbols from being exported from the object file, reducing the risk of name conflicts—an issue that can be challenging to debug.
+Only the Module itself is exported, and this is achieved via a specific macro.
+
+## Example
An example is provided to demonstrate the usage. From the application's perspective (Loader):
@@ -44,10 +63,8 @@ An example is provided to demonstrate the usage. From the application's perspect
4. **Retrieve Imported Module:** Retrieve the imported module.
-*Note: If the module's name isn't specified, it is assumed that the external library developer followed the naming conventions given in the header. If not, you can use a custom module name and typename to define the struct manually.*
-
-
+_Note: If the module's name isn't specified, it is assumed that the external library developer followed the naming conventions given in the header. If not, you can use a custom module name and type name to define the structure manually._
# License
-This project is licensed under the MIT License, allowing for unrestricted use, modification, and distribution. Please review the LICENSE file for detailed licensing terms.
\ No newline at end of file
+This project is licensed under the MIT License, allowing for unrestricted use, modification, and distribution. Please review the LICENSE file for detailed licensing terms.
diff --git a/examples/advanced/loader.cpp b/examples/advanced/loader.cpp
new file mode 100644
index 0000000..fb416c2
--- /dev/null
+++ b/examples/advanced/loader.cpp
@@ -0,0 +1,15 @@
+#include "loader.hpp"
+#include "modules/modules.hpp"
+#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;
+}
+} // namespace UnsafeUDF
diff --git a/examples/advanced/loader.hpp b/examples/advanced/loader.hpp
new file mode 100644
index 0000000..51134b6
--- /dev/null
+++ b/examples/advanced/loader.hpp
@@ -0,0 +1,12 @@
+#ifndef LOADER_HPP
+#define LOADER_HPP
+#include
+#include
+
+#include
+
+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
new file mode 100644
index 0000000..a8dda0e
--- /dev/null
+++ b/examples/advanced/main.cpp
@@ -0,0 +1,34 @@
+#include "modules/modules.hpp"
+#include
+#include
+#include
+#include
+#include "loader.hpp"
+
+#define LOAD_LIB(name) auto _ = UnsafeUDF::init_lib(name);
+
+int exec() {
+
+ Model m;
+
+ m.init(42);
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ std::string_view arg0;
+
+ if (argc == 2) {
+ arg0 = argv[1];
+ try {
+
+ LOAD_LIB(arg0);
+ return exec();
+ } catch (...) {
+ std::cerr
+ << "Not default provided and library is not available: early return "
+ << std::endl;
+ }
+ }
+ return -1;
+}
diff --git a/examples/advanced/meson.build b/examples/advanced/meson.build
new file mode 100644
index 0000000..09da369
--- /dev/null
+++ b/examples/advanced/meson.build
@@ -0,0 +1,44 @@
+library(
+ 'wrong',
+ 'modules/wrong.cpp',
+ dependencies: dynlib_dep,
+ pic: true,
+ gnu_symbol_visibility: 'hidden',
+ cpp_args: ['-DDEFAULT_MODULE'],
+)
+
+library(
+ 'external',
+ 'modules/external_module.cpp',
+ dependencies: dynlib_dep,
+ pic: true,
+ gnu_symbol_visibility: 'hidden',
+ cpp_args: ['-DDEFAULT_MODULE'],
+)
+
+default = library(
+ 'default',
+ 'modules/default_lib.cpp',
+ dependencies: dynlib_dep,
+ pic: true,
+ gnu_symbol_visibility: 'hidden',
+ cpp_args: ['-DDEFAULT_MODULE'],
+)
+
+model = library(
+ 'model',
+ 'modules/modules.cpp',
+ dependencies: dynlib_dep,
+ pic: true,
+ gnu_symbol_visibility: 'hidden',
+ cpp_args: ['-DDEFAULT_MODULE'],
+)
+
+executable(
+ 'example',
+ 'main.cpp',
+ 'loader.cpp','modules/modules.cpp',
+ link_with: [default,model],
+ dependencies: dynlib_dep,
+ cpp_args: ['-DDEFAULT_MODULE'],
+)
diff --git a/examples/advanced/modules/default_lib.cpp b/examples/advanced/modules/default_lib.cpp
new file mode 100644
index 0000000..74e4a38
--- /dev/null
+++ b/examples/advanced/modules/default_lib.cpp
@@ -0,0 +1,27 @@
+#include "modules.hpp"
+#include
+
+struct impl {
+
+};
+
+
+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 _delete_udf(impl **pimpl) {
+ if (pimpl != nullptr) {
+ delete *pimpl;
+ *pimpl = nullptr;
+ }
+}
+
+
+#ifdef DEFAULT_MODULE
+EXPORT_MODULE(default_module,&_init_udf, &_make_udf,
+ &_delete_udf);
+#else
+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
new file mode 100644
index 0000000..b75a64b
--- /dev/null
+++ b/examples/advanced/modules/external_module.cpp
@@ -0,0 +1,23 @@
+#include "modules.hpp"
+#include
+
+struct impl {
+ 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) {
+ model.pimpl = new impl;
+ model.pimpl->a = 11272024;
+}
+
+// This macro can be used for trivial desctruction
+// This declare de _delete_udf function
+DECLARE_DELETER(impl)
+
+// Don't forget to export the module (and deleter).
+EXPORT_MODULE(module,&_init_udf, &_make_udf, &_delete_udf);
diff --git a/examples/advanced/modules/modules.cpp b/examples/advanced/modules/modules.cpp
new file mode 100644
index 0000000..280e6f9
--- /dev/null
+++ b/examples/advanced/modules/modules.cpp
@@ -0,0 +1,20 @@
+#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
+
+Model::Model() { UnsafeUDF::make_udf(*this); }
+
+void Model::init(int a) {
+ if (pimpl != nullptr) {
+ return UnsafeUDF::init_udf(*pimpl, a);
+ }
+}
+Model::~Model() {
+ if (pimpl != nullptr) {
+ UnsafeUDF::delete_udf(&pimpl);
+ }
+}
diff --git a/examples/advanced/modules/modules.hpp b/examples/advanced/modules/modules.hpp
new file mode 100644
index 0000000..98085e2
--- /dev/null
+++ b/examples/advanced/modules/modules.hpp
@@ -0,0 +1,31 @@
+#ifndef __MYMODULE_HPP__
+#define __MYMODULE_HPP__
+#include
+
+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() ;
+ void init(int a);
+ ~Model() ;
+ impl *pimpl = nullptr;
+};
+
+using init_udf_ptr = decltype(UnsafeUDF::init_udf);
+using make_udf_ptr = decltype(UnsafeUDF::make_udf);
+using delete_udf_ptr = decltype(UnsafeUDF::delete_udf);
+
+DEFINE_MODULE(MODULE_ITEM(init_udf) MODULE_ITEM(make_udf)
+ MODULE_ITEM(delete_udf))
+
+EXPORT_DEFAULT
+
+
+#endif
diff --git a/examples/advanced/modules/wrong.cpp b/examples/advanced/modules/wrong.cpp
new file mode 100644
index 0000000..9f08a71
--- /dev/null
+++ b/examples/advanced/modules/wrong.cpp
@@ -0,0 +1,26 @@
+
+#include "modules.hpp"
+#include
+
+struct impl {
+ int a;
+};
+
+void _init_udf(impl &pimpl, int a) {
+ std::cout << "A=" << pimpl.a << std::endl;
+}
+
+void _make_udf(Model &model) {
+ model.pimpl = new impl;
+ model.pimpl->a = 56;
+}
+
+void _delete_udf(impl **pimpl) {
+ if (pimpl != nullptr) {
+ delete *pimpl;
+ *pimpl = nullptr;
+ }
+}
+
+// Don't forget to export the module.
+// Module module = {&_init_udf, &_make_udf, &_delete_udf};
diff --git a/examples/basic/main.cpp b/examples/basic/main.cpp
new file mode 100644
index 0000000..82d08f3
--- /dev/null
+++ b/examples/basic/main.cpp
@@ -0,0 +1,39 @@
+#include "modules/modules.hpp"
+#include
+#include
+
+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.
+ Module _mod = DynamicLibrary::getModule(handle, &default_module);
+
+ // Retrieve the function pointer to the function named "_foo_m" from the
+ // module.
+ 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::endl;
+
+ 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
+ // result.
+ std::cout << f(1234, 1) << std::endl;
+ return (f(1, 1) == 20) ? 0 : -1;
+}
+
+int main(int argc, char **argv) {
+
+ std::shared_ptr _handle;
+
+ if (argc == 2) {
+ std::cout << "Loading " << argv[1] << std::endl;
+ _handle = DynamicLibrary::getLib(argv[1]);
+ }
+
+ return exec(_handle);
+}
diff --git a/examples/basic/meson.build b/examples/basic/meson.build
new file mode 100644
index 0000000..16008fb
--- /dev/null
+++ b/examples/basic/meson.build
@@ -0,0 +1,23 @@
+wrong = library('wrong',
+'modules/wrong.cpp',
+dependencies:dynlib_dep,
+pic:true,
+gnu_symbol_visibility: 'hidden',
+cpp_args:['-DDEFAULT_MODULE'])
+
+external = library('external','modules/external_module.cpp',
+dependencies:dynlib_dep,
+pic:true,
+gnu_symbol_visibility: 'hidden',
+cpp_args:['-DDEFAULT_MODULE'])
+
+
+default = library('default','modules/default_lib.cpp',
+dependencies:dynlib_dep,pic:true,
+gnu_symbol_visibility:
+'hidden',cpp_args:['-DDEFAULT_MODULE'])
+
+basic_examples = executable('example','main.cpp',
+link_with:default,
+dependencies:dynlib_dep,
+cpp_args:['-DDEFAULT_MODULE'])
diff --git a/examples/modules/default_lib.cpp b/examples/basic/modules/default_lib.cpp
similarity index 78%
rename from examples/modules/default_lib.cpp
rename to examples/basic/modules/default_lib.cpp
index 15ded34..2dd3b92 100644
--- a/examples/modules/default_lib.cpp
+++ b/examples/basic/modules/default_lib.cpp
@@ -1,4 +1,5 @@
#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; }
@@ -9,7 +10,7 @@ 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.
-Module default_module = {&default_foo, &default_bar};
+EXPORT_MODULE(default_module,&default_foo, &default_bar);
#else
-Module module = {._foo_m = &default_foo, ._bar_m = &default_bar};
+EXPORT_MODULE(module,&default_foo, &default_bar);
#endif
diff --git a/examples/modules/external_module.cpp b/examples/basic/modules/external_module.cpp
similarity index 77%
rename from examples/modules/external_module.cpp
rename to examples/basic/modules/external_module.cpp
index 92d3a70..be30587 100644
--- a/examples/modules/external_module.cpp
+++ b/examples/basic/modules/external_module.cpp
@@ -1,3 +1,4 @@
+#include "dynlib/dyn_module.hpp"
#include "modules.hpp"
// It's possible to declare "private" functions.
@@ -9,8 +10,7 @@ int foo(int a, int b) { return baz() * (a + b); }
int bar(int a) { return a * 16 * 2; }
// Don't forget to export the module.
-Module module = {._foo_m = &foo, ._bar_m = &bar};
-
+EXPORT_MODULE(module, ._foo_m = &foo, ._bar_m = &bar);
/* We could define the default module as described in modules.hpp,
but in our case, this external module will never be used as a default module,
-so the definition doesn't exist. */
\ No newline at end of file
+so the definition doesn't exist. */
diff --git a/examples/modules/modules.hpp b/examples/basic/modules/modules.hpp
similarity index 84%
rename from examples/modules/modules.hpp
rename to examples/basic/modules/modules.hpp
index cde4d08..6e581de 100644
--- a/examples/modules/modules.hpp
+++ b/examples/basic/modules/modules.hpp
@@ -1,7 +1,7 @@
#ifndef __MYMODULE_HPP__
#define __MYMODULE_HPP__
-#include "../../lib/dyn_module.hpp"
+#include
using foo_ptr = int (*)(int, int);
using bar_ptr = int (*)(int);
diff --git a/examples/basic/modules/wrong.cpp b/examples/basic/modules/wrong.cpp
new file mode 100644
index 0000000..ebebd4a
--- /dev/null
+++ b/examples/basic/modules/wrong.cpp
@@ -0,0 +1,11 @@
+#include "modules.hpp"
+
+// It's possible to declare "private" functions.
+int baz() { return 10; }
+
+// Declaration and implementation of the function to be exported.
+int foo(int a, int b) { return baz() * (a + b); }
+
+int bar(int a) { return a * 16 * 2; }
+
+//function defined but not exported
\ No newline at end of file
diff --git a/examples/main.cpp b/examples/main.cpp
deleted file mode 100644
index 193b744..0000000
--- a/examples/main.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-#include "modules/modules.hpp"
-#include
-#include
-
-int main() {
- // Attempt to load the dynamic library "./external_module.so" and get a handle
- // to it.
- auto _handle = DynamicLibrary::getLib("./external_module.so");
-
- // Try to retrieve the module from the loaded library.
- // If the module is not found, use the default module provided by
- // default_module.
- Module _mod = DynamicLibrary::getModule(_handle, &default_module);
-
- // Retrieve the function pointer to the function named "_foo_m" from the
- // module.
- foo_ptr f = _mod._foo_m;
-
- // Obtain the addresses of the retrieved function and the default function
- // "_bar_m".
- int *addr1 = (int *)f;
- int *addr2 = (int *)default_module._bar_m;
-
- // Print the addresses of the current function and the default function.
- printf("Current function address %p\n", f);
- printf("Default function address %p\n", default_module._bar_m);
-
- // Call the function pointer "f" with arguments 1234 and 1 and print the
- // result.
- std::cout << f(1234, 1) << std::endl;
- return (f(1, 1) == 20) ? 0 : -1;
-}
diff --git a/examples/makefile b/examples/makefile
index 77cac51..61a7e5e 100644
--- a/examples/makefile
+++ b/examples/makefile
@@ -1,7 +1,7 @@
.PHONY: all clean external_module
BUILD_DIR=./build
-INCLUDE_DIR=../lib
+INCLUDE_DIR=../public
all: dir main
@@ -9,13 +9,16 @@ dir:
mkdir -p ${BUILD_DIR}
default:
- g++ -shared -I${INCLUDE_DIR} -fPIC ./modules/default_lib.cpp -o ${BUILD_DIR}/libmodule1.so -DDEFAULT_MODULE
+ g++ -shared -fvisibility=hidden -I${INCLUDE_DIR} -fPIC ./basic/modules/default_lib.cpp -o ${BUILD_DIR}/libmodule1.so -DDEFAULT_MODULE
external_module:
- g++ -shared -fPIC ./modules/external_module.cpp -o ${BUILD_DIR}/external_module.so -I${INCLUDE_DIR}
+ g++ -shared -fvisibility=hidden -fPIC ./basic/modules/external_module.cpp -o ${BUILD_DIR}/external_module.so -I${INCLUDE_DIR}
main: default
- g++ main.cpp -I${INCLUDE_DIR} -fPIC -L${BUILD_DIR} -lmodule1 -o ${BUILD_DIR}/main -Wl,-rpath=$(PWD)/${BUILD_DIR} -DDEFAULT_MODULE
+ g++ basic/main.cpp -fvisibility=hidden -I${INCLUDE_DIR} -fPIC -L${BUILD_DIR} -lmodule1 -o ${BUILD_DIR}/main -Wl,-rpath=$(PWD)/${BUILD_DIR} -DDEFAULT_MODULE
clean:
rm -rf ${BUILD_DIR}
+
+run:
+ ${BUILD_DIR}/main
diff --git a/examples/meson.build b/examples/meson.build
new file mode 100644
index 0000000..1df504d
--- /dev/null
+++ b/examples/meson.build
@@ -0,0 +1,7 @@
+
+
+
+subdir('basic')
+
+
+subdir('advanced')
diff --git a/lib/dyn_module.hpp b/lib/dyn_module.hpp
deleted file mode 100644
index 6942165..0000000
--- a/lib/dyn_module.hpp
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef __DYN_MODULE_HPP__
-#define __DYN_MODULE_HPP__
-
-#ifdef DEFAULT_MODULE
-// If DEFAULT_MODULE is defined, EXPORT is defined as 'extern'.
-#define EXPORT extern
-#define EXPORT_DEFAULT EXPORT Module default_module;
-#else
-// If DEFAULT_MODULE is not defined, EXPORT is defined as 'extern "C"'.
-#define EXPORT extern "C"
-#define EXPORT_DEFAULT
-#endif
-
-// Template alias for function pointers.
-template using FuncPtr = Func *;
-
-// Macro to define a type alias for a function pointer.
-#define USING_TYPE(func) using func##_ptr = FuncPtr;
-
-// Macro to define a pointer to a module item (function or variable).
-#define MODULE_ITEM(name) name##_ptr _##name##_m = nullptr;
-
-// Macro to define a module structure containing provided items.
-#define DEFINE_MODULE(...) typedef struct Module {\
- __VA_ARGS__ \
-} *ImportedModule;
-
-
-
-#endif
diff --git a/meson.build b/meson.build
new file mode 100644
index 0000000..43d6d80
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,12 @@
+project(
+ 'dynamic-library',
+ 'cpp',
+ version: '1.0',
+ default_options: ['warning_level=3', 'cpp_std=gnu++20'],
+)
+
+shared_include = include_directories('../public')
+
+dynlib_dep = declare_dependency(include_directories: shared_include)
+
+subdir('examples')
diff --git a/public/dynlib/dyn_module.hpp b/public/dynlib/dyn_module.hpp
new file mode 100644
index 0000000..b192c6c
--- /dev/null
+++ b/public/dynlib/dyn_module.hpp
@@ -0,0 +1,47 @@
+#ifndef __DYN_MODULE_HPP__
+#define __DYN_MODULE_HPP__
+
+// Template alias for function pointers.
+template using FuncPtr = Func *;
+
+// Macro to define a type alias for a function pointer.
+#define USING_TYPE(func) using func##_ptr = FuncPtr;
+
+#define DECLARE_DELETER(__typename__) \
+ void _delete_udf(__typename__ **pimpl) { \
+ if (pimpl != nullptr) { \
+ delete *pimpl; /*NOLINT*/ \
+ *pimpl = nullptr; \
+ } \
+ }
+
+#if defined(WIN32) || defined(WIN64)
+ #define _EXPOSE_CST_SYMBOL_FROM_SO \
+ extern const __declspec(dllexport)
+#else
+ #define _EXPOSE_CST_SYMBOL_FROM_SO \
+ extern const __attribute__((visibility("default")))
+#endif
+
+
+#define EXPORT_MODULE(__name__, ...) \
+ _EXPOSE_CST_SYMBOL_FROM_SO Module __name__ = {__VA_ARGS__}
+
+// Macro to define a pointer to a module item (function or variable).
+#define MODULE_ITEM(name) name##_ptr _##name##_m = nullptr;
+
+#ifdef DEFAULT_MODULE
+#define EXPORT_DEFAULT _EXPOSE_CST_SYMBOL_FROM_SO Module default_module;
+#else
+#define EXPORT_DEFAULT
+#endif
+
+#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__ \
+ } *ImportedModule;
+
+#endif
diff --git a/lib/dynlib.hpp b/public/dynlib/dynlib.hpp
similarity index 69%
rename from lib/dynlib.hpp
rename to public/dynlib/dynlib.hpp
index e6f5576..72e66b7 100644
--- a/lib/dynlib.hpp
+++ b/public/dynlib/dynlib.hpp
@@ -1,10 +1,12 @@
/**
* @file dynlib.hpp
- * @brief Defines the DynamicLibrary class for loading and accessing symbols from dynamic libraries.
+ * @brief Defines the DynamicLibrary class for loading and accessing symbols
+ * from dynamic libraries.
*
- * This file provides the declaration of the DynamicLibrary class, which encapsulates functionality
- * for loading dynamic libraries and retrieving symbols from them. It also includes necessary headers
- * and type definitions required for the class implementation.
+ * This file provides the declaration of the DynamicLibrary class, which
+ * encapsulates functionality for loading dynamic libraries and retrieving
+ * symbols from them. It also includes necessary headers and type definitions
+ * required for the class implementation.
*
* @author CASALE Benjamin
* @date 08/03/2024
@@ -13,6 +15,7 @@
#ifndef __DYNLIB_HPP__
#define __DYNLIB_HPP__
+#include
#include
#include
#include
@@ -26,36 +29,39 @@ class DynamicLibrary {
public:
/**
* @brief Retrieves an item from the dynamic library by its name.
- *
+ *
* @tparam T The type of the item to retrieve.
* @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;
/**
* @brief Retrieves a dynamic library object given its path.
- *
+ *
* @param path The path to the dynamic library.
- * @return std::shared_ptr A shared pointer to the dynamic library object.
+ * @return std::shared_ptr A shared pointer to the dynamic
+ * library object.
*/
static std::shared_ptr getLib(std::string_view path) {
try {
- auto lib = new DynamicLibrary(path);
+ auto *lib = new DynamicLibrary(path);
return std::shared_ptr(lib);
} catch (std::exception &e) {
- std::cout<_impl = std::make_unique(path);
}
@@ -84,8 +90,7 @@ class DynamicLibrary {
std::unique_ptr _impl;
};
-
-///LINUX IMPLEMENTATION
+/// LINUX IMPLEMENTATION
#if defined(__linux__)
#include
@@ -94,34 +99,33 @@ class DynamicLibrary::Impl {
public:
/**
* @brief Constructs the implementation object for the dynamic library.
- *
+ *
* @param path The path to the dynamic library.
*/
- Impl(std::string_view path) {
+ explicit Impl(std::string_view path) {
this->handle = dlopen(std::string(path).c_str(), RTLD_NOW);
- if (!handle) {
+ if (handle == nullptr) {
throw std::runtime_error("Library cannot be loaded");
}
}
/**
* @brief Retrieves a function from the dynamic library by its name.
- *
+ *
* @tparam T The type of the function to retrieve.
* @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;
}
// Destructor
~Impl() {
- if (handle) {
+ if (handle != nullptr) {
dlclose(handle);
}
handle = nullptr;
@@ -133,7 +137,6 @@ class DynamicLibrary::Impl {
#endif
-
#if defined(WIN32) || defined(WIN64)
#include
@@ -141,7 +144,7 @@ class DynamicLibrary::Impl {
public:
/**
* @brief Constructs the implementation object for the dynamic library.
- *
+ *
* @param path The path to the dynamic library.
*/
Impl(std::string_view path) {
@@ -154,15 +157,14 @@ class DynamicLibrary::Impl {
/**
* @brief Retrieves a function from the dynamic library by its name.
- *
+ *
* @tparam T The type of the function to retrieve.
* @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
@@ -178,44 +180,37 @@ class DynamicLibrary::Impl {
};
#endif
-
// Implementation of getModule for DynamicLibrary class
template
ModuleType DynamicLibrary::getModule(std::shared_ptr lib_handle,
- ModuleType *_def,
+ ModuleType* _def,
std::string_view modulename) {
- ModuleType _mod;
- //Check if the lib is correclty openned
if (!lib_handle) {
- // if not
if (!_def) {
- // If no default module is provided
- throw std::runtime_error(
- "Library is not loaded correctly and no default one is provided");
- }
- _mod = *_def; // Else we get the default instead of the
- }
- else
- {
- auto sym = lib_handle->getItem(modulename);
- if (!sym) {
- if (!_def) {
- throw std::runtime_error(
- "Cannot find required symbol and no default one is provided");
- } else {
- _mod = *_def; // IF the lib is opened but we can find the wanted symbol we use the defaul;t
- std::cerr<<"Symbol not found, using default implementation"<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");
+ }
+
+ std::cerr << "Symbol not found, using default implementation" << std::endl;
+ return *_def; // Return default module if symbol is not found
}
// 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");
}