This project contains git sub-modules that are needed for building example and tests.
If you just want to use the implementation, you can clone without sub-modules. In case you want to build the example or tests, be sure to clone the repository
with --recurse-submodules or --recursive on older versions of git. Alternatively, you can clone without sub-modules and initialize these later.
function_loader is a header-only library that can find free functions in a shared library and provides std::function<T> wrapper around the found function.
Essentially represents a wrapper around the calls LoadLibrary, GetProcedure and FreeLibrary system calls on Windows and dlopen, dlsym and dlclose on POSIXes.
function_loader class supports move semantics and disables copy operations; implementation is in C++11.
These exceptions might be thrown:
library_load_failedlibrary_handle_invalidfunction_does_not_exist
Exceptions provide additional information about the reason using what(), see exceptions.hpp for more info.
In order to use the function_loader, it's the include directory that matters. Just make sure that the header search path is pointing to the include directory located in the root directory.
Implementation resides in the burda::function_loader namespace, so it might be useful to do something like namespace fe = burda::function_loader; in your project.
There are basically these options when it comes to build system integration:
Recommended option.
There are essentially these ways of how to use this package depending on your preferences our build architecture:
Call add_subdirectory(...) directly in your CMakeLists.txt:
add_executable(my-project main.cpp)
add_subdirectory(<path-to-function-loader>)
# example: add_subdirectory(function-loader ${CMAKE_BINARY_DIR}/function-loader)
# query of package version
message(STATUS "Current version of function-loader is: ${function-loader_VERSION}")
add_library(burda::function-loader ALIAS function-loader)
# this will import search paths, compile definitions and other dependencies of the function-loader as well
target_link_libraries(my-project function-loader)
# or with private visibility: target_link_libraries(my-project PRIVATE function-loader)Generation phase on the function-loader is run separately, that means that you run:
cmake <path-to-function-loader>
# example: cmake -Bbuild/function-loader -Hfunction-loader in the root of your project This will create automatically generated package configuration file function-loader-config.cmake that contains exported target and all important information.
Then you can do this in your CMakeLists.txt:
add_executable(my-project main.cpp)
find_package(function-loader CONFIG PATHS <path-to-binary-dir-of-function-loader>)
# alternatively assuming that the "function-loader_DIR" variable is set: find_package(function-loader CONFIG)
# you can also query (or force specific version during the previous "find_package()" call)
message(STATUS "Found version of function-loader is: ${function-loader_VERSION}")
# this will import search paths, compile definitions and other dependencies of the function-loader as well
target_link_libraries(my-project burda::function-loader)
# or with public visibility: target_link_libraries(my-project PUBLIC burda::function-loader)Not recommended.
Make sure that the include directory is in the search paths.
You also have to set C++ 11 standard and potentially other settings as well (e.g. linking libdl on POSIXes).
For full use cases, see main.cpp or implementation of unit tests at tests/unit.
#include <iostream>
#include <function_loader/exceptions.hpp>
#include <function_loader/function_loader.hpp>
namespace function_loader = burda::function_loader;
try
{
// or load DLL on Windows, or .dylib on OS X
function_loader::function_loader loader{ "./shared-library.so" };
// function_loader supports move semantics, so we can safely do e.g. "const auto other = std::move(loader)"
// get procedures at runtime from the shared library
// see "demo-library.hpp" and "demo-library.cpp" in the "demo-library" directory
const auto func_simple = loader.get_function<void()>("foo");
const auto func_more_complex = loader.get_function<int(float, const char *)>("bar");
// don't have to check for call-ability, otherwise the "function_does_not_exist" would be thrown
func_simple();
std::clog << "func_more_complex returned " << func_more_complex(99.0, "foo");
// if the "loader" object went out of scope in here, it would free all resources and unload
// the library handle, but for demo purposes, we'll move the instance
const auto another_loader = std::move(loader);
// do whatever actions you like with the "another_loader"
// the "another_loader" goes out of scope
}
catch (const function_loader::exceptions::library_load_failed & error)
{
// handle exception, error.what() contains information about the error code from the OS
// library load failed upon construction of the function_loader
}
catch (const function_loader::exceptions::library_handle_invalid & error)
{
// happens when "get_function" called on the function_loader with invalid library handle
// (may happen after the object was moved)
}
catch (const function_loader::exceptions::function_does_not_exist & error)
{
// given function not found in the library, might be caused by incorrect signature,
// or function is not exported (visible) from outside
}Where this is the header of the shared-library.(so|dll|dylib):
extern "C"
{
/// LIBRARY_EXPORT is defined elsewhere, but we just need the symbols to be visible from outside
/// the shared libary (e.g. using "__declspec(dllexport)" or "__attribute__((visibility("default")))" on the GCC).
/// When using function_loader, we don't need to import any symbols (e.g. "__declspec(dllimport)"),
/// because there's no static linking.
LIBRARY_EXPORT void foo();
LIBRARY_EXPORT int bar(float number, const char * str);
}Tests require sub-modules cmake-helpers and test-utils.
For building tests, run CMake in the source directory tests/unit:
cmake -Bbuild -H.
cmake -Bbuild/submodules/test-utils -Hsubmodules/test-utils
# you can also add coverage by appending "-DCOVERAGE:BOOL=ON"
cmake -Bbuild/tests/unit -Htests/unit
-Dfunction-loader_DIR:PATH=$(pwd)/build
-Dtest-utils_DIR:PATH=$(pwd)/build/submodules/test-utils
cmake --build build/tests/unit
# this runs target "run-all-tests-verbose" that will also run the tests with timeout, etc.:
cmake --build build/tests/unit --target run-all-tests-verboseThis is the example of running tests in the debug mode.
For more info, see .travis.yml.
Continuous Integration is now being run Linux, OS X and Windows on Travis: https://travis-ci.org/karel-burda/function-loader.
Compilers are set-up to treat warnings as errors and with pedantic warning level. Targets are built in one stage with debug symbols with code coverage measure and in release mode with debug symbols in the second one.
Valgrind is being run on the example as well.
The project is using these jobs:
function-loader, example, tests -- linux, debug, cppcheck, coverage, g++, 64-bitfunction-loader, example, tests -- osx, release with debug info, valgrind, clang++, 64-bitfunction-loader, example, tests -- windows, release, msvc, 32-bit
Project uses codecov.io for code coverage summary.