martin-olivier / dylib Goto Github PK
View Code? Open in Web Editor NEWC++ cross-platform wrapper around dynamic loading of shared libraries (dll, so, dylib)
Home Page: https://conan.io/center/recipes/dylib
License: MIT License
C++ cross-platform wrapper around dynamic loading of shared libraries (dll, so, dylib)
Home Page: https://conan.io/center/recipes/dylib
License: MIT License
Thanks for the great package. Conan center holds many c++ libraries. https://conan.io/center/ It will be great to publish this package there.
When defining a function with the following:auto printFunction = lib.get_function<void(*)(std::uint8_t, const char*, ...)>("printFunction");
the error appears
MacOS 10.15.7 (Using the dylib.hpp files inside my folder and using the lib.cpp and cmake.txt)
I expected a the function to run from a dylib running on attached to another proccess.
lib.cpp (dynamic_lib.dylib):
#include <iostream>
#include <mach-o/dyld.h>
#include <cstdarg>
int64_t ASLR(int64_t arg1) {
return (_dyld_get_image_vmaddr_slide(0) + arg1);
}
enum colours : std::uint8_t
{
regular,
info,
warn,
error
};
// Define the print function prototype
extern "C" {
void printFunction(std::uint8_t color, const char* message, ...);
}
int main() {
// Calculate the address using ASLR
int64_t address = ASLR(0x100c5ae91);
// Convert the address to a function pointer
auto printFunction = reinterpret_cast<void(*)(std::uint8_t, const char*, ...)>(address);
return 0;
}
main.cpp:
#include <iostream>
#include "dylib.hpp"
int main(int argc, char* argv[]) {
if (argc < 2) {
std::cerr << "Usage: " << argv[0] << " <message>" << std::endl;
return 1;
}
const char* message = argv[1];
try {
// Load the dynamic library
dylib lib("./", "dynamic_lib.dylib");
// Get the printFunction symbol
auto printFunction = lib.get_function<void(*)(std::uint8_t, const char*, ...)>("printFunction");
// Call the function from the dynamic library
printFunction(1, message); //<-- error
} catch (const dylib::exception &ex) {
std::cerr << "Error: " << ex.what() << std::endl;
return 1;
}
return 0;
}
Considering the dylib is going to be attached to another process, those arguments are required. The actual function may not end up working, and I may need to use IPC. Regardless, I don't know how to fix this error.
In the README, you specify that the file extension dylib looks for to load macOS shared modules is .dylib
.
Unfortunately, there seems to be a mixture of uses of both .dylib
and .so
for these kinds of shared objects in macOS.
Interestingly, CMake uses .dylib
for shared libraries, and .so
for shared modules (the kind that are only intended for loading at runtime, and cannot be linked to).
Sample output from building one of my projects with CMake where I have two duplicate libraries, one SHARED
and one MODULE
:
[ 76%] Linking CXX shared library libgbfp.dylib
[ 82%] Linking CXX shared module libgbfpm.so
See also this CMake issue: https://gitlab.kitware.com/cmake/cmake/-/issues/21189
I feel like the best solution may be to check for both extensions on macOS. What do you think?
The exception class inherits directly from std::exception
. But - your exceptions seem to be either runtime errors (file not found), or invalid arguments (e.g. passing a null extension) etc. So, inherit from the appropriate standard exception class. That would also remove the need for the base class with the string member - don't reinvent the wheel unless you have to.
C++ has had, for the last 10 years, a standard, cross-platform mechanism for representing system errors: <system_error>
. I believe you should use it instead of your own custom exceptions.
See also:
<system_error> categories and standard/system error codes
on StackOverflow.
At the moment, there are two ways to check whether a library contains a symbol: Trying to get_xxxx
it - which may throw, and requires the type; or get_symbol()
, which doesn't throw, and may return NULL.
I'm not sure the user should even have to know about NULL in order to check for symbol presence.
There are different ways to approach this. One would be returning an optional; another - a contains()
or has()
method which returns a boolean.
Hi there!
In my use case, I need to load multiple dylibs globally at the same time. I want to be able to check if these dylibs have conflicting symbols, so I need a way to list all defined exported symbols to compare them with other libs I want to load.
Something similar can be done using dlinfo on Linux, but I need a cross-platform solution.
What do you think?
The packaging via CPack was gone in 3c748b8 without any words about it, but fix: CMakeLists.txt
. It is unclear if it got gone intentionally or accidentally.
Deleting the copy constructor and the move assignment operator makes it hard to manage the lifetime of dylib
members when working with static constructor-like methods. (When I want to return an error and not throw an exception in the constructor itself)
class HostFXR
{
public:
hostfxr_initialize_for_dotnet_command_line_fn initialize_for_dotnet_command_line_fn{};
hostfxr_initialize_for_runtime_config_fn initialize_for_runtime_config_fn{};
hostfxr_get_runtime_delegate_fn get_runtime_delegate_fn{};
hostfxr_run_app_fn run_app_fn{};
hostfxr_close_fn close_fn{};
static HostFXR init()
{
size_t buffer_size = 0;
get_hostfxr_path(nullptr, &buffer_size, nullptr);
auto lib_path = static_cast<char_t *>(calloc(buffer_size, sizeof(char_t)));
get_hostfxr_path(lib_path, &buffer_size, nullptr);
dylib lib(lib_path);
HostFXR fxr;
fxr.initialize_for_dotnet_command_line_fn = *lib.get_function<hostfxr_initialize_for_dotnet_command_line_fn>("hostfxr_initialize_for_dotnet_command_line");
printf("%p\n", fxr.initialize_for_dotnet_command_line_fn);
return fxr;
}
};
This is the only solution I found that works for me, the dylib object goes out of scope but the loaded function pointers don't, which is... questionable (Are they still valid?)
Why is it the case from the first place? Is it related to multithreading / managing the raw handle lifetime?
static char msg[buf_size];
This is a bug in multi-threaded code: Different threads will try to use the same buffer.
dylib is not supposed to have any requirements from dynamic-linking libraries. They exist entirely independently of it, ignorant of its existence. So, where would they know about DYLIB_API
from? ... nowhere.
As for the code linking against them, using dylib - it shouldn't have to know about that either; it just defines a function type, e.g.int(void)
, and get_function()
's with that.
So - it seems to me like this:
#if defined(_WIN32) || defined(_WIN64)
#define DYLIB_API extern "C" __declspec(dllexport)
#else
#define DYLIB_API extern "C"
#endif
is unnecessary. Perhaps it belongs in the test library?
Does not seem to build using Mingw64 on Windows 11
lonni@DESKTOP10 MINGW64 ~/dynlibs/dylib
$ cmake . -B build -DBUILD_TESTS=ON
CMake Warning (dev) at C:/msys64/mingw64/share/cmake/Modules/FetchContent.cmake:1264 (message):
The DOWNLOAD_EXTRACT_TIMESTAMP option was not given and policy CMP0135 is
not set. The policy's OLD behavior will be used. When using a URL
download, the timestamps of extracted files should preferably be that of
the time of extraction, otherwise code that depends on the extracted
contents might not be rebuilt if the URL changes. The OLD behavior
preserves the timestamps from the archive instead, but this is usually not
what you want. Update your project to the NEW behavior or specify the
DOWNLOAD_EXTRACT_TIMESTAMP option with a value of true to avoid this
robustness issue.
Call Stack (most recent call first):
CMakeLists.txt:25 (FetchContent_Declare)
This warning is for project developers. Use -Wno-dev to suppress it.
-- Configuring done
-- Generating done
-- Build files have been written to: C:/msys64/home/lonni/dynlibs/dylib/build
then I tried
lonni@DESKTOP10 MINGW64 ~/dynlibs/dylib
$ cmake --build build
[1/8] Building CXX object CMakeFiles/dynamic_lib.dir/tests/lib.cpp.obj
FAILED: CMakeFiles/dynamic_lib.dir/tests/lib.cpp.obj
C:\msys64\mingw64\bin\c++.exe -Ddynamic_lib_EXPORTS /W4 -std=gnu++11 -MD -MT CMakeFiles/dynamic_lib.dir/tests/lib.cpp.obj -MF CMakeFiles\dynamic_lib.dir\tests\lib.cpp.obj.d -o CMakeFiles/dynamic_lib.dir/tests/lib.cpp.obj -c C:/msys64/home/lonni/dynlibs/dylib/tests/lib.cpp
c++.exe: warning: /W4: linker input file unused because linking not done
c++.exe: error: /W4: linker input file not found: No such file or directory
[2/8] Building CXX object CMakeFiles/unit_tests.dir/tests/tests.cpp.obj
FAILED: CMakeFiles/unit_tests.dir/tests/tests.cpp.obj
C:\msys64\mingw64\bin\c++.exe -IC:/msys64/home/lonni/dynlibs/dylib/include -isystem C:/msys64/home/lonni/dynlibs/dylib/build/_deps/googletest-src/googletest/include -isystem C:/msys64/home/lonni/dynlibs/dylib/build/_deps/googletest-src/googletest /W4 -std=gnu++11 -MD -MT CMakeFiles/unit_tests.dir/tests/tests.cpp.obj -MF CMakeFiles\unit_tests.dir\tests\tests.cpp.obj.d -o CMakeFiles/unit_tests.dir/tests/tests.cpp.obj -c C:/msys64/home/lonni/dynlibs/dylib/tests/tests.cpp
c++.exe: warning: /W4: linker input file unused because linking not done
c++.exe: error: /W4: linker input file not found: No such file or directory
[3/8] Linking CXX static library lib\libgtest.a
ninja: build stopped: subcommand failed.
Any thoughts?
C++11 introduced a mechanism - not a fun one, or an easy one to use, but a mechanism - for working with system errors - among others, the ones that, on Unix, you get via errno
, and on Windows, with GetLastError()
. This is the <system_error>
header.
When the error you encounter is one of those - that's what you should throw. See some SO posts about it:
generic_category
rather than system_category
. Yes, it's a bit fucked up. Read <system_error> categories and standard/system error codes.We shouldn't return a char*
from _get_error()
- it's not a buffer to modify. In fact... we can't return a const char* either, unless we malloc it ourselves, which would be a leak or would require extra work outside... it needs to be an std::string
unfortunately.
Also, we're getting the description, not the error, so perhaps this should be renamed.
Originally posted by sethupavan12 February 17, 2022
Just to try out the suggested way ....
I tried generating a C dynamic lib using the libray compiler app in MATLAB and tried to extract a function from the generated DLL.
.m -> DLL -> extract usign DYLIB
Here is the matlab file that has been compiled into a DLL
function output = compile(a)
% find nth prime number using the sieve of Eratosthenes and store in output
sieve = ones(1,a);
sieve(1) = 0;
sieve(2) = 0;
% store the primes in output
output = [];
for i = 1:a
if sieve(i) == 1
output = [output i];
end
end
end
and when I load the DLL using a C++ file (main.cpp) I got the following error
dylib: error while loading symbol "compile"
The specified procedure could not be found.
main.cpp which is modified version of your example in readme.md
#include <iostream>
#include "dylib.hpp"
int main()
{
try {
dylib lib("./compileLibCompiler", dylib::extension);
auto nth_prime = lib.get_function<int(int)>("compile");
//nth_prime(5);
int a = 5;
int ans = nth_prime(a);
printf("%d\n", ans);
return 0;
}
catch (const dylib::exception &e) {
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
What do you think went wrong here?
In the README, we have the following example code:
dylib lib("./dynamic_lib.so");
// ... etc.
// Get the global variable pi_value
double pi = lib.get_variable<double>("pi_value");
Shouldn't this be:
double& pi = lib.get_variable<double>("pi_value");
?
Or perhaps
const double& pi = lib.get_variable<double>("pi_value");
?
I mean, I realize you don't need the address, only the value, for the function call to addr()
, but this use makes it unclear whether get_variable returns a value or a reference.
configure, build, make test.
$ ctest --rerun-failed --output-on-failure
Test project /home/eyalroz/src/mine/dylib/build
Start 1: exemple.exemple_test
1/10 Test #1: exemple.exemple_test .............***Failed 0.00 sec
Note: Google Test filter = exemple.exemple_test
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from exemple
[ RUN ] exemple.exemple_test
/home/eyalroz/src/mine/dylib/tests/tests.cpp:50: Failure
Expected equality of these values:
true
false
[ FAILED ] exemple.exemple_test (0 ms)
[----------] 1 test from exemple (0 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[ PASSED ] 0 tests.
[ FAILED ] 1 test, listed below:
[ FAILED ] exemple.exemple_test
1 FAILED TEST
Start 3: multiple_handles.basic_test
2/10 Test #3: multiple_handles.basic_test ......***Failed 0.00 sec
Note: Google Test filter = multiple_handles.basic_test
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from multiple_handles
[ RUN ] multiple_handles.basic_test
unknown file: Failure
C++ exception with description "dylib: error while loading dynamic library "./dynamic_lib.so"
./dynamic_lib.so: cannot open shared object file: No such file or directory" thrown in the test body.
[ FAILED ] multiple_handles.basic_test (0 ms)
[----------] 1 test from multiple_handles (0 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[ PASSED ] 0 tests.
[ FAILED ] 1 test, listed below:
[ FAILED ] multiple_handles.basic_test
1 FAILED TEST
Start 6: get_function.bad_symbol
3/10 Test #6: get_function.bad_symbol ..........***Failed 0.00 sec
Note: Google Test filter = get_function.bad_symbol
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from get_function
[ RUN ] get_function.bad_symbol
unknown file: Failure
C++ exception with description "dylib: error while loading dynamic library "./dynamic_lib.so"
./dynamic_lib.so: cannot open shared object file: No such file or directory" thrown in the test body.
[ FAILED ] get_function.bad_symbol (0 ms)
[----------] 1 test from get_function (0 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[ PASSED ] 0 tests.
[ FAILED ] 1 test, listed below:
[ FAILED ] get_function.bad_symbol
1 FAILED TEST
Start 8: get_variable.bad_symbol
4/10 Test #8: get_variable.bad_symbol ..........***Failed 0.00 sec
Note: Google Test filter = get_variable.bad_symbol
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from get_variable
[ RUN ] get_variable.bad_symbol
unknown file: Failure
C++ exception with description "dylib: error while loading dynamic library "./dynamic_lib.so"
./dynamic_lib.so: cannot open shared object file: No such file or directory" thrown in the test body.
[ FAILED ] get_variable.bad_symbol (0 ms)
[----------] 1 test from get_variable (0 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[ PASSED ] 0 tests.
[ FAILED ] 1 test, listed below:
[ FAILED ] get_variable.bad_symbol
1 FAILED TEST
Start 9: get_variable.alter_variables
5/10 Test #9: get_variable.alter_variables .....***Failed 0.00 sec
Note: Google Test filter = get_variable.alter_variables
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from get_variable
[ RUN ] get_variable.alter_variables
/home/eyalroz/src/mine/dylib/tests/tests.cpp:151: Failure
Expected equality of these values:
true
false
[ FAILED ] get_variable.alter_variables (0 ms)
[----------] 1 test from get_variable (0 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[ PASSED ] 0 tests.
[ FAILED ] 1 test, listed below:
[ FAILED ] get_variable.alter_variables
1 FAILED TEST
Start 10: bad_arguments.null_pointer
6/10 Test #10: bad_arguments.null_pointer .......***Failed 0.00 sec
Note: Google Test filter = bad_arguments.null_pointer
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from bad_arguments
[ RUN ] bad_arguments.null_pointer
unknown file: Failure
C++ exception with description "dylib: error while loading dynamic library "./dynamic_lib.so"
./dynamic_lib.so: cannot open shared object file: No such file or directory" thrown in the test body.
[ FAILED ] bad_arguments.null_pointer (0 ms)
[----------] 1 test from bad_arguments (0 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[ PASSED ] 0 tests.
[ FAILED ] 1 test, listed below:
[ FAILED ] bad_arguments.null_pointer
1 FAILED TEST
Start 12: os_detector.basic_test
7/10 Test #12: os_detector.basic_test ...........***Failed 0.00 sec
Note: Google Test filter = os_detector.basic_test
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from os_detector
[ RUN ] os_detector.basic_test
/home/eyalroz/src/mine/dylib/tests/tests.cpp:221: Failure
Expected equality of these values:
true
false
[ FAILED ] os_detector.basic_test (0 ms)
[----------] 1 test from os_detector (0 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[ PASSED ] 0 tests.
[ FAILED ] 1 test, listed below:
[ FAILED ] os_detector.basic_test
1 FAILED TEST
Start 14: has_symbol.basic_test
8/10 Test #14: has_symbol.basic_test ............***Failed 0.00 sec
Note: Google Test filter = has_symbol.basic_test
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from has_symbol
[ RUN ] has_symbol.basic_test
unknown file: Failure
C++ exception with description "dylib: error while loading dynamic library "./dynamic_lib.so"
./dynamic_lib.so: cannot open shared object file: No such file or directory" thrown in the test body.
[ FAILED ] has_symbol.basic_test (0 ms)
[----------] 1 test from has_symbol (0 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[ PASSED ] 0 tests.
[ FAILED ] 1 test, listed below:
[ FAILED ] has_symbol.basic_test
1 FAILED TEST
Start 15: operator_bool.basic_test
9/10 Test #15: operator_bool.basic_test .........***Failed 0.00 sec
Note: Google Test filter = operator_bool.basic_test
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from operator_bool
[ RUN ] operator_bool.basic_test
unknown file: Failure
C++ exception with description "dylib: error while loading dynamic library "./dynamic_lib.so"
./dynamic_lib.so: cannot open shared object file: No such file or directory" thrown in the test body.
[ FAILED ] operator_bool.basic_test (0 ms)
[----------] 1 test from operator_bool (0 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[ PASSED ] 0 tests.
[ FAILED ] 1 test, listed below:
[ FAILED ] operator_bool.basic_test
1 FAILED TEST
Start 16: handle_management.basic_test
10/10 Test #16: handle_management.basic_test .....***Failed 0.00 sec
Note: Google Test filter = handle_management.basic_test
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from handle_management
[ RUN ] handle_management.basic_test
unknown file: Failure
C++ exception with description "dylib: error while loading dynamic library "./dynamic_lib.so"
./dynamic_lib.so: cannot open shared object file: No such file or directory" thrown in the test body.
[ FAILED ] handle_management.basic_test (0 ms)
[----------] 1 test from handle_management (0 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[ PASSED ] 0 tests.
[ FAILED ] 1 test, listed below:
[ FAILED ] handle_management.basic_test
1 FAILED TEST
0% tests passed, 10 tests failed out of 10
Total Test time (real) = 0.03 sec
The following tests FAILED:
1 - exemple.exemple_test (Failed)
3 - multiple_handles.basic_test (Failed)
6 - get_function.bad_symbol (Failed)
8 - get_variable.bad_symbol (Failed)
9 - get_variable.alter_variables (Failed)
10 - bad_arguments.null_pointer (Failed)
12 - os_detector.basic_test (Failed)
14 - has_symbol.basic_test (Failed)
15 - operator_bool.basic_test (Failed)
16 - handle_management.basic_test (Failed)
Configured with BUILD_TESTS and built.
No compiler warnings
/home/eyalroz/src/mine/dylib/tests/lib.cpp:4:18: warning: ‘pi_value’ initialized and declared ‘extern’
4 | DYLIB_API double pi_value = 3.14159;
| ^~~~~~~~
/home/eyalroz/src/mine/dylib/tests/lib.cpp:5:17: warning: ‘ptr’ initialized and declared ‘extern’
5 | DYLIB_API void *ptr = (void *)1;
| ^~~
Now, the warnings are pretty innocuous, but - maybe you should create an extern "C" block to avoid them? Or perhaps - a proper-C library?
We've made several changes to the dev branch which require updating the README (e.g. w.r.t. open()
and close()
).
The code of get_function()
and get_variable()
is almost identical. Even if you want to distinguish the function names, there's no good reason to duplicate the code in there.
At the moment, one has to specify either the full path of a dynamic library, or the full path sans the extension (and even in that case, you need to incant the magic spell of mylib::extension
). In particular, this means that it is up to library user to construct the path correctly, and to make sure that on some OSes, lib
is prepended, while on others it is not. Also, the user has to pass a concrete path, something else which is prone to change when porting.
Instead, or at least, in addition to this API, the user code should be able to not be aware of these issues, and just be able to get the library using its basic name (and perhaps a path).
Ideally, I would like to be able to write
auto foo_lib = dylib::load("foo");
and for load()
to do the following:
libfoo
or foo
as the basename.LD_LIBRARY_SEARCH_PATH
)alternatively, and if we're stuck with the current API, I would expect this to work:
auto foo_lib_path = dylib::build_path("foo");
dylib foo_lib = dylib::lib(foo_lib_path);
and the above snippets could have variants specifying the location, e.g.
auto foo_lib = dylib::with_search_paths(dylib::search_recursively, "/some/path1", "/some/path2").load("foo");
for the first option or
auto foo_lib_path = dylib::with_search_paths(dylib::search_recursively, "/some/path1", "/some/path2").build_path("foo");
dylib foo_lib = dylib::lib(foo_lib_path);
for the second option.
On Windows, the DLL handle is an HINSTANCE
. You don't "officially" know that's a pointer. Yet - later in the code you assign a nullptr to m_handle
. If you've managed to remove these assignments from the code then nevermind; otherwise - you need to make sure and assign something you know is assignable. So, you might need to either asset it's a pointer, or define a "null handle" constant. The former is probably easier.
I'm looking at this kind of line, which we would now write with dylib (2.0):
auto mod = lib.get_function<float *, const char *>("driver::factory");
I find that's not good enough. It's neither here nor there. If you want something fully dynamic, then don't even pass the type via a template, but as a string, e.g.
lib.get_function("driver::factory(float *, const char *)");
where users would manage the calling conventions themselves using a void*
.
Similarly, you would also accept
lib.get_function("foo driver::factory(float *, const char *)");
for any foo, i.e. be willing to ignore the return type in the string (but also to check it if that's at all possible).
However, if you do have the namespace, name and signature at compile-time, then I would expect something like:
namespace driver {
foo (*factory)(float *, const char *) = nullptr;
} // namespace driver
lib.populate(driver::factory);
But I'm not sure the latter can be easily implemented in C++. Perhaps a macro would help here (allowing us to use both the value and the name.
Instead of saying:
dylib lib("foo.lib", false);
I should be able to say:
dylib lib("foo.lib", dylib::no_decorations);
or
dylib lib("foo.lib", dylib::no_os_decorations);
or
dylib lib("foo.lib", dylib::use_filename_verbatim);
(whichever of these identifiers you like best.) Otherwise, the reader has to guess what false
means. This breaks the Principle of Least Astonishment.
and similarly
dylib lib("foo", dylib::with_os_decorations);
if I want to.
getVariable() currently returns a value, while it seems it can return a reference - allowing the caller to possibly alter the global value.
std::function is a heavy container, whose main use is encapsulating potentially complex invokable objects. See this discussion; why use it? A simple (typed) function pointer should probably do nicely.
When building with GCC 10.2.1, I get:
/path/to/dylib/tests/lib.cpp:4:18: warning: ‘pi_value’ initialized and declared ‘extern’
4 | DYLIB_API double pi_value = 3.14159;
| ^~~~~~~~
/path/to/src/dylib/tests/lib.cpp:5:17: warning: ‘ptr’ initialized and declared ‘extern’
5 | DYLIB_API void *ptr = (void *)1;
| ^~~
The point is that either you declare something extern (coming from elsewhere), or you initialize it, but not both on the same line.
This is a C++ library for working with shared objects, but it only supports unmangled, C-style functions. That means it doesn't serve its primary function. The library must support any C++ function one can load from a shared object. Naturally, this is ABI-specific, but that's either for the user to configure and build accordingly, or potentially a case for multi-ABI support. The latter is much more complicated, and would be a feature request in itself, but function symbols should definitely be looked up by their mangled name, if they're not extern-C.
The dylib class has a default ctor. Why? What is the use of a "dummy", empty, dylib? Should you not follow the RAII paradigm, and let construct correspond to opening a library, and destruction to closing it?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.