Skip to content

Commit

Permalink
Version 1.7.1 (#9)
Browse files Browse the repository at this point in the history
fix: better error messages
fix: documentation
fix: CMakeLists.txt
  • Loading branch information
martin-olivier authored Jan 19, 2022
1 parent 3669a4b commit 3c748b8
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 165 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ jobs:
- uses: actions/checkout@v2

- name: Generate Project Files
run: cmake . -B build/ -DCMAKE_BUILD_TYPE=Release
run: cmake . -B build -DBUILD_TESTS=ON

- name: Build Dynamic Library and Unit Tests
run: cmake --build build/
run: cmake --build build

- name: Run Unit Tests
run: ${{ matrix.dir }}${{ matrix.bin }}
Expand Down
104 changes: 11 additions & 93 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
cmake_minimum_required(VERSION 3.14)
project(dylib)

set(CMAKE_VERBOSE_MAKEFILE off)
set(CMAKE_VERBOSE_MAKEFILE OFF)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR})

option(WITH_TESTS "Enable testing" ON)
option(BUILD_TESTS "when set to ON, build unit tests" OFF)

if(WITH_TESTS)
include_directories(.)

if(BUILD_TESTS)
include(import/FetchGoogleTest.cmake)

if(UNIX)
Expand All @@ -20,26 +22,20 @@ elseif(WIN32)
add_compile_options(/W4)
endif()

add_library(dynlib SHARED test/myDynLib.cpp)
target_include_directories(dynlib PRIVATE .)
set_target_properties(dynlib PROPERTIES PREFIX "")
add_library(dynamic_lib SHARED test/dynamic_lib.cpp)
set_target_properties(dynamic_lib PROPERTIES PREFIX "")

enable_testing()

add_executable(unit_tests test/tests.cpp)

target_include_directories(unit_tests PRIVATE .)

if(UNIX AND NOT APPLE)
add_compile_options(--coverage)
target_link_libraries(unit_tests PRIVATE gcov)
endif()

if(UNIX)
target_link_libraries(unit_tests PRIVATE
dl
pthread
)
target_link_libraries(unit_tests PRIVATE dl)
endif()

target_link_libraries(unit_tests PRIVATE gtest_main)
Expand All @@ -48,84 +44,6 @@ include(GoogleTest)

gtest_discover_tests(unit_tests)

add_dependencies(unit_tests dynlib)
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 "7")
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}")
set(CPACK_RPM_PACKAGE_NAME "${CPACK_PACKAGE_NAME}")

include(CPackComponent)
include(CMakePackageConfigHelpers)

set(PackagingTemplatesDir "${CMAKE_CURRENT_SOURCE_DIR}/packaging")

set(LIB_NAME "dylib")
string(TOUPPER "${LIB_NAME}" LIB_NAME_UPPER)
set(CMAKE_EXPORT_NAME "${LIB_NAME}")
set(PKG_CONFIG_NAME "${LIB_NAME}")

cpack_add_component(dev
DISPLAY_NAME "${LIB_NAME} header"
DESCRIPTION "The header needed for using ${LIB_NAME} in own software"
)

install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/${LIB_NAME}.hpp"
TYPE INCLUDE
COMPONENT "dev"
)

