diff --git a/.github/workflows/cpp-build.yml b/.github/workflows/build-and-test.yml similarity index 75% rename from .github/workflows/cpp-build.yml rename to .github/workflows/build-and-test.yml index 7c5215f..af40f50 100644 --- a/.github/workflows/cpp-build.yml +++ b/.github/workflows/build-and-test.yml @@ -144,3 +144,55 @@ jobs: --legend coverage_without_system_and_test_files lcov --list coverage_without_system_and_test_files shell: alpine.sh {0} + - uses: actions/upload-artifact@v4 + with: + name: coverage_${{ matrix.cpp_version }} + path: coverage + retention-days: 3 + + ctest: + name: "ctest" + needs: build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/download-artifact@v4 + with: + name: build_alpine-v3.20_g++_cpp17 + path: build + - name: Fix artifact permissions + run: chmod +x build/test/tests + + - uses: jirutka/setup-alpine@v1 + with: + branch: v3.20 + packages: > + cmake + ninja-build + g++ + boost-dev + boost-filesystem + boost-python3 + lua5.2-dev + python3-dev + fmt-dev + gtest-dev + - name: Fixup environment + run: | + ln -s /usr/lib/ninja-build/bin/ninja /usr/bin/ninja + ln -s liblua-5.2.so.0 /usr/lib/liblua-5.2.so + shell: alpine.sh --root {0} + + - name: Run cmake tests + run: | + cd build + ctest -R cmake_ --output-on-failure + env: + CMAKE_GENERATOR: Ninja + shell: alpine.sh {0} + - uses: actions/upload-artifact@v4 + if: success() || failure() + with: + name: cmake_tests_results + path: build/Testing/Temporary + retention-days: 2 diff --git a/.github/workflows/cmake-format.yml b/.github/workflows/cmake-format.yml index 1e92f53..ea24dd4 100644 --- a/.github/workflows/cmake-format.yml +++ b/.github/workflows/cmake-format.yml @@ -38,4 +38,4 @@ jobs: run: find . \( -path '*/.*' -prune \) -o \( -type f -a -name 'CMakeLists.txt' \) -exec echo "Format checking '{}'..." \; - -exec cmake-format --check -- {} + + -exec cmake-format --check --line-width=80 -- {} + diff --git a/.github/workflows/cmake-lint.yml b/.github/workflows/cmake-lint.yml index 5f1407b..5555e62 100644 --- a/.github/workflows/cmake-lint.yml +++ b/.github/workflows/cmake-lint.yml @@ -30,11 +30,13 @@ jobs: python-version: '3.13' cache-dependency-path: '.github/workflows/cmake-lint.yml' cache: 'pip' - - name: Install dependencies - run: pip install cmakelint + - name: Install CMake linting tool + run: pip install cmakelang - - name: Execute cmakelint + # Check all cmake files; ignore files in hidden directories; + # use increased line width since formatting is checked by other workflow + - name: Execute cmake-lint run: find . \( \( -path './build' -o -path '*/.*' \) -prune \) -o \( -type f -a -iname 'CMakeLists.txt' \) -exec echo "Linting '{}'..." \; - -exec cmakelint --spaces=1 {} + + -exec cmake-lint --line-width=90 -- {} + diff --git a/CMakeLists.txt b/CMakeLists.txt index fa5b942..7b49739 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,7 @@ option(PPPLUGIN_ENABLE_UNDEFINED_SANITIZE option(PPPLUGIN_ENABLE_UNREACHABLE_SANITIZE "Enable compilation with unreachable sanitize flags" OFF) -find_package(Boost 1.61.0 REQUIRED COMPONENTS headers filesystem) +find_package(Boost 1.70.0 REQUIRED CONFIG COMPONENTS headers filesystem) find_package(Python 3.0 REQUIRED COMPONENTS Development) find_package(Lua 5.2 REQUIRED) @@ -60,8 +60,6 @@ set(DEBUG_FLAGS "-g3") if(${PPPLUGIN_ENABLE_CPP17_COMPATIBILITY}) find_package(fmt 8.1.0 REQUIRED) set(CMAKE_CXX_STANDARD 17) - # TODO: generate C++17 compatible header files instead - add_definitions("-DPPPLUGIN_CPP17_COMPATIBILITY") else() set(CMAKE_CXX_STANDARD 20) endif() @@ -129,5 +127,6 @@ if(${PPPLUGIN_ENABLE_EXAMPLES}) add_subdirectory(examples) endif() if(${PPPLUGIN_ENABLE_TESTS}) + enable_testing() add_subdirectory(test) endif() diff --git a/cmake/ppplugin-config.cmake.in b/cmake/ppplugin-config.cmake.in index b6e2c5d..9d24d6b 100644 --- a/cmake/ppplugin-config.cmake.in +++ b/cmake/ppplugin-config.cmake.in @@ -6,6 +6,10 @@ find_dependency(Boost @Boost_VERSION_MAJOR@ COMPONENTS headers filesystem find_dependency(Python @Python_VERSION_MAJOR@ COMPONENTS Development) find_dependency(Lua @LUA_VERSION_MAJOR@) +if(${PPPLUGIN_ENABLE_CPP17_COMPATIBILITY}) + find_dependency(fmt @fmt_VERSION_MAJOR@) +endif() + check_required_components("@PROJECT_NAME@") set(PPPLUGIN_INCLUDE_DIR ${PACKAGE_PREFIX_DIR}/include) diff --git a/examples/lua_plugin/CMakeLists.txt b/examples/lua_plugin/CMakeLists.txt index 09c45f4..e5ea902 100644 --- a/examples/lua_plugin/CMakeLists.txt +++ b/examples/lua_plugin/CMakeLists.txt @@ -7,4 +7,5 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/plugin.lua $/plugin_1.lua COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/plugin.lua - $/plugin_2.lua) + $/plugin_2.lua + COMMENT "Copying Lua plugins to output directory...") diff --git a/examples/multi_language_plugin/CMakeLists.txt b/examples/multi_language_plugin/CMakeLists.txt index 6d83f4b..f54082a 100644 --- a/examples/multi_language_plugin/CMakeLists.txt +++ b/examples/multi_language_plugin/CMakeLists.txt @@ -11,11 +11,9 @@ add_custom_command( POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/plugins/lua_plugin.lua - $) -add_custom_command( - TARGET multi_language_plugin_manager - POST_BUILD + $ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/plugins/python_plugin.py - $) + $ + COMMENT "Copying plugins to output directory...") diff --git a/examples/multi_return_lua_plugin/CMakeLists.txt b/examples/multi_return_lua_plugin/CMakeLists.txt index 35b48fd..9d9ba39 100644 --- a/examples/multi_return_lua_plugin/CMakeLists.txt +++ b/examples/multi_return_lua_plugin/CMakeLists.txt @@ -6,4 +6,5 @@ add_custom_command( TARGET multi_return_lua_plugin_manager POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/plugin.lua - $) + $ + COMMENT "Copying Lua plugin to output directory...") diff --git a/examples/python_plugin/CMakeLists.txt b/examples/python_plugin/CMakeLists.txt index d4dea6d..75346b5 100644 --- a/examples/python_plugin/CMakeLists.txt +++ b/examples/python_plugin/CMakeLists.txt @@ -7,4 +7,5 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/plugin.py $/plugin_1.py COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/plugin.py - $/plugin_2.py) + $/plugin_2.py + COMMENT "Copying Python plugins to output directory...") diff --git a/include/ppplugin/errors.h b/include/ppplugin/errors.h index 0aa6749..c23d4e1 100644 --- a/include/ppplugin/errors.h +++ b/include/ppplugin/errors.h @@ -4,7 +4,6 @@ #include "ppplugin/detail/compatibility_utils.h" #include "ppplugin/expected.h" -#include #ifndef PPPLUGIN_CPP17_COMPATIBILITY #include #endif // PPPLUGIN_CPP17_COMPATIBILITY diff --git a/include/ppplugin/expected.h b/include/ppplugin/expected.h index 5f6768c..2fbf6ca 100644 --- a/include/ppplugin/expected.h +++ b/include/ppplugin/expected.h @@ -4,7 +4,7 @@ #include #include #include -#if __cplusplus >= 202101L +#if __cplusplus >= 202101L // if C++23 is available #include #endif // __cplusplus diff --git a/include/ppplugin/lua/lua_state.h b/include/ppplugin/lua/lua_state.h index 599e074..17c8555 100644 --- a/include/ppplugin/lua/lua_state.h +++ b/include/ppplugin/lua/lua_state.h @@ -7,6 +7,7 @@ #include "ppplugin/errors.h" #include +#include #include struct lua_State; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1be4a5f..bc5d063 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -15,15 +15,19 @@ set(LIBRARY_SOURCES add_library(${LIBRARY_TARGET} ${LIBRARY_SOURCES}) target_link_libraries( ${LIBRARY_TARGET} - PUBLIC Boost::filesystem - PUBLIC Python::Python PRIVATE ${LUA_LIBRARIES} - PUBLIC $<$:fmt::fmt>) + PUBLIC Boost::filesystem Python::Python + $<$:fmt::fmt>) target_include_directories( ${LIBRARY_TARGET} PRIVATE ${LUA_INCLUDE_DIR} PUBLIC $ - PUBLIC $) + $) +target_compile_definitions( + ${LIBRARY_TARGET} + PUBLIC + $<$:"PPPLUGIN_CPP17_COMPATIBILITY"> +) set_target_properties( ${LIBRARY_TARGET} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 90e9f6a..c143f8b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -6,6 +6,55 @@ add_executable(${TESTS_NAME} detail_templates_tests.cpp expected_tests.cpp scope_guard_tests.cpp) target_include_directories(${TESTS_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/include) -target_link_libraries( - ${TESTS_NAME} PRIVATE GTest::GTest GTest::Main gmock Threads::Threads - ${LIBRARY_TARGET_STATIC}) +target_link_libraries(${TESTS_NAME} PRIVATE GTest::GTest GTest::Main gmock + Threads::Threads ${LIBRARY_TARGET}) + +gtest_discover_tests(${TESTS_NAME}) + +add_test( + NAME cmake_shared_cpp17_compatible_installation_test + COMMAND + test.sh ${CMAKE_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR}/cmake_find_package_test_build + ${CMAKE_CURRENT_BINARY_DIR}/test_install_root_shared_cpp17 "SHARED" "Cpp17" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/cmake_tests/find_package_test) +add_test( + NAME cmake_shared_cpp20_compatible_installation_test + COMMAND + test.sh ${CMAKE_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR}/cmake_find_package_test_build + ${CMAKE_CURRENT_BINARY_DIR}/test_install_root_shared_cpp20 "SHARED" "Cpp20" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/cmake_tests/find_package_test) +add_test( + NAME cmake_static_cpp17_compatible_installation_test + COMMAND + test.sh ${CMAKE_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR}/cmake_find_package_test_build + ${CMAKE_CURRENT_BINARY_DIR}/test_install_root_static_cpp17 "STATIC" "Cpp17" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/cmake_tests/find_package_test) +add_test( + NAME cmake_static_cpp20_compatible_installation_test + COMMAND + test.sh ${CMAKE_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR}/cmake_find_package_test_build + ${CMAKE_CURRENT_BINARY_DIR}/test_install_root_static_cpp20 "STATIC" "Cpp20" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/cmake_tests/find_package_test) + +add_test( + NAME cmake_no_shared_installation_test + COMMAND + test.sh ${CMAKE_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR}/cmake_find_package_test_build + ${CMAKE_CURRENT_BINARY_DIR}/test_install_root_shared_fail "SHARED_FAIL" + "Cpp20" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/cmake_tests/find_package_test) +set_property(TEST cmake_no_shared_installation_test PROPERTY WILL_FAIL TRUE) +add_test( + NAME cmake_no_static_installation_test + COMMAND + test.sh ${CMAKE_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR}/cmake_find_package_test_build + ${CMAKE_CURRENT_BINARY_DIR}/test_install_root_static_fail "STATIC_FAIL" + "Cpp20" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/cmake_tests/find_package_test) +set_property(TEST cmake_no_static_installation_test PROPERTY WILL_FAIL TRUE) diff --git a/test/cmake_tests/build_and_install_ppplugin.sh b/test/cmake_tests/build_and_install_ppplugin.sh new file mode 100755 index 0000000..e27f123 --- /dev/null +++ b/test/cmake_tests/build_and_install_ppplugin.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +set -e +set -x + +ROOT_SOURCE_DIR="${1}" +BUILD_DIR="${2}" +INSTALL_ROOT="${3}" +BUILD_SHARED="${4}" +BUILD_CPP17_COMPATIBLE="${5}" + +echo "Building ppplugin library (shared: ${BUILD_SHARED})..." + +echo "Use sources at '${ROOT_SOURCE_DIR}'..." +cmake "${ROOT_SOURCE_DIR}" -B "${BUILD_DIR}" -DPPPLUGIN_SHARED="${BUILD_SHARED}" -DPPPLUGIN_ENABLE_CPP17_COMPATIBILITY="${BUILD_CPP17_COMPATIBLE}" +echo "Build in '${BUILD_DIR}'..." +cmake --build "${BUILD_DIR}" +echo "Install to '${INSTALL_ROOT}'..." +cmake --install "${BUILD_DIR}" --prefix "${INSTALL_ROOT}/usr/local" diff --git a/test/cmake_tests/find_package_test/CMakeLists.txt b/test/cmake_tests/find_package_test/CMakeLists.txt new file mode 100644 index 0000000..2c087a4 --- /dev/null +++ b/test/cmake_tests/find_package_test/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.10 FATAL_ERROR) + +project(a) + +find_package(ppplugin REQUIRED) + +message(DEBUG "ppplugin found: ${ppplugin_FOUND}") +message(DEBUG "ppplugin should be shared library: ${PPPLUGIN_SHARED}") +message(DEBUG "ppplugin library dir: ${PPPLUGIN_LIBRARY_DIR}") +message(DEBUG "ppplugin include dir: ${PPPLUGIN_INCLUDE_DIR}") +message( + DEBUG + "ppplugin should be C++17 compatible: ${PPPLUGIN_ENABLE_CPP17_COMPATIBILITY}") + +if(${PPPLUGIN_ENABLE_CPP17_COMPATIBILITY}) + set(CMAKE_CXX_STANDARD 17) +else() + set(CMAKE_CXX_STANDARD 20) +endif() + +add_executable(a a.cpp) +target_link_libraries(a PUBLIC ppplugin::ppplugin) diff --git a/test/cmake_tests/find_package_test/a.cpp b/test/cmake_tests/find_package_test/a.cpp new file mode 100644 index 0000000..10471cd --- /dev/null +++ b/test/cmake_tests/find_package_test/a.cpp @@ -0,0 +1,13 @@ +#include + +#include + +int main(int argc, char* /*argv*/[]) +{ + auto plugin = ppplugin::LuaPlugin::load("a.lua"); + if (plugin) { + std::cout << plugin->call("Main", argc).value().value() << '\n'; + } else { + std::cerr << "Error: " << static_cast(plugin.error().value()) << '\n'; + } +} diff --git a/test/cmake_tests/find_package_test/a.lua b/test/cmake_tests/find_package_test/a.lua new file mode 100644 index 0000000..ce89077 --- /dev/null +++ b/test/cmake_tests/find_package_test/a.lua @@ -0,0 +1,3 @@ +function Main(a) + return a + 10 +end diff --git a/test/cmake_tests/find_package_test/test.sh b/test/cmake_tests/find_package_test/test.sh new file mode 100755 index 0000000..878d840 --- /dev/null +++ b/test/cmake_tests/find_package_test/test.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +set -e +set -x + +ROOT_SOURCE_DIR="${1}" +BUILD_DIR="${2}" +INSTALL_ROOT="${3}" + +if [ "${4}" = "SHARED" ] || [ "${4}" = "STATIC_FAIL" ]; then + TEST_SHARED=ON +elif [ "${4}" = "STATIC" ] || [ "${4}" = "SHARED_FAIL" ]; then + TEST_SHARED=OFF +else + echo "Fourth argument must be 'SHARED', 'STATIC', 'SHARED_FAIL' or 'STATIC_FAIL'" + return +fi + +if [ "${5}" = "Cpp17" ]; then + TEST_CPP17_COMPATIBILITY=ON +elif [ "${5}" = "Cpp20" ]; then + TEST_CPP17_COMPATIBILITY=OFF +else + echo "Fifth argument must be 'Cpp17' or 'Cpp20'" + return +fi + +TEST_BUILD_DIR="${BUILD_DIR}/shared_${TEST_SHARED}_cpp17_${TEST_CPP17_COMPATIBILITY}" +EXECUTABLE_NAME="${TEST_BUILD_DIR}/a" + +"${ROOT_SOURCE_DIR}/test/cmake_tests/build_and_install_ppplugin.sh" "${ROOT_SOURCE_DIR}" "${BUILD_DIR}/ppplugin_build_shared_${TEST_SHARED}_cpp17_${TEST_CPP17_COMPATIBILITY}" "${INSTALL_ROOT}" "${TEST_SHARED}" "${TEST_CPP17_COMPATIBILITY}" + +# if it is a test with expected failure, switch dependency to opposite library type to provoke error +if [ "${4}" = "SHARED_FAIL" ]; then + TEST_SHARED=ON + TEST_BUILD_DIR="${TEST_BUILD_DIR}_shared_fail" +elif [ "${4}" = "STATIC_FAIL" ]; then + TEST_SHARED=OFF + TEST_BUILD_DIR="${TEST_BUILD_DIR}_static_fail" +fi + +CMAKE_PREFIX_PATH="${INSTALL_ROOT}/usr/local/lib/cmake" \ + cmake . --log-level DEBUG -B "${TEST_BUILD_DIR}" -DPPPLUGIN_SHARED="${TEST_SHARED}" -DPPPLUGIN_ENABLE_CPP17_COMPATIBILITY="${TEST_CPP17_COMPATIBILITY}" +cmake --build "${TEST_BUILD_DIR}" + +"${EXECUTABLE_NAME}"