Skip to content

Commit

Permalink
Feature/headless impl (#3)
Browse files Browse the repository at this point in the history
Add option for headless mode
move exception and none-exception impl to different headers
replace "friend" with a member function for find_function and add free function for convenience.
add preset for header-only
  • Loading branch information
doocman authored Jun 11, 2024
1 parent abd3424 commit 5334ecc
Show file tree
Hide file tree
Showing 14 changed files with 355 additions and 197 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@

# IDE-specifics
.idea
.vs

# common build out-folders:
out-*
Expand Down
40 changes: 22 additions & 18 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ set(DYNLOAD_USE_EXCEPTIONS ON CACHE BOOL "Standard C++ uses exceptions, thus, th
set(DYNLOAD_IMPORT ON CACHE BOOL "Set to true if needing importing part of DYNLOAD")
set(DYNLOAD_EXPORT ON CACHE BOOL "Set to true if needing exporting part of DYNLOAD")
set(DYNLOAD_COMPILE_PLATFORM ON CACHE BOOL "If true, dynl will be automatically compiled for the target platform. Set to false if custom backend is needed.")
set(DYNLOAD_HEADERONLY OFF CACHE BOOL "Set to true to use dynload as a header-only library")

add_library(dynl_compile_opts INTERFACE)
add_library(dynl::compile_opts ALIAS dynl_compile_opts)
Expand All @@ -29,43 +30,46 @@ if (DYNLOAD_IMPORT)
)
target_compile_features(dynl_headers INTERFACE cxx_std_20)

add_library(dynl_shared)
add_library(dynl::dynl_shared ALIAS dynl_shared)
target_link_libraries(dynl_shared PUBLIC
dynl::dynl_headers
${DYNLOAD_DEV_LINK}
)
target_sources(dynl_shared PRIVATE
src/dynl_shared.cpp
)
if (DYNLOAD_USE_EXCEPTIONS)
else ()
target_compile_definitions(dynl_shared PRIVATE
"DYNLOAD_NO_EXCEPTIONS=1"
)
endif ()

if (DYNLOAD_HEADERONLY)
set(DYNLOAD_LIB_TYPE INTERFACE)
set(DYNLOAD_PUBLIC_LINK_TYPE INTERFACE)
else ()
set(DYNLOAD_LIB_TYPE "")
set(DYNLOAD_PUBLIC_LINK_TYPE PUBLIC)
endif ()

add_library(dynl)
add_library(dynl ${DYNLOAD_LIB_TYPE})
add_library(dynl::dynl ALIAS dynl)
target_link_libraries(dynl PUBLIC
dynl::dynl_shared
target_link_libraries(dynl ${DYNLOAD_PUBLIC_LINK_TYPE}
dynl::dynl_headers
${DYNLOAD_DEV_LINK}
)
if (DYNLOAD_COMPILE_PLATFORM)
if (WIN32)
target_sources(dynl PRIVATE
src/dynl_win32.cpp
)
set(DYNL_SRC src/dynl_win32.cpp)
set(DYNL_PLATFORM DYNL_WINDOWS=1)
elseif (UNIX)
target_sources(dynl PRIVATE
src/dynl_unix.cpp
)
set(DYNL_SRC src/dynl_unix.cpp)
set(DYNL_PLATFORM DYNL_UNIX=1)
else ()
message(SEND_ERROR "Dynload: no automatic backend available! Use custom defined source file")
endif ()
else ()
message(STATUS "Dynload: no automatic backend. Custom defined source-file(-s) for 'dynl' required")
set(DYNL_SRC "")
set(DYNL_PLATFORM "")
endif ()
if(DYNLOAD_HEADERONLY)
target_compile_definitions(dynl INTERFACE DYNLOAD_HEADERONLY=1 ${DYNL_PLATFORM})
else ()
target_sources(dynl PRIVATE ${DYNL_SRC})
endif ()
endif ()
if (DYNLOAD_EXPORT)
Expand Down
48 changes: 45 additions & 3 deletions CMakePresets.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@
"DYNLOAD_DEVELOP": true
}
},
{
"name": "dynl-headeronly",
"hidden": true,
"cacheVariables": {
"DYNLOAD_HEADERONLY": true
}
},
{
"name": "msvc-warnings",
"hidden": true,
Expand Down Expand Up @@ -56,7 +63,7 @@
"lhs": "${hostSystemName}",
"rhs": "Windows"
},
"inherits": ["msvc-warnings", "dynl-dev", "windows-test-include"],
"inherits": [ "msvc-warnings", "dynl-dev", "windows-test-include" ],
"cacheVariables": {
"CMAKE_CXX_COMPILER": "cl",
"CMAKE_C_COMPILER": "cl"
Expand All @@ -66,7 +73,7 @@
{
"name": "clang-base",
"hidden": true,
"inherits": ["clang-warnings", "dynl-dev"],
"inherits": [ "clang-warnings", "dynl-dev" ],
"cacheVariables": {
"CMAKE_CXX_COMPILER": "clang++",
"CMAKE_C_COMPILER": "clang"
Expand All @@ -76,7 +83,7 @@
{
"name": "gcc-base",
"hidden": true,
"inherits": ["gcc-warnings", "dynl-dev", "linux-test-include"],
"inherits": [ "gcc-warnings", "dynl-dev", "linux-test-include" ],
"cacheVariables": {
"CMAKE_CXX_COMPILER": "g++",
"CMAKE_C_COMPILER": "gcc"
Expand All @@ -102,6 +109,18 @@
},
"installDir": "${sourceDir}/install/msvc22-debug"
},
{
"name": "msvc22-hh-debug",
"binaryDir": "${sourceDir}/build/msvc22-hh-debug",
"installDir": "${sourceDir}/install/msvc22-hh-debug",
"inherits": [
"msvc-base",
"dynl-headeronly"
],
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "msvc22-reldeb",
"binaryDir": "${sourceDir}/build/msvc22-relwithdebinfo",
Expand All @@ -124,6 +143,18 @@
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "clang-hh-release",
"inherits": [
"clang-base",
"dynl-headeronly"
],
"binaryDir": "${sourceDir}/build/clang-hh-release",
"installDir": "${sourceDir}/install/clang-hh-release",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "gcc-release",
"inherits": [
Expand All @@ -134,6 +165,17 @@
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "gcc-hh-release",
"inherits": [
"gcc-base"
],
"binaryDir": "${sourceDir}/build/gcc-hh-release",
"installDir": "${sourceDir}/install/gcc-hh-release",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
}
]
}
98 changes: 18 additions & 80 deletions include/dynl/dynl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,84 +13,15 @@
#include <memory>

#include <dynl/dynl_error.hpp>
#include <dynl/dynl_types.hpp>

namespace dynl {
/// \typedef c_function_pointer
/// Template alias to make function pointer API readable.
template <typename T> using c_function_pointer = T *;

void _default_error_callback(dynl_error const &);
constexpr auto _default_error_callbacker = [](dynl_error const &err) {
_default_error_callback(err);
};

class dynamic_library;
class dynamic_function_symbol;

/// \class dynamic_library_pointer
/// Represents a raw dynamic library. It lacks any formal definition and is only
/// used for type safety. reinterpret_cast it to/from platform-dependent type
/// representing the dynamic library.
class dynamic_library_pointer;
namespace _backend {

/// Platform-dependent low-level dynamic library function access.
/// You must implement your own version of this when extending the code for
/// further platforms. If an error occurs, call err_cb with an appropriate error
/// and return nullptr.
/// \param p Path to library
/// \param err_cb Error handler. Default throws exception if enabled, otherwise
/// aborts with error message.
/// \return Library pointer. Can be null if err_cb returns without throwing.
dynamic_library_pointer *do_load_library(char const *p,
error_callback const &err_cb = {
_default_error_callbacker});

/// Platform-dependent low-level dynamic library function access.
/// You must implement your own version of this when extending the code for
/// further platforms.
/// \param p Pointer to library
void do_release_library(dynamic_library_pointer *p);

/// Platform-dependent low-level dynamic library function access.
/// You must implement your own version of this when extending the code for
/// further platforms. If an error occurs, call err_cb with an appropriate error
/// and return nullptr.
/// \param lib Library to search
/// \param name Function name to find
/// \param err_cb Error handler. Default throws exception if enabled, otherwise
/// aborts with error message.
/// \return Symbol, can be null if callback returns without throwing.
dynamic_function_symbol
do_find_function(dynamic_library_pointer *lib, char const *name,
error_callback const &err_cb = {_default_error_callbacker});
} // namespace _backend

/// \class dynamic_function_symbol
/// Represents a callable symbol from a dynamically loaded library.
/// The symbol lacks any type information and it is up to the user to
/// do the correct 'symbol_cast'.
class dynamic_function_symbol {
public:
using raw_cymbol_t = c_function_pointer<void()>;

private:
c_function_pointer<void()> raw_symbol_{};
#if defined(DYNLOAD_HEADERONLY)
#include <dynl/platform_details/dynl_headeronly.hpp>
#else
#include <dynl/platform_details/dynl_src.hpp>
#endif

public:
explicit constexpr dynamic_function_symbol(raw_cymbol_t rs) noexcept
: raw_symbol_(rs) {}
explicit(false) constexpr dynamic_function_symbol(std::nullptr_t) {}
constexpr dynamic_function_symbol() noexcept = default;

[[nodiscard]] constexpr bool valid() const noexcept {
return raw_symbol_ != nullptr;
}
constexpr explicit operator bool() const noexcept { return valid(); }

template <typename T>
friend c_function_pointer<T> symbol_cast(dynamic_function_symbol in);
};
namespace dynl {

/// Cast a dynamic_function_symbol to the specified function pointer.
/// Note, the symbol lacks any type information and as such the responsibility
Expand Down Expand Up @@ -133,14 +64,21 @@ class dynamic_library {
/// aborts with error message.
/// \return Function pointer. May be null if ecb returns without throwing.
template <typename T>
friend c_function_pointer<T>
find_function(dynamic_library const &in, char const *name,
error_callback const &ecb = {_default_error_callbacker}) {
auto res = _backend::do_find_function(in.lib_.get(), name, ecb);
c_function_pointer<T>
find_function(char const *name,
error_callback const &ecb = {_default_error_callbacker}) const {
auto res = _backend::do_find_function(lib_.get(), name, ecb);
return symbol_cast<T>(res);
}
[[nodiscard]] bool valid() const noexcept { return lib_ != nullptr; }
explicit operator bool() const noexcept { return valid(); }
};

template <typename T>
c_function_pointer<T>
find_function(dynamic_library const &in, char const *name,
error_callback const &ecb = {_default_error_callbacker}) {
return in.template find_function<T>(name, ecb);
}

} // namespace dynl
56 changes: 56 additions & 0 deletions include/dynl/dynl_types.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
///

#pragma once

#include <dynl/dynl_error.hpp>

#if defined(DYNLOAD_NO_EXCEPTIONS)
#include <dynl/platform_details/dynl_error_noexcept.hpp>
#else
#include <dynl/platform_details/dynl_error_except.hpp>
#endif

namespace dynl {
/// \typedef c_function_pointer
/// Template alias to make function pointer API readable.
template <typename T> using c_function_pointer = T *;

/// \class dynamic_library_pointer
/// Represents a raw dynamic library. It lacks any formal definition and is only
/// used for type safety. reinterpret_cast it to/from platform-dependent type
/// representing the dynamic library.
class dynamic_library_pointer;

constexpr auto _default_error_callbacker = [](dynl_error const &err) {
_default_error_callback(err);
};

class dynamic_library;

/// \class dynamic_function_symbol
/// Represents a callable symbol from a dynamically loaded library.
/// The symbol lacks any type information and it is up to the user to
/// do the correct 'symbol_cast'.
class dynamic_function_symbol {
public:
using raw_cymbol_t = c_function_pointer<void()>;

private:
c_function_pointer<void()> raw_symbol_{};

public:
explicit constexpr dynamic_function_symbol(raw_cymbol_t rs) noexcept
: raw_symbol_(rs) {}
explicit(false) constexpr dynamic_function_symbol(std::nullptr_t) {}
constexpr dynamic_function_symbol() noexcept = default;

[[nodiscard]] constexpr bool valid() const noexcept {
return raw_symbol_ != nullptr;
}
constexpr explicit operator bool() const noexcept { return valid(); }

template <typename T>
friend c_function_pointer<T> symbol_cast(dynamic_function_symbol in);
};

} // namespace dynl
15 changes: 15 additions & 0 deletions include/dynl/platform_details/dynl_error_except.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
///@file
/// Contains default error handling routines when exceptions are enabled.
///

#pragma once

#include <dynl/dynl_error.hpp>
#include <dynl/dynl_except.hpp>

namespace dynl {

inline void _default_error_callback(dynl_error const &err) {
throw dynl_except(err);
}
} // namespace dynl
19 changes: 19 additions & 0 deletions include/dynl/platform_details/dynl_error_noexcept.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
///@file
/// Contains default error handling routines when exceptions are disabled.
///

#pragma once

#include <cstdlib>
#include <iostream>

#include <dynl/dynl_error.hpp>

namespace dynl {

inline void _default_error_callback(dynl_error const &err) {
std::cerr << "Dynload error: " << message(err) << " (" << details(err)
<< ")\n";
std::abort();
}
} // namespace dynl
Loading

0 comments on commit 5334ecc

Please sign in to comment.