The Dynamic Module¶
To use this module, include ccbase/dynamic.hpp. Please note that this module currently works on OS X and Linux only.
Overview¶
This module does the following two things:
- Provides clean, cross-platform syntax for loading functions and symbols from dynamic libraries.
- Provides cross-platform macros to control symbol visibility.
Loading Dynamic Libraries¶
Suppose that you have a library called test.dll, which defines two symbols of interest: msg, a std::string and test(), a function with the signature int(const std::string&, const std::string&). Assuming that both symbols have C linkage, then you could load them as follows:
using sig = int(const std::string&, const std::string&);
auto img = cc::image{"test.dll", cc::binding_mode::lazy};
auto test = cc::load<signature>("test", img).get();
auto& msg = cc::load<std::string>("msg", img).get();
The function load<T>() returns an expected<T> object, which contains either the object loaded from the symbol, or the exception that prevented the object from being loaded. Invoking get() on the expected<T> objects throws the stored exception if the object is in an invalid state, and returns the stored value otherwise.
Notice that when we loaded msg from the image, we accepted the return value by reference rather than by value. This is because load<T>() returns a reference to the object at the symbol’s address, so mutating the reference will also change the data at the symbol’s address in memory.
One can also query information about the loaded objects, as in the following example:
using sig = std::string(std::string, std::string);
auto img = cc::image{"test.dll", cc::binding_mode::lazy};
auto test = cc::load<signature>("test", img).get();
auto test_info = cc::query(test).get();
cc::println(test_info.name());
// Prints "test".
cc::println(test_info.address());
// Prints the address of `test`.
Reference¶
- class binding_mode : int¶
Specifies the way in which the symbols in the library are loaded. A valid binding_mode consists of either lazy or now OR’d with zero or more of the other enum values.
- binding_mode lazy¶
Equivalent in function to the POSIX macro RTLD_LAZY.
- binding_mode now¶
Equivalent in function to the POSIX macro RTLD_NOW.
- binding_mode global¶
Equivalent in function to the POSIX macro RTLD_GLOBAL.
- binding_mode local¶
Equivalent in function to the POSIX macro RTLD_LOCAL.
- binding_mode nodelete¶
Defined only if the Linux-specific macro RTLD_NODELETE is defined.
- binding_mode noload¶
Defined only if the Linux-specific macro RTLD_NOLOAD is defined.
- binding_mode deepbind¶
Defined only if the Linux-specific macro RTLD_DEEPBIND is defined.
- class image¶
This class provides a wrapper over the platform-specific handle to a loaded dynamic library.
- explicit image(const boost::string_ref path, binding_mode mode)¶
Retrieves a handle to the dynamic library at the given path, using the specified mode.
Throws: std::runtime_exception If the dynamic library could not be accessed.
- ~image()¶
Closes the handle to the dynamic library, if the handle is valid.
- void* handle() const noexcept¶
Returns the internal handle to the dynamic library.
- void close()¶
Closes the handle to the dynamic library, if the handle is valid.
- class function<Signature>¶
This class is used to represent a function loaded from a dynamic library.
- ReturnType operator()(Args&& args) const¶
Invokes the function by forwarding the given arguments.
Noexcept: True iff the function has the noexcept property when called with the fowarded arguments.
- class symbol_info¶
This class is used to store the information obtained after querying a symbol loaded from a dynamic library.
- const boost::string_ref path() const noexcept¶
Returns the path to the dynamic library file.
- const boost::string_ref name() const noexcept¶
Returns the name of the symbol.
- const void* base_address() const noexcept¶
Returns the base address of the dynamic library.
- expected<symbol_info> query(const T& t) noexcept¶
Returns the symbol information associated with the given object.
- expected<symbol_info> query(const function<Signature>& f) noexcept¶
Returns the symbol information associated with the given function.
- expected<T&> load<T>(const boost::string_ref name, const image& img) noexcept¶
Loads the object symbol with the given name from the image file.
- expected<function<Signature>> load<Signature>(const boost::string_ref name, const image& img) noexcept¶
Loads the function symbol with the given name from the image file.
Controlling Symbol Visibility¶
The following macros can be used to set symbol visibility when compiling shared libraries.
// Used for public symbols in a header for a shared library that is to
// be implicitly linked into the final executable.
IMPORT_SYMBOL
// Used for public symbols in source code that is to be compiled into a
// shared library.
EXPORT_SYMBOL
// Used to hide symbols in source code that is to be compiled into a
// shared library.
HIDDEN_SYMBOL
Often times, it is the case that the same header file is used both by the source code that is compiled into the shared library, and by the source code that links to the shared library. In the first case, public symbols should be prefixed by EXPORT_SYMBOL; in the second case, public symbols should be prefixed by IMPORT_SYMBOL. In both cases, private symbols that are not included in the shared library should be prefixed by HIDDEN_SYMBOL. The following macros are provided to make this task easier:
PUBLIC_SYMBOL
PRIVATE_SYMBOL
PUBLIC_SYMBOL expands to IMPORT_SYMBOL if CCBASE_IMPORT_SYMBOLS is defined, or EXPORT_SYMBOL if CCBASE_EXPORT_SYMBOLS is defined. If neither of the two macros is defined, then PUBLIC_SYMBOL expands to nothing. PRIVATE_SYMBOL expands to HIDDEN_SYMBOL if either of the two macros is defined, and nothing otherwise.