Skip to content

Commit

Permalink
Merge pull request #6 from tocola/dev
Browse files Browse the repository at this point in the history
feat: dlerror on unix && getVariable() returns a ref to <T>
  • Loading branch information
martin-olivier authored Oct 20, 2021
2 parents 70998ec + c18613f commit 4304f96
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 46 deletions.
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ endif(WITH_TESTS)
set(CPACK_PACKAGE_NAME "DyLib")
set(CPACK_PACKAGE_VENDOR "Martin Olivier")
set(CPACK_PACKAGE_VERSION_MAJOR "1")
set(CPACK_PACKAGE_VERSION_MINOR "5")
set(CPACK_PACKAGE_VERSION_PATCH "1")
set(CPACK_PACKAGE_VERSION_MINOR "6")
set(CPACK_PACKAGE_VERSION_PATCH "0")
set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
set(CPACK_PACKAGE_DESCRIPTION "Cross-platform Dynamic Library Loader for C++")
set(CPACK_DEBIAN_PACKAGE_NAME "${CPACK_PACKAGE_NAME}")
Expand Down
70 changes: 38 additions & 32 deletions DyLib.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* \file DyLib.hpp
* \brief Cross-platform Dynamic Library Loader
* \author Martin Olivier
* \version 1.5.1
* \version 1.6.0
*
* MIT License
* Copyright (c) 2021 Martin Olivier
Expand All @@ -29,6 +29,14 @@ class DyLib
{
return LoadLibrary(TEXT(path));
}
static std::string getHandleError(const std::string &name)
{
return "error while loading dynamic library : " + name;
}
static std::string getSymbolError(const std::string &name)
{
return "error while loading symbol : " + name;
}
FARPROC getSymbol(const char *name) const noexcept
{
return GetProcAddress(m_handle, name);
Expand All @@ -43,6 +51,20 @@ class DyLib
{
return dlopen(path, RTLD_NOW | RTLD_LOCAL);
}
static std::string getHandleError(const std::string &name)
{
auto err = dlerror();
if (!err)
return "error while loading dynamic library : " + name;
return err;
}
static std::string getSymbolError(const std::string &name)
{
auto err = dlerror();
if (!err)
return "error while loading symbol : " + name;
return err;
}
void *getSymbol(const char *name) const noexcept
{
return dlsym(m_handle, name);
Expand Down Expand Up @@ -77,7 +99,7 @@ class DyLib
};

/**
* This exception is thrown when the library failed to load
* This exception is thrown when the library failed to load
* or the library encountered symbol resolution issues
*
* @param message error message
Expand All @@ -89,7 +111,7 @@ class DyLib
};

/**
* This exception is thrown when the library failed to load a symbol.
* This exception is thrown when the library failed to load a symbol.
* This usually happens when you forgot to mark a library function or variable as extern "C"
*
* @param message error message
Expand All @@ -104,6 +126,7 @@ class DyLib
* Creates a dynamic library object
*/
constexpr DyLib() noexcept = default;

DyLib(const DyLib&) = delete;
DyLib& operator=(const DyLib&) = delete;

Expand Down Expand Up @@ -144,16 +167,11 @@ class DyLib
open(path.c_str());
}

DyLib(std::string &&path, const char *ext)
DyLib(std::string path, const char *ext)
{
open(std::move(path), ext);
}

DyLib(const std::string &path, const char *ext)
{
open(path, ext);
}

