Coder Social home page Coder Social logo

boost.dll's Introduction

boost.dll's People

Contributors

an-ky avatar apolukhin avatar ashtum avatar bebuch avatar dmsck avatar eldiener avatar flamefire avatar grafikrobot avatar klemens-morgenstern avatar kojoley avatar lastique avatar luzpaz avatar mkurdej avatar naios avatar pdimov avatar phprus avatar ramilgauss avatar retf avatar rettichschnidi avatar sdarwin avatar travbid avatar uskok avatar xialichao82 avatar zerotypos-found avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

boost.dll's Issues

path_from_handle implementation is incorrect (redux)

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);

Cast between pointer-to-function and pointer-to-object

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).

use extern "C++" instead of extern "C" will crash

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?

Question: How can I detach from shared_library?

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

Averting dependency on boost.filesystem ?

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 ?

Suggestion: load from memory?

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?

Possible Extension - Loading mangled symbols

This issue describes possible features I'd like to add to boost.DLL.

Preface

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.

Idea

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.

Mangled Functions and Variables

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");

Constructors/Destructors and Member functions

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");

Safe Import

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.

Variant 1 - Each export has a symbol

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.

Variant 2 - Export Table

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.

Status

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.

Reading a dll file on Linux

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

MFrontCastemBehaviours.dll.zip

Can we add BOOST_DLL_USE_STD to specifiy if we want to use boost version or std version of library

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:

  • shared_ptr
  • filesystem
  • type_traits

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.

unclear how to specify calling convention for dll::import

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:

define BOOST_BIND_ENABLE_STDCALL

define BOOST_MEM_FN_ENABLE_STDCALL

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;
}

Possible wrong include in path_from_handle.hpp

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..

Problem with "Factory method in plugin" example

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.

`

PROTECTED visibility should be listed on symbols since they are exported

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

Problems with de-mangled names (Linux)

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

Compatability with pybind11?

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:

With only 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)

With both 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?

Choose another shared library for test

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 ======

Check if shared_library::unload succeeded?

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?

undefined behavior with import_alias<T> returning boost::function<T>

in Import.hpp :

  • \code
  • boost::function<int(int)> f = import<int(int)>("test_lib.so", "integer_func_name");
  • \endcode

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.

Handling duplicate dependencies

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?

`boost::dll::shared_library self(boost::dll::program_location());` causing issues on Linux

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):

  • On some linux flavors it causes double static initialisation always (not fully understood which config parameter is different on affected systems, see the linked issue above for a reproducer and a table of affected systems)
  • On containerized CentOS 8 Continuous Integration environments we sometimes (20% chance or so) see errors like this: 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!

Is Boost.DLL really not thread safe on macOS?

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?

Document linkage requirements

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.

smart_library.get_mem_fn failed to call with 64bit dll

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.
image

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;
};

Support for Window Mingw

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.

Suggestion: it seems there is no library enumeration mechanism in Boost.DLL

My suggestion - add routins for enumeration shared libraries already loaded by current process

For example we have host app

  1. host.exe(or just bin on nix)
  2. host.exe dynamically loads some plugin.dll/so
  3. plugin.dll/so loads impl.dll/so automatically by lnker's import table(before run host(for example on linux) we set LD_LIBRARY_PATH to directory with impl.so to choose actual implementation)
  4. now from host.exe i want to set some global variable inside impl.so(for example some global interfaces used by impl) - but i dont know which of impl.so was loaded inside my process, i can not determine path of loaded dll/so - so i can't import symbol

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

Memory leak in example code

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:

  1. 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.

symbol_location example mainly reports: "./a.out"

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;
}

The macro BOOST_DLL_ALIAS does not appear to work for tutorial 1.

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;

Provide a no-load flag to enable use of shared_library with maybe-already-loaded libraries

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().

Importing multiple plug-ins linked into executable

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 ?

Confused by the Win32 `path_from_handle()` function

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?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.