set(PKG_CONFIG_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/${PKG_CONFIG_NAME}.pc")
configure_file("${PackagingTemplatesDir}/pkgconfig.pc.in" "${PKG_CONFIG_FILE_NAME}" @ONLY)
install(FILES "${PKG_CONFIG_FILE_NAME}"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig"
COMPONENT "dev"
)

set(CMAKE_CONFIG_FILE_BASENAME "${CMAKE_EXPORT_NAME}Config.cmake")
set(CMAKE_CONFIG_VERSION_FILE_BASENAME "${CMAKE_EXPORT_NAME}ConfigVersion.cmake")
set(CMAKE_CONFIG_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CONFIG_FILE_BASENAME}")
configure_package_config_file("${PackagingTemplatesDir}/CMakeConfig.cmake.in" "${CMAKE_CONFIG_FILE_NAME}"
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake"
)


set(CMAKE_CONFIG_VERSION_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CONFIG_VERSION_FILE_BASENAME}")
write_basic_package_version_file(
"${CMAKE_CONFIG_VERSION_FILE_NAME}"
VERSION "100500.100500.100500" # any version of same bitness suits. CMake cannot compare to infinity, so use a large number we expect to be greater than any future version
COMPATIBILITY AnyNewerVersion
)

install(FILES "${CMAKE_CONFIG_FILE_NAME}" "${CMAKE_CONFIG_VERSION_FILE_NAME}"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${CMAKE_EXPORT_NAME}"
COMPONENT "dev"
)

set("CPACK_DEBIAN_DEV_PACKAGE_NAME" "lib${LIB_NAME}-dev")
set("CPACK_DEBIAN_DEV_PACKAGE_DEPENDS" "libc6-dev")
set("CPACK_DEBIAN_DEV_PACKAGE_SUGGESTS" "cmake, pkg-config, pkg-conf")

set("CPACK_RPM_DEV_PACKAGE_NAME" "lib${LIB_NAME}-devel")
set("CPACK_RPM_DEV_PACKAGE_SUGGESTS" "${CPACK_DEBIAN_DEV_PACKAGE_SUGGESTS}")

set(CPACK_COMPONENTS_ALL "dev")

set(CPACK_PACKAGE_HOMEPAGE_URL "https://github.com/martin-olivier/dylib")
set(CPACK_PACKAGE_MAINTAINER "${CPACK_PACKAGE_VENDOR}")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "${CPACK_PACKAGE_MAINTAINER}")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
set(CPACK_PACKAGE_MAINTAINER "${CPACK_PACKAGE_VENDOR}")
set(CPACK_DEB_COMPONENT_INSTALL ON)
set(CPACK_RPM_COMPONENT_INSTALL ON)
set(CPACK_NSIS_COMPONENT_INSTALL ON)
set(CPACK_DEBIAN_COMPRESSION_TYPE "xz")

include(CPack)
add_dependencies(unit_tests dynamic_lib)