~DyLib()
{
close();
Expand All @@ -170,38 +188,26 @@ class DyLib
{
close();
if (!path)
throw handle_error("error while loading the dynamic library : (nullptr)");
throw handle_error(getHandleError("(nullptr)"));
m_handle = openLib(path);
if (!m_handle)
throw handle_error("error while loading the dynamic library : " + std::string(path));
throw handle_error(getHandleError(path));
}

void open(const std::string &path)
{
open(path.c_str());
}

void open(std::string &&path, const char *ext)
void open(std::string path, const char *ext)
{
close();
if (!ext)
throw handle_error("bad extension name : (nullptr)");
throw handle_error(getHandleError("bad extension name : (nullptr)"));
path += ext;
m_handle = openLib(path.c_str());
if (!m_handle)
throw handle_error("error while loading the dynamic library : " + path);
}

void open(const std::string &path, const char *ext)
{
close();
if (!ext)
throw handle_error("bad extension name : (nullptr)");
std::string path_ext(path);
path_ext += ext;
m_handle = openLib(path_ext.c_str());
if (!m_handle)
throw handle_error("error while loading the dynamic library : " + path_ext);
throw handle_error(getHandleError(path));
}

/**
Expand All @@ -219,10 +225,10 @@ class DyLib
if (!m_handle)
throw handle_error("error : no dynamic library loaded");
if (!name)
throw symbol_error("error while loading function : (nullptr)");
throw symbol_error(getSymbolError("(nullptr)"));
auto sym = getSymbol(name);
if (!sym)
throw symbol_error("error while loading function : " + std::string(name));
throw symbol_error(getSymbolError(name));
return reinterpret_cast<T *>(sym);
}

Expand All @@ -241,20 +247,20 @@ class DyLib
* @returns global variable of type <T>
*/
template<typename T>
T getVariable(const char *name) const
T &getVariable(const char *name) const
{
if (!m_handle)
throw handle_error("error : no dynamic library loaded");
if (!name)
throw symbol_error("error while loading global variable : (nullptr)");
throw symbol_error(getSymbolError("(nullptr)"));
auto sym = getSymbol(name);
if (!sym)
throw symbol_error("error while loading global variable : " + std::string(name));
throw symbol_error(getSymbolError(name));
return *reinterpret_cast<T *>(sym);
}

template<typename T>
T getVariable(const std::string &name) const
T &getVariable(const std::string &name) const
{
return getVariable<T>(name.c_str());
}
Expand Down
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# DyLib - Dynamic Library Loader for C++
[![DyLib](https://img.shields.io/badge/DyLib-v1.5.1-blue.svg)](https://github.com/tocola/DyLib/releases/tag/v1.5.1)
[![DyLib](https://img.shields.io/badge/DyLib-v1.6.0-blue.svg)](https://github.com/tocola/DyLib/releases/tag/v1.6.0)
[![MIT license](https://img.shields.io/badge/License-MIT-orange.svg)](https://github.com/tocola/DyLib/blob/main/LICENSE)
[![CPP Version](https://img.shields.io/badge/C++-11/14/17/20-darkgreen.svg)](https://isocpp.org/)

Expand All @@ -10,7 +10,7 @@
[![workflow](https://github.com/tocola/DyLib/actions/workflows/unit_tests.yml/badge.svg)](https://github.com/tocola/DyLib/actions/workflows/unit_tests.yml)
[![codecov](https://codecov.io/gh/tocola/DyLib/branch/main/graph/badge.svg?token=4V6A9B7PII)](https://codecov.io/gh/tocola/DyLib)

[![GitHub download](https://img.shields.io/github/downloads/tocola/DyLib/total?style=for-the-badge)](https://github.com/tocola/DyLib/releases/download/v1.5.1/DyLib.hpp)
[![GitHub download](https://img.shields.io/github/downloads/tocola/DyLib/total?style=for-the-badge)](https://github.com/tocola/DyLib/releases/download/v1.6.0/DyLib.hpp)

The goal of this C++ Library is to load dynamic libraries (.so, .dll, .dylib) and access its functions and global variables at runtime.

Expand All @@ -19,7 +19,7 @@ Works on `Linux`, `Windows`, `MacOS`

# Installation

Click [HERE](https://github.com/tocola/DyLib/releases/download/v1.5.1/DyLib.hpp) to download the DyLib header file
Click [HERE](https://github.com/tocola/DyLib/releases/download/v1.6.0/DyLib.hpp) to download the DyLib header file
`Don't forget to put a star on the project 🌟`

# Documentation
Expand Down Expand Up @@ -120,7 +120,7 @@ Lets write some functions in our future dynamic library :

extern "C" {
double pi_value = 3.14159;
void *ptr = nullptr;
void *ptr = (void *)1;

double adder(double a, double b)
{
Expand Down Expand Up @@ -159,9 +159,9 @@ int main()
double pi_value = lib.getVariable<double>("pi_value");
std::cout << pi_value << std::endl;

void *ptr = lib.getVariable<void *>("ptr");
if (ptr == nullptr)
std::cout << "nullptr" << std::endl;
auto &ptr = lib.getVariable<void *>("ptr");
if (ptr == (void *)1)
std::cout << "1" << std::endl;
}
catch (const DyLib::exception &e) {
std::cerr << e.what() << std::endl;
Expand All @@ -180,5 +180,5 @@ Output :
15
Hello!
3.14159
nullptr
1
```
2 changes: 1 addition & 1 deletion test/myDynLib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

extern "C" {
double pi_value = 3.14159;
void *ptr = nullptr;
void *ptr = (void *)1;

double adder(double a, double b)
{
Expand Down
29 changes: 26 additions & 3 deletions test/tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ TEST(exemple, exemple_test)
EXPECT_EQ(pi_value, 3.14159);

void *ptr = lib.getVariable<void *>("ptr");
EXPECT_EQ(ptr, nullptr);
EXPECT_EQ(ptr, (void *)1);
}
catch (const DyLib::exception &) {
EXPECT_EQ(true, false);
Expand All @@ -59,7 +59,8 @@ TEST(ctor, bad_library)
EXPECT_EQ(true, false);
}
catch (const DyLib::exception &e) {
EXPECT_EQ(std::string(e.what()), "error while loading the dynamic library : ./null.so");
e.what();
EXPECT_EQ(true, true);
}
}

Expand Down Expand Up @@ -132,6 +133,28 @@ TEST(getVariable, bad_symbol)
}
}

TEST(getVariable, alter_variables)
{
try {
DyLib lib(std::string("./dynlib"), DyLib::extension);
DyLib other(std::move(lib));
auto &pi = other.getVariable<double>("pi_value");
EXPECT_EQ(pi, 3.14159);
pi = 123;
auto &pi1 = other.getVariable<double>("pi_value");
EXPECT_EQ(pi1, 123);

auto &ptr = other.getVariable<void *>("ptr");
EXPECT_EQ(ptr, (void *)1);
ptr = &lib;
auto &ptr1 = other.getVariable<void *>("ptr");
EXPECT_EQ(ptr1, &lib);
}
catch (const DyLib::handle_error &) {
EXPECT_EQ(true, false);
}
}

TEST(bad_arguments, null_pointer)
{
try {
Expand Down Expand Up @@ -198,7 +221,7 @@ TEST(std_move, basic_test)
EXPECT_EQ(pi, 3.14159);
lib = std::move(other);
auto ptr = lib.getVariable<void *>("ptr");
EXPECT_EQ(ptr, nullptr);
EXPECT_EQ(ptr, (void *)1);
other.getVariable<double>("pi_value");
EXPECT_EQ(true, false);
}
Expand Down

0 comments on commit 4304f96

Please sign in to comment.