...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
During discussion of the library a lot of questions were about ABI stability and should the library take care about it. It was decided that making ABI stable could be a useful feature, but it will add a lot of overhead and make the library usage less simple. For those who do not require ABI stability across compilers such feature will be an overkill.
It was decided to make this library more simple and low level, so that it could be used to make ABI stable plugins system for users that require it still not adding overhead for other users.
There are some open C++ plugin systems. Most of them force user to have some predefined API. The problem is that all of those API differ.
To be more usable Boost.DLL does not force API. It's up to user to design suitable API.
Some methods of the library use boost::filesystem::path
or return std::vector<std::string>
. This may look non optimal at first,
but there is a reason to do so.
boost::filesystem::path
allows to transparently use Unicode
strings with non-Unicode ones. Using it provides a more user-friendly interface
for the library while the performance overhead is not noticeable because
of a slow file system operations that occur in boost::filesystem::path
accepting methods.
std::vector<std::string>
variables are returned by the library_info
methods. Querying a library
is a slow procedure anyway: it randomly reads parts of file from disc and
executes algorithms that sometimes have linear complexity from sections or
exported symbols count. Returning std::vector<std::string>
simplifies implementation and does not
require from user to keep an instance of library_info
after query. Having not a very noticeable performance overhead in rarely
called methods seems reasonable.
Other methods are assumed to be hot paths and optimized as much as possible.
There is a good big reason to make self loading via shared_library(program_location())
instead of having some shared_library::load_self()
member method. That reason is the requirement
to have an ability to call shared_library(this_line_location())
from any place, even from the main binary.
We need that to link plugins into the binary and to create a transparent
reference counting mechanism.
Making multiple interfaces that do exactly the same things looks unreasonable
to me, that's why shared_library(program_location())
and shared_library(this_line_location())
are used without shared_library::load_self()
.
Mangling depends on source code, for example "boost::foo"
could be foo
function or
foo
variable. Depending on
that knowledge it must be mangled in different ways. More problems arise
if foo
is an overloaded function
that accepts parameters: "boost::foo(variant<int,
short>)"
. In that case full name of parameter must
be specified, which could be boost::variant<int,
short>
or variant<int, short, void_, void_>
...
There was an idea to allow user to forward declare function and generate mangled name from it:
namespace boost { void foo(variant<int, short>); } std::string mangled_name = boost::dll::magic_mangle(boost::foo);
But that idea has epic failed because of linker problems and no reliable way to get mangled symbol name from compiler internals at compile time.
That's why aliases were considered a lesser evil:
BOOST_DLL_ALIAS(boost::foo, foo_variant) // in plugin "foo_variant" // in plugin importer