endif()
68 changes: 42 additions & 26 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.7.0-blue.svg)](https://github.com/martin-olivier/dylib/releases/tag/v1.7.0)
[![Dylib](https://img.shields.io/badge/Dylib-v1.7.1-blue.svg)](https://github.com/martin-olivier/dylib/releases/tag/v1.7.1)
[![MIT license](https://img.shields.io/badge/License-MIT-orange.svg)](https://github.com/martin-olivier/dylib/blob/main/LICENSE)
[![CPP Version](https://img.shields.io/badge/C++-11_and_above-darkgreen.svg)](https://isocpp.org/)

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

[![GitHub download](https://img.shields.io/github/downloads/martin-olivier/dylib/total?style=for-the-badge)](https://github.com/martin-olivier/dylib/releases/download/v1.7.0/dylib.hpp)
[![GitHub download](https://img.shields.io/github/downloads/martin-olivier/dylib/total?style=for-the-badge)](https://github.com/martin-olivier/dylib/releases/download/v1.7.1/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/martin-olivier/dylib/releases/download/v1.7.0/dylib.hpp) to download the dylib header file
Click [HERE](https://github.com/martin-olivier/dylib/releases/download/v1.7.1/dylib.hpp) to download the dylib header file
`⭐ Don't forget to put a star if you like the project!`

# Documentation
Expand All @@ -28,16 +28,16 @@ Click [HERE](https://github.com/martin-olivier/dylib/releases/download/v1.7.0/dy

The dylib class can load a dynamic library at runtime:
```c++
dylib lib("./myDynLib.so");
dylib lib("./dynamic_lib.so");
```
The dylib class can detect the file extension of the actual os using `dylib::extension`:
```c++
dylib lib("./myDynLib", dylib::extension);
dylib lib("./dynamic_lib", dylib::extension);
```
or
```c++
dylib lib;
lib.open("./myDynLib", dylib::extension);
lib.open("./dynamic_lib", dylib::extension);
```

## Open and Close
Expand All @@ -48,15 +48,15 @@ Load a dynamic library into the object. If a dynamic library was already opened,
`close`
Close the dynamic library currently loaded in the object. This function will be automatically called by the class destructor
```c++
// Load ./myDynLib.so
// Load ./dynamic_lib.so

dylib lib("./myDynLib.so");
dylib lib("./dynamic_lib.so");

// Unload ./myDynLib.so and load ./otherLib.so
// Unload ./dynamic_lib.so and load ./other_dynamic_lib.so

lib.open("./otherLib.so");
lib.open("./other_dynamic_lib.so");

// Close ./otherLib.so
// Close ./other_dynamic_lib.so

lib.close();
```
Expand All @@ -69,9 +69,9 @@ Get a function from the dynamic library currently loaded in the object.
`get_variable`
Get a global variable from the dynamic library currently loaded in the object.
```c++
// Load ./myDynLib.so
// Load ./dynamic_lib.so
dylib lib("./myDynLib.so");
dylib lib("./dynamic_lib.so");
// Get the global function adder
Expand Down Expand Up @@ -99,7 +99,7 @@ This usually happens when you forgot to put `DYLIB_API` before a library functio
Those exceptions inherit from `dylib::exception`
```c++
try {
dylib lib("./myDynLib.so");
dylib lib("./dynamic_lib.so");
double pi_value = lib.get_variable<double>("pi_value");
std::cout << pi_value << std::endl;
}
Expand All @@ -114,7 +114,7 @@ return EXIT_SUCCESS;

Let's write some functions in our forthcoming dynamic library:
```c++
// myDynLib.cpp
// dynamic_lib.cpp

#include <iostream>
#include "dylib.hpp"
Expand All @@ -129,13 +129,16 @@ DYLIB_API double adder(double a, double b)

DYLIB_API void print_hello()
{
std::cout << "Hello!" << std::endl;
std::cout << "Hello" << std::endl;
}
```
Let's build our code into a dynamic library:
`g++ -std=c++11 -fPIC -shared myDynLib.cpp -o myDynLib.so`
```cmake
add_library(dynamic_lib SHARED dynamic_lib.cpp)
set_target_properties(dynamic_lib PROPERTIES PREFIX "")
```

Let's try to access the functions and global variables of our dynamic library at runtime with this code:
```c++
Expand All @@ -147,7 +150,7 @@ Let's try to access the functions and global variables of our dynamic library at
int main()
{
try {
dylib lib("./myDynLib.so");
dylib lib("./dynamic_lib", dylib::extension);

auto adder = lib.get_function<double(double, double)>("adder");
std::cout << adder(5, 10) << std::endl;
Expand All @@ -170,30 +173,43 @@ int main()
}
```

Let's build and run our code:
`g++ -std=c++11 main.cpp -o out -ldl`
`./out`

Output:
Let's build our code:
```cmake
add_executable(bin main.cpp)
if(UNIX)
target_link_libraries(bin PRIVATE dl)
endif()
```

Let's run our binary:
```sh
> ./bin
15
Hello!
Hello
3.14159
1
```

# Tips

## Remove the lib prefix

> If you use CMake to build a dynamic library, running the below CMake rule will allow you to remove the prefix `lib` for macOS and linux, ensuring that the library shares the same name on all the different OS:
```cmake
set_target_properties(target PROPERTIES PREFIX "")
```

## Results

| | Without CMake rule | With CMake rule |
|:-------:|:----------------------|:----------------|
| Linux | ***lib***malloc.so | malloc.so |
| MacOS | ***lib***malloc.dylib | malloc.dylib |
| Windows | malloc.dll | malloc.dll |

## Build and run unit tests

```sh
cmake . -B build -DBUILD_TESTS=ON
cmake --build build
./unit_tests
```
Loading

0 comments on commit 3c748b8

Please sign in to comment.