apolukhin / boost.dll Goto Github PK
View Code? Open in Web Editor NEWLibrary for comfortable work with DLL and DSO
Home Page: https://boost.org/libs/dll
Library for comfortable work with DLL and DSO
Home Page: https://boost.org/libs/dll
I got next error:
C:/Boost/include/boost-1_56/boost/plugin/detail/windows/shared_library_impl.hpp:185:86: error: invalid conversion from 'boost::detail::winapi::FARPROC_ {aka int (__attribute__((__stdcall__)) *)()}' to 'void*' [-fpermissive]
void* const symbol = boost::detail::winapi::GetProcAddress(handle_, sb.data());
It can be fixed with using reinterpret_cast
but casting between pointer-to-function void(*)()
and pointer-to-object void*
will cause such warning which is described on dylsym page.
Since GetProcAddress
could be used to get address for objects too, I can't propose a simpler way to workaround this issue than just suppress this error with using static_assert for ensuring that sizes of both pointers are equal (in shared_library.hpp
).
Previous issue: #57
PR which was intending to fix that issue: #59
@apolukhin I believe this fix is incorrect. Per the documentation from GetModuleFileNameW (emphasis mine):
If the function succeeds, the return value is the length of the string that is copied to the buffer, in characters, not including the terminating null character. If the buffer is too small to hold the module name, the string is truncated to nSize characters including the terminating null character, the function returns nSize, and the function sets the last error to ERROR_INSUFFICIENT_BUFFER.
The important thing to note here is that the returned size can be non-zero even in failure cases. This appears to not be handled any more, which is the entire purpose of that loop which grows the buffer on each iteration afaict.
Likely the original structure of the code was correct, but what it meant to do instead of calling GetLastError was this:
SetLastError(0);
There seems to be a built-in assumption that we only ever want to load directly from the file system, however there are instances where loading from memory is useful though. In my project I'm planning on packaging up my plugins with any associated assets so that they can be downloaded as a unit, placed in the plugins folder as a single package, and then referenced via the PhysFS library. This means that the boost filesystem requirement ends up being a hindrance rather than a help. Not sure how difficult this would be of course; I imagine there may be technicalities I'm unaware of. Something to consider, anyway?
Dear developers,
we are using Boost.DLL for a small plugin system. Some plugins are linked into the executable following this guide: https://www.boost.org/doc/libs/1_76_0/doc/html/boost_dll/tutorial.html#boost_dll.tutorial.linking_plugin_into_the_executable.
The boost::dll::shared_library self(boost::dll::program_location());
statement however is causing two error classes for us (see FairRootGroup/FairMQ#351):
boost::dll::shared_library::load() failed (dlerror system message: /mnt/mesos/sandbox/sandbox/o2-fullci/sw/slc8_x86-64/O2/5964-local1/bin/o2-sim-primary-server-device-runner: cannot dynamically load executable): Bad file descriptor
On a first glance, it looks like boost::dll::shared_library self(boost::dll::program_location());
is implemented with a dlopen("/path/to/executable", ...)
on Linux. The Linux manpage also suggests to use dlopen(NULL, ...)
for this case. But I am no expert here. Do you have any deeper insight in what might be the underlying issue for the problems described above? Your comments are very much appreciated!
Using Boost 1.83.0
Using boost::dll::experimental::smart_library
Calling get_function(name)
The library does not seem to be generating correct de-mangled names for a C++ function, so it fails to find a "match" in the actual .so
This is only occurring on Linux, on Windows there are no issues. On Linux we are compiling with _GLIBCXX_USE_CXX11_ABI=1
The C++ prototype is
Run (
std::string const& filename,
bool const& flag,
std::size_t const numThreads,
std::atomic< bool > const& stopToken,
std::vector<int64_t> const& selected);
The actual signature is as follows ( using nm to query the .so )
Run( std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool const&, unsigned long, std::atomic<bool> const&, std::vector<long, std::allocator<long> > const&)
When compiled with the Intel ICX (clang) compiler, smart_library makes a mistake with the std::string type
smart_library sees the first parameter as std::basic_string ( not std::__cxx11::basic_string)
Run( std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool const&, unsigned long, std::atomic<bool> const&, std::vector<long"...
When compiled with gcc 11 , it gets the "string" type correct, but comes up with "long unsigned int" as the 4th parameter ( which is size_t)
Run(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool const&, long unsigned int, std::atomic<bool> const&, std"...
I am able to see the failures in the function
template<typename Func> std::string mangled_storage_impl::get_function(const std::string &name) const
I think the 4th include line in the boost/dll/detail/path_from_handle.hpp is incorrect. It should be:
#include <boost/detail/winapi/GetLastError.hpp>
instead of
#include <boost/detail/winapi/get_last_error.hpp>
The get_last_error.hpp doesn't exist in boost_1_60_0..
To my understanding, the usage of the aliasing constructor in example8 induces a memory leak as the my_refcounting_api
pointer plugin
does not get freed by this kind of shared_ptr:
- The aliasing constructor: constructs a shared_ptr which shares ownership information with r, but holds an unrelated and unmanaged pointer ptr. Even if this shared_ptr is the last of the group to go out of scope, it will call the destructor for the object originally managed by r. However, calling get() on this will always return a copy of ptr. It is the responsibility of the programmer to make sure that this ptr remains valid as long as this shared_ptr exists, such as in the typical use cases where ptr is a member of the object managed by r or is an alias (e.g., downcast) of r.get()
How about some auxiliary wrapper:
template <typename T> struct ResourceWrapper {
boost::dll::shared_library m_Dll;
std::unique_ptr<T> m_T;
ResourceWrapper(boost::dll::shared_library &dllLib, std::unique_ptr<T> i)
: m_Dll(dllLib), m_T(std::move(i)) {}
};
Then use it along those lines:
boost::dll::shared_library myLib("myLib.so");
auto myObject = std::make_unique<MyType>();
auto myWrapper = std::make_shared<ResourceWrapper<MyType>>(myLib, std::move(myObject));
auto myAliasedSharedPointer = std::shared_ptr<MyType>(myWrapper, myWrapper->m_T.get());
I am not sure if this really THE way to go. But according to my understanding, this at least does not leak memory.
Dear developers,
We are using dll boost project to access shared libraries symbols on Linux EL7 (ELF)
We notice that we symbols with PROTECTED visibility attribute are not listed on library_info symbols.
Protected symbols are exported and can be accessed when loading shared libraries using dlopen/dlsym, so I understand they should be included on symbols list retrieved using library_info.
We try changing is_visible method on dll/detail/elf_info.hpp, and changing the condition to:
return ((sym.st_other & 0x03) == STV_DEFAULT_ || (sym.st_other & 0x03) == STV_PROTECTED_ ) && (sym.st_info >> 4) != STB_LOCAL_ && !!sym.st_size;
and it seems to work.
Can you please review this?
Regards
I'd like to use the functionality of Boost.DLL to access libraries that are already loaded in the process, but be able to avoid loading libraries that are not already loaded. Essentially:
boost::dll::shared_library foo("/path/to/some/library", load_mode::dont_load);
if (foo.is_loaded())
{
// look up functions
}
On POSIX, this would equate to use of RTLD_NOLOAD with dlopen, and on Windows the use of GetModuleHandle() instead of LoadLibary().
Qt's QPluginLoader has a way to get an error string about what happened when a plug-in could not be loaded: http://doc.qt.io/qt-5/qpluginloader.html#errorString
Is there a way to get the same with Boost.DLL ? it makes debugging for missing export symbols much easier.
The code below suggest that you can replace it with BOOST_DLL_ALIAS(my_namespace::plugin, plugin)
, but if you do it will not build. Is there something missing?
// Exporting `my_namespace::plugin` variable with alias name `plugin`
// (Has the same effect as `BOOST_DLL_ALIAS(my_namespace::plugin, plugin)`)
extern "C" BOOST_SYMBOL_EXPORT my_plugin_sum plugin;
my_plugin_sum plugin;
This section : https://www.boost.org/doc/libs/1_67_0/doc/html/boost_dll/tutorial.html#boost_dll.tutorial.linking_plugin_into_the_executable
proposes a method that works fine, given a single plug-in with a symbol of known name. If there are multiple plug-ins linked into the executable, however, this does not really scale : the executable has to know the name of all plug-ins linked into it statically : the plug-in symbol, for instance create_plugin
has to be different for each plug-in.
The solution in Qt is to have a global registry of such plug-ins: http://doc.qt.io/qt-5/qpluginloader.html#staticInstances ; is there something similar in boost.dll ?
I am the beginer to use boost,and I have no idea to compile these code.So could someone help me compile these code in linux/windows?
My suggestion - add routins for enumeration shared libraries already loaded by current process
For example we have host app
i wrote some platform dependent code to demonstrate root of my suggestion
std::filesystem::path impl_dll_path;
#ifdef BOOST_OS_LINUX
auto self_handle = dlopen(NULL, RTLD_LAZY | RTLD_LOCAL);
for (auto link_map = static_cast<const struct link_map*>(self_handle);
link_map; link_map = link_map->l_next)
{
std::string dll_name(link_map->l_name);
if (dll_name.ends_with("libimpl.so"))
{
impl_dll_path = dll_name;
break;
}
}
#endif
Overall i think enumeration of loaded libraries will be usefull in many other cases too
PS
For Windows OS this article will be useful obviosly https://learn.microsoft.com/en-us/windows/win32/psapi/enumerating-all-modules-for-a-process
Right now, there's no way to know if shared_library::unload
succeeded or not. On Windows, this can be checked by return values of FreeLibrary
. On POSIX systems, dlclose
returns a non-zero value in case of error.
Is it possible to implement an optional boost::system::error_code
argument for unload
so it'll be possible to see what goes wrong?
I've created a program to test boost::dll::symbol_location
, based on the documentation page here. If I compile the code ($CXX -std=c++17 main.cpp) on my Ubuntu 22.04 system with Clang (clang++), the output is as expected (a.out/libstdc++.so/libc.so etc.); but using GCC (g++), the program outputs that all 5 symbols are located at a.out
. On another machine (Debian Crostini), -dl
is required; and both GCC and Clang indicate that all 5 symbols are located at a.out
. How can I get consistent results?
#define BOOST_DLL_USE_STD_FS
#include <boost/dll/config.hpp>
#include <boost/dll/runtime_symbol_info.hpp>
#include <iostream>
#include <cassert>
#include <functional> // std::placeholders
int var;
void foo() {}
int main(int argc, char *argv[])
{
namespace dll = boost::dll;
boost::dll::fs::path p1, p2, p3, p4, p5;
boost::dll::fs::error_code ec{};
p1 = dll::symbol_location(var, ec); // returns program location
assert(!ec);
p2 = dll::symbol_location(foo, ec); // returns program location
assert(!ec);
// returns location of libstdc++: "/usr/lib/x86_64-linux-gnu/libstdc++.so.6"
p3 = dll::symbol_location(std::cerr, ec);
assert(!ec);
// returns location of libstdc++: "/usr/lib/x86_64-linux-gnu/libstdc++.so.6"
p4 = dll::symbol_location(std::placeholders::_1, ec);
assert(!ec);
// returns location of libc: "/lib/x86_64-linux-gnu/libc.so.6"
p5 = dll::symbol_location(std::puts, ec);
assert(!ec);
for (const auto& p : {p1, p2, p3, p4, p5}) { std::cout << p << std::endl; }
return 0;
}
This issue describes possible features I'd like to add to boost.DLL.
I was recently working on a shared library import library, though with a few more features boost.DLL does not have. It is currently more a proof-of-concept, but I could certify (on windows with gcc 5.1 and MSVC) that these work. Since Clang uses the same ABI as Gcc, I am quite confident that this will work on most platforms.
The basic Idea is to implement loading of mangled names. This shall be done by reading the complete outline from the shared library and demangle each name. These demangled names will then be stored in a map with the mangled one.
That way we can easily match names for requested functions.
If this is added to boost.DLL, it would be an additional class, which shared a shared_lib.
The examples given below are overly simple on purpose. I don't have a detailed design for the library, but I will add it during development. This shall give a basic idea and start a discussion.
Loading a plain mangled name is quite easy, though I have to add, that it's also type-safe in MSVC, since this compiler also mangles the typename, whlie the Itanium ABI does not. I will later discuss how this could be added for GCC.
So now, compared to the plain boost.dll, a mangled name can be loaded rather easy:
var = dll::import_variable<int>("some_namespace::variable");
The check if the name is mangled is in itself trivial. Or for static functions:
plugin = dll::import_function<int(double)>("some_namespace::some_function");
It is basicly as easy to get pointers to member-functions and constructors. Constructors and Member-functions behave in the same way, so once we have enough allocated memory, we can explicitly call the constructors.
Getting a Constructor:
plugin = dll::import_constructor<void(int, int)>("some_namespace::some_class");
Loading a member-function:
Getting a Constructor:
plugin = dll::import_constructor<double(int, int)>("some_namespace::some_class::method");
Now if we import a constructor, we can call him like a member-function, but we still do not know which size it has.
Hence we need a mechanism to import this safely. Additionally such a mechanism would also provide a safe import for all variables and functions, because we know their (return) types.
Now quite simple is the following solution: export a symbol for each variable, e.g.:
#define EXPORT_VARIABLE(Name) \
namespace boost { namespace dll_export { \
struct Name##Export { static size_t size() {return sizeof(Name);}; }}}
We could also export it's type this way. The problem is, that the outline looks aweful afterwards.
We declare a global variable, which holds all information. Out macro will declary a dummy, whoms constructor will pass information to a singleton. This singleton then is exported.
I didn't think this concept through, but I will give it some thought as soon as I am finished with the core.
As mentioned in the beginning, I have a proof-of-concept implemenation and I am currently working on building a implementation which ties into boost.dll. This will be the major part, i.e. to develop a layer which allows the import of mangled functions. If that works, one of the concepts described above will come in place, and I will exploit the type system, to construct type safety while importing functions.
My thought is we could have a BOOST_DLL_USE_STD macro to control if we want to use the boost version or std version of the following:
The way I am thinking is that we could define boost::dll::shared_ptr
in config.hpp and use macro to control if we want to use the std version or the boost version, similar to how the boost::dll::fs
is done.
Just want to ask is this an acceptable solution, I could do this if this idea is approved.
Apologies in advance if this is actually expected behavior and the answer is "just don't try this."
I'm using the BOOST_DLL_ALIAS
/ boost_import_alias()
machinery following this recipe to load a DLL library I developed in C++. It's been working great for me.
The library functionality is all in a single class Foo
. There's a factory method Foo::Create()
that returns a boost::shared_ptr
to a new Foo
, and a single BOOST_DLL_ALIAS
in the project that exports Foo::Create()
to a DLL symbol CreateFoo
. The project is compiled to FooLibrary.dll
and can be loaded and used from C++ exactly as described in the docs.
I want to be able to access the functionality from Python as well, so I defined a pybind11
interface using the PYBIND11_MODULE
macro. The module's __init__
is bound to Foo::Create()
though I've also tried it bound to a different factory function with the same results. When I compile with the pybind interface, I can copy and rename FooLibrary.dll
to FooLibrary.pyd
and import it as a correctly functioning module in Python.
However, compiling in the pybind code breaks it so that FooLibrary.dll
can no longer be loaded as a C++ DLL. It fails with boost::dll::shared_library::load() failed: The specified module could not be found.
I'm using boost::dll::library_info
in C++ to get the sections and symbols contained in the DLL and CreateFoo
is in the DLL in both cases:
BOOST_DLL_ALIAS
export in the source of FooLibrary.dll
:In C++, everything works perfectly, as expected:
--- Reading Symbols from shared library ---
Found no symbols in section .text
Found no symbols in section .rdata
Found no symbols in section .data
Found no symbols in section .pdata
Found symbol CreateFoo in section boostdll
Found no symbols in section .rsrc
Found no symbols in section .reloc
--- Trying boost::dll::import_alias() to load CreateDHSolver from builds/VS2019/x64/Release/FooLibrary ---
--- Shared Library Loaded Successfully, Program Continuing ---
In Python (copied compiled DLL and renamed to FooLibrary.pyd
), there's the obvious failure:
Python 3.7.6 (default, Jan 8 2020, 20:23:39) [MSC v.1916 64 bit (AMD64)] :: Anaconda, Inc. on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import FooLibrary
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: dynamic module does not define module export function (PyInit_FooLibrary)
BOOST_DLL_ALIAS
and PYBIND11_MODULE
in the source of FooLibrary.dll
:In C++, it fails even though CreateFoo is an available symbol:
--- Reading Symbols from shared library ---
Found symbol PyInit_FooLibrary in section .text
Found no symbols in section .rdata
Found no symbols in section .data
Found no symbols in section .pdata
Found symbol CreateFoo in section boostdll
Found no symbols in section .rsrc
Found no symbols in section .reloc
--- Trying boost::dll::import_alias() to load CreateFoo from builds/VS2019/x64/Release/FooLibrary ---
boost::dll::shared_library::load() failed: The specified module could not be found
In Python, it works fine:
Python 3.7.6 (default, Jan 8 2020, 20:23:39) [MSC v.1916 64 bit (AMD64)] :: Anaconda, Inc. on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import FooLibrary
>>> FooLibrary.Foo().doSomething()
'Foo Python Interface Did Something...'
>>>
Window 10, Microsoft Visual Studio 2019, Boost 1.7.2, C++17 language
Any ideas on how to resolve this would be appreciated. Or a clear understanding that it's impossible.
I expect this involves some fairly subtle point of C++ or DLL knowledge, and maybe I'll just have to live with compiling separate projects for the Python module and the C++ DLL.
The library is for use from C++ but needs some complex functional testing against Python prototype code, however, so it's really convenient to imagine having a dual-use Python/C++ DLL that has both interfaces in a single binary build. Is there a reason why boost::python
would work better here?
libdl is merge into libc in glibc-2.34[1], so test/shared_library_load_test.cpp(248) failes because libdl.so no longer exists.
Maybe we should choose another library for test?
[1]https://sourceware.org/glibc/wiki/Release/2.34
test log:
testing.capture-output ../../../bin.v2/libs/dll/test/shared_library_load_test.test/gcc-12/release/debug-symbols-on/pch-off/threading-multi/visibility-hidden/shared_library_load_test.run
====== BEGIN OUTPUT ======
Library: "../../../bin.v2/libs/dll/test/gcc-12/release/debug-symbols-on/pch-off/threading-multi/visibility-hidden/libtest_library.so.1.80.0"shared_library_load_test.cpp(248): test 'false' failed in function 'int main(int, char**)'
platform_independent_path: "../../../bin.v2/libs/dll/test/gcc-12/release/debug-symbols-on/pch-off/threading-multi/visibility-hidden/test_library"
Program location: "/home/sdlzx/rpmbuild/BUILD/boost_1_80_0/bin.v2/libs/dll/test/shared_library_load_test.test/gcc-12/release/debug-symbols-on/pch-off/threading-multi/visibility-hidden/shared_library_load_test"
Library location: "/home/sdlzx/rpmbuild/BUILD/boost_1_80_0/bin.v2/libs/dll/test/shared_library_load_test.test/gcc-12/release/debug-symbols-on/pch-off/threading-multi/visibility-hidden/shared_library_load_test"1 error detected.
EXIT STATUS: 1
====== END OUTPUT ======
I want to export a std::string foo(), and use extern "C++" to avoid a warning, however when i get the function, it crashed.
So i want to know if boos.dll support extern "C++" or not?
How can i export such kind of c++ function with boost.dll?
Hi,
The problem is with the tutorial, not the library itself.
Your factory method in tutorial returns boost::shared_ptr<my_plugin_aggregator>.
However, you import it via alias, as function returning boost::shared_ptr<my_plugin_api>, which is quite confusing.
I was wondering HOW this could even work in general, with all the low level stuff going on, but I checked that it doesn't really work:
program crashes (in gcc and clang) as soon as address of my_plugin_api subobject differs from that of my_plugin_aggregator
object. To see the problem, simply change my_plugin_aggregator to something like
class my_plugin_aggregator : public S, public my_plugin_api {/*.../*};
with
struct S {
float f = 13.0;
virtual ~S() = default;
};
By constrast, if your factory method returns boost::shared_ptr<my_plugin_api> (as it should I guess), everythng works just fine with new version of my_plugin_aggregator.
`
Do we have document about how to build and use library in Android and iOS ? Is it possible?
in Import.hpp :
template
BOOST_DLL_IMPORT_RESULT_TYPE import(const boost::shared_ptr<shared_library>& lib, const char* name) {
typedef typename boost::dll::detail::import_type::base_type type;
return type(lib, &lib->get(name)); // returns refc_function(lib , &lib->get(name))
}
It does not return aliasing shared_ptr constructor but rather your own refc_function
But I don't see how you maintain ref count after your conversion operator
operator T*() const BOOST_NOEXCEPT ;
is called assigning to boost::function
Basically this is how it looks after type substitution
boost::function<int (int)> f = refc_function<int (int)>(lib, &lib->get<int(int)>(name)).operator T*() ;
What guarantees that the function pointer from shared_library ( aka return of dlsym ) is still valid after shared_library destructor ( see ~shared_library_impl() ) is called and actual shared lib is unloaded from the process ?
Can we continue to hold the pointer returned by dlsym() ?
Am I missing something ?
You handle it correctly in case of
shared_ptr p = import(lib, name) ; // this will share p and lib ref count
But it does not look like it applies to another case.
Thanks,
Vlad.
Please note in the docs which compilers and compiler versions are supported
Referenced here.
I write custom .NET apphost application(for our project) and load into it coreclr.dll/so but this library(.NET VM) writed very tricky and not clean. They create several threads inside and there is no way to join them, so due destroying of shared_library object dtor unloads coreclr library and my app just cause access violation in random places, cos coreclr thread still alive, but code already unloaded!
I investigated original code of MS apphost - it seems there no FreeLibrary at all, so my suggession: they just left threads in the hope that system finish them and unload coreclr at the end of process.
But i don't know how make same behaviour with boost.dll - it seems shared_libarary has no any methods like detach or something like that.
PS
.net project: https://github.com/dotnet/runtime
so it's here and the link is https://github.com/boostorg/dll/blob/a7f356119218a9a6d58fd5ea61cc6bc4c120ac9d/include/boost/dll/detail/windows/path_from_handle.hpp#L35
// On success, GetModuleFileNameW() doesn't reset last error to ERROR_SUCCESS. Resetting it manually.
boost::winapi::GetLastError(); // HERE
// If `handle` parameter is NULL, GetModuleFileName retrieves the path of the
// executable file of the current process.
boost::winapi::WCHAR_ path_hldr[DEFAULT_PATH_SIZE_];
boost::winapi::GetModuleFileNameW(handle, path_hldr, DEFAULT_PATH_SIZE_);
ec = boost::dll::detail::last_error_code();
if (!ec) {
return boost::filesystem::path(path_hldr);
}
So this really confuses me. AFAIK GetLastError() function only gets the last error, it doesn't reset it.
What does Resetting it manually.
mean?
It seems that Mingw is not supported.
The BOOST_DLL_ALIAS does not work and the error message is the following:
D:\CPPLib\boost\boost\dll\alias.hpp:32: error: expected constructor, destructor, or type conversion before '(' token
__pragma(section(#SectionName, Permissions)) __declspec(allocate(#SectionName))
^
Would you like to add support for mingw. I deem that it may just cost a few more codes.
This has the huge drawback of requiring the compiled parts of boost which is much more complicated to handle in a cross-platform way than the header-only parts of boost. Wouldn't it be possible to optionally depend on std::filesystem if available ?
Environment: Windows 10 1903; MSVC 14.2; Boost 1.70
A member function in my class was successfully imported only in x86 and failed in x64.
auto f = sm.get_mem_fn<alias, void(Callback)>("set_callback");
give me an exception in x64.
My prject file: test_class.zip
My class like this:
#include <iostream>
#include <functional>
#include <boost/config.hpp>
struct CallbackInfo
{
void* p;
int a;
int b;
void* pContext;
};
//using Callback = std::function<void(CallbackInfo* pInfo)>;
typedef void(__stdcall* Callback)(CallbackInfo* pInfo);
class BOOST_SYMBOL_EXPORT test_a
{
int _a;
public:
test_a();
test_a(int a);
~test_a();
void print();
bool large_than(int a);
const char* number();
void set_callback(Callback callback);
static std::size_t size();
std::string name() const;
};
compile ok, run error!
boost 1.57 and visual studio 2010 sp1 on windows 7 64bit!
The documentation clearly states that Boost.DLL is not thread safe on macOS due to thread safety issues with dlopen(). Is this really still true or is this bit of documentation out of date? I'm unaware of any thread safety problems with dlopen on any recent version of macOS, and our system is both heavily threaded and a heavy user of dlopen. We make no special affordances for macOS vs Linux vs Windows. Or is Boost.DLL using some undocumented macOS APIs that do still have issues?
I'm learning how to use Boost.DLL at the moment (I haven't used shared libraries in my C++ code before now). I was wondering about the possible issues regarding (and ways to deal with) a plugin's own dependencies when there are multiple plugins that are unaware of each other but where each uses the same shared library. My directory structure will look something like this:
/bin/[main application files]
/bin/plugins/[plugin directories]
/bin/plugins/foo-plugin/plugin.dll
/bin/plugins/foo-plugin/[other files used by foo plugin.dll]
If I have two plugins, let's say "foo" and "bar", and both want to use the nanomsg library, which has a dll shared library, then each would end up with a copy of that dll in their respective plugin directories.
How would I deal with conflicts between the two? What's the common approach?
Dear developpers,
First, let me thank you all for creating this very usefull library.
I tried to read a dll file under Linux. I am using Boost 1.63 under Debian Jessie with gcc 4.9.2.
The test is the following:
#include <boost/dll/shared_library.hpp>
#include <boost/dll/library_info.hpp>
#include <iostream>
int main(void) {
boost::dll::library_info i("./MFrontCastemBehaviours.dll");
return 0;
}
This test fails with the following exception:
terminate called after throwing an instance of 'std::ios_base::failure'
what(): basic_ios::clear
Abandon
Under gdb, we see that something goes wrong in boost::dll::detail::pe_info::parsing_supported.
#7 0x00007ffff794adda in std::basic_ios<char, std::char_traits<char> >::clear(std::_Ios_Iostate) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#8 0x00007ffff794dd73 in std::istream::seekg(std::fpos<__mbstate_t>) ()
from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#9 0x0000000000402e1d in boost::dll::detail::pe_info<unsigned long>::parsing_supported (f=...) at ../../1.63/install/include/boost/dll/detail/pe_info.hpp:188
#10 0x00000000004025e5 in boost::dll::library_info::init (this=0x7fffffffde70,
throw_if_not_native=true)
at ../../1.63/install/include/boost/dll/library_info.hpp:101
#11 0x0000000000402877 in boost::dll::library_info::library_info (
this=0x7fffffffde70, library_path=..., throw_if_not_native_format=true)
at ../../1.63/install/include/boost/dll/library_info.hpp:140
#12 0x0000000000401d4e in main () at symbols.cxx:14
The DLL that is tested comes from the unit-tests of my project and has been generated with Visual Studio 2015. This DLL works as expected under windows so I don't expect that the issue is related to that specific DLL.
With kind regards,
Thomas Helfer
Building a project that uses boost.dll under Linux results in: undefined reference to symbol 'dlclose@@GLIBC_2.2.5'
This can be fixed with -ldl
.
I didn't try to do it under Windows, but I assume that other library may be required on non-Linux platforms.
By now I could only find linkage requirements in test/Jamfile.v2
:
# linux
<target-os>linux:<linkflags>"-ldl" <target-os>linux:<cxxflags>"-fvisibility=hidden"
<toolset>gcc:<cxxflags>"-Wall -Wextra -pedantic -Wno-long-long"
# others
<library>/boost/filesystem//boost_filesystem
<library>/boost/system//boost_system
<threading>multi
;
But this is not obvious and not easy to read. Having it in official tutorial would be awesome.
Thanks.
On Android, I caught an exception while trying to load the shared library on tutorial 2๏ผ
boost::dll::shared_library::get() failed (dlerror system message: symbol found but not global: createPlugin): Illegal seek [generic:29]
Hello,
I've just started using Boost.DLL in order to simplify loading of various WinApi functions exclusive to specific Windows versions, however, I've faced the issue (or may be it's just misunderstanding from my side).
it's pretty well-known there are multiple calling conventions around - cdecl, stdcall, fastcall, etc. most of WinApi functions are in stdcall calling convention, while default one for MSVC 2015 is cdecl (unless compiler options are changed).
I've read documentation on http://apolukhin.github.io/Boost.DLL/, as well as I've scanned source code a bit, but didn't find any avidence on how to specify calling convention of function I am importing.
example from tutorial9 works just fine, as it uses timeGetTime function which has no arguments. however, if I modify example (see my code below copy-pasted from tutorial9) to import function with at least one argument or more (e.g. GetStdHandle) I receive the following debugger error:
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
this indicates that Boost.DLL incorrectly interpreted stdcall function as cdeacl function that caused stack corruption.
I've googled a bit about calling convention and boost, and found the following two definitions:
unfortunately adding them has no effect.
if I add explicit __stdcall into the function typedef, then program no longer compiles
#include <boost/dll/import.hpp> // for import
#include <iostream>
#include <windows.h>
namespace dll = boost::dll;
int main()
{
typedef HANDLE(GetStdHandle_fn)(DWORD nStdHandle); // function signature
boost::function<GetStdHandle_fn> plugin
= dll::import<GetStdHandle_fn>( // we import using C name, not alias! Using `import<>`
"Kernel32.dll", // Windows dll
"GetStdHandle" // function name
);
std::cout << "timeGetTime() returned " << plugin(STD_OUTPUT_HANDLE) << std::endl;
return 0;
}
I have come across this issue when using function pointer type instead of function type. In this case calling a function after getting symbol address causes application crash: segmentation fault.
OS: Ubuntu 18.04.4 LTS
Compiler: clang 9
Boost version is: 1.67.0
Please check attached example:
BoostDllTest.zip
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.