From 7e8379a6e40c4f46db2858eb5885c11af22f8443 Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Thu, 28 Apr 2022 12:27:59 +0200 Subject: [PATCH 1/4] Make the test library a compiled library Convert the header-only library to a compiled library which additionally depends (privately) on another compiled library (Boost.Atomic chosen as it has few other dependencies). This reproduces the runtime link failure of #155 when compiling shared libraries. --- CMakeLists.txt | 12 ++++++-- build/Jamfile.v2 | 25 +++++++++++++++ include/boost/boost-ci/boost_ci.hpp | 33 ++++++++------------ src/boost_ci.cpp | 47 +++++++++++++++++++++++++++++ test/Jamfile | 5 ++- test/cmake_test/CMakeLists.txt | 23 ++++++++++++-- 6 files changed, 117 insertions(+), 28 deletions(-) create mode 100644 build/Jamfile.v2 create mode 100644 src/boost_ci.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 2c1630d4..09f5ec45 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,16 +7,22 @@ cmake_minimum_required(VERSION 3.5...3.16) project(boost_ci VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX) -add_library(boost_boost_ci INTERFACE) +add_library(boost_boost_ci src/boost_ci.cpp) add_library(Boost::boost_ci ALIAS boost_boost_ci) -target_include_directories(boost_boost_ci INTERFACE include) +target_include_directories(boost_boost_ci PUBLIC include) target_link_libraries(boost_boost_ci - INTERFACE + PUBLIC Boost::config + PRIVATE + Boost::atomic ) +if(BUILD_SHARED_LIBS) + target_compile_definitions(boost_boost_ci PUBLIC BOOST_BOOST_CI_DYN_LINK) +endif() + if(BUILD_TESTING) add_subdirectory(test) endif() diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 new file mode 100644 index 00000000..40239514 --- /dev/null +++ b/build/Jamfile.v2 @@ -0,0 +1,25 @@ +# Boost CI Test Build Jamfile + +# Copyright (c) 2022 Alexander Grund +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE or www.boost.org/LICENSE_1_0.txt) + +import configure ; + +local requirements = + shared:BOOST_BOOST_CI_DYN_LINK=1 + /boost/atomic//boost_atomic + ; + +project boost/ci + : source-location ../src + : requirements $(requirements) + : usage-requirements $(requirements) + ; + +lib boost_ci + : boost_ci.cpp + ; + +boost-install boost_ci ; diff --git a/include/boost/boost-ci/boost_ci.hpp b/include/boost/boost-ci/boost_ci.hpp index b2d5f407..b5817fbb 100644 --- a/include/boost/boost-ci/boost_ci.hpp +++ b/include/boost/boost-ci/boost_ci.hpp @@ -11,6 +11,17 @@ #include #endif +// This define is usually set in boost//config.hpp +#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_BOOST_CI_DYN_LINK) +#ifdef BOOST_BOOST_CI_SOURCE +#define BOOST_BOOST_CI_DECL BOOST_SYMBOL_EXPORT +#else +#define BOOST_BOOST_CI_DECL BOOST_SYMBOL_IMPORT +#endif +#else +#define BOOST_BOOST_CI_DECL +#endif + namespace boost { namespace boost_ci @@ -21,25 +32,7 @@ namespace boost #define MSVC_VALUE false #endif - // Some function to test - BOOST_NOINLINE int get_answer(const bool isMsvc = MSVC_VALUE) - { - int answer; - // Specifically crafted condition to check for coverage from MSVC and non MSVC builds - if(isMsvc) - { - answer = 21; - } else - { - answer = 42; - } -#ifdef BOOST_NO_CXX11_SMART_PTR - return answer; -#else - // Just use some stdlib feature combined with a Boost.Config feature as demonstration - auto ptr = std::unique_ptr(new int(answer)); - return *ptr; -#endif - } + // Some function to test. Returns 41 for true, 42 otherwise + BOOST_BOOST_CI_DECL int get_answer(bool isMsvc = MSVC_VALUE); } } diff --git a/src/boost_ci.cpp b/src/boost_ci.cpp new file mode 100644 index 00000000..1c3a43cf --- /dev/null +++ b/src/boost_ci.cpp @@ -0,0 +1,47 @@ +// +// Copyright (c) 2022 Alexander Grund +// +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_BOOST_CI_SOURCE + +#include +// Just some dependency on another Boost library +#include + +// Some simple struct big enough so that the atomic is forced to use a lock +// forcing it to call into the library +struct X +{ + double x, y, z; + explicit X(int value = 0): x(value), y(value), z(value) {} +}; + +namespace boost +{ + namespace boost_ci + { + // Some function to test + int get_answer(const bool isMsvc) + { + boost::atomic answer; + // Specifically crafted condition to check for coverage from MSVC and non MSVC builds + if(isMsvc) + { + answer = X(21); + } else + { + answer = X(42); + } +#ifdef BOOST_NO_CXX11_SMART_PTR + return answer.load().x; +#else + // Just use some stdlib feature combined with a Boost.Config feature as demonstration + auto ptr = std::unique_ptr(new int(answer.load().x)); + return *ptr; +#endif + } + } +} diff --git a/test/Jamfile b/test/Jamfile index fdbbeaba..db979644 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -8,9 +8,8 @@ import os ; import testing ; -project boost/ci/test - : requirements - . +project : requirements + /boost/ci//boost_ci ; local B2_ADDRESS_MODEL = [ os.environ B2_ADDRESS_MODEL ] ; diff --git a/test/cmake_test/CMakeLists.txt b/test/cmake_test/CMakeLists.txt index 01efe823..429ada16 100644 --- a/test/cmake_test/CMakeLists.txt +++ b/test/cmake_test/CMakeLists.txt @@ -11,8 +11,27 @@ project(cmake_subdir_test LANGUAGES CXX) if(BOOST_CI_INSTALL_TEST) find_package(boost_boost_ci REQUIRED) else() - add_subdirectory(../.. boostorg/ci) - add_subdirectory(../../../config boostorg/config) + add_subdirectory(../.. boostorg/boost-ci) + + set(deps + # Primary dependencies + atomic + config + core + # Secondary dependencies + align + assert + predef + preprocessor + static_assert + throw_exception + type_traits + winapi + ) + + foreach(dep IN LISTS deps) + add_subdirectory(../../../${dep} boostorg/${dep}) + endforeach() endif() add_executable(main main.cpp) From 2a23623997c4e08efa78a2c2b5979f0a85779b62 Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Sat, 21 May 2022 10:29:39 +0200 Subject: [PATCH 2/4] Fix dynamic CMake subdir tests on Windows On Windows DLLs need to be either in PATH or in the same folder as the executable. The latter is easy to achieve by setting CMAKE_RUNTIME_OUTPUT_DIRECTORY which puts all runtime files (exe, dll, so) into the specified folder. So do that. --- .github/workflows/ci.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1df5176d..8a132fa9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -391,7 +391,12 @@ jobs: [ -d "$cmake_test_folder" ] || cmake_test_folder="$BOOST_ROOT/libs/$SELF/test/cmake_subdir_test" cd "$cmake_test_folder" mkdir __build_cmake_subdir_test__ && cd __build_cmake_subdir_test__ - cmake -G "${{matrix.generator}}" -DBOOST_CI_INSTALL_TEST=OFF -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DBUILD_SHARED_LIBS=${{matrix.build_shared}} .. + extra_args="" + # On Windows DLLs need to be either in PATH or in the same folder as the executable, so put all binaries into the same folder + if [[ "$RUNNER_OS" == "Windows" ]] && [[ "${{matrix.build_shared}}" == "ON" ]]; then + extra_args="-DCMAKE_RUNTIME_OUTPUT_DIRECTORY='$(pwd)/bin'" + fi + cmake -G "${{matrix.generator}}" -DBOOST_CI_INSTALL_TEST=OFF -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DBUILD_SHARED_LIBS=${{matrix.build_shared}} $extra_args .. cmake --build . --config ${{matrix.build_type}} -j$B2_JOBS ctest --output-on-failure --build-config ${{matrix.build_type}} From 2efd425f2cf9fce9ca07a6b9f60e832c4d108f30 Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Sat, 21 May 2022 10:45:56 +0200 Subject: [PATCH 3/4] Use a variable to store the install path for the CMake test Avoids the repetition. Use a subfolder of /tmp which is unlikely to exist. Additionally using $HOME may cause trouble due to path translation on Windows-Bash --- .github/workflows/ci.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8a132fa9..d08456ce 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -402,9 +402,11 @@ jobs: - name: Install Library run: | + BCM_INSTALL_PATH=/tmp/boost_install + echo "BCM_INSTALL_PATH=$BCM_INSTALL_PATH" >> $GITHUB_ENV cd "$BOOST_ROOT" mkdir __build_cmake_install_test__ && cd __build_cmake_install_test__ - cmake -G "${{matrix.generator}}" -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DBOOST_INCLUDE_LIBRARIES=$SELF -DBUILD_SHARED_LIBS=${{matrix.build_shared}} -DCMAKE_INSTALL_PREFIX=~/.local -DBoost_VERBOSE=ON -DBoost_DEBUG=ON .. + cmake -G "${{matrix.generator}}" -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DBOOST_INCLUDE_LIBRARIES=$SELF -DBUILD_SHARED_LIBS=${{matrix.build_shared}} -DCMAKE_INSTALL_PREFIX="$BCM_INSTALL_PATH" -DBoost_VERBOSE=ON -DBoost_DEBUG=ON .. cmake --build . --target install --config ${{matrix.build_type}} -j$B2_JOBS - name: Run CMake install tests run: | @@ -412,6 +414,6 @@ jobs: [ -d "$cmake_test_folder" ] || cmake_test_folder="$BOOST_ROOT/libs/$SELF/test/cmake_install_test" cd "$cmake_test_folder" mkdir __build_cmake_install_test__ && cd __build_cmake_install_test__ - cmake -G "${{matrix.generator}}" -DBOOST_CI_INSTALL_TEST=ON -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DBUILD_SHARED_LIBS=${{matrix.build_shared}} -DCMAKE_PREFIX_PATH=~/.local .. + cmake -G "${{matrix.generator}}" -DBOOST_CI_INSTALL_TEST=ON -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DBUILD_SHARED_LIBS=${{matrix.build_shared}} -DCMAKE_PREFIX_PATH="$BCM_INSTALL_PATH" .. cmake --build . --config ${{matrix.build_type}} -j$B2_JOBS ctest --output-on-failure --build-config ${{matrix.build_type}} From 96dab180e9aa0e0759aa179d24502e39dbfe7c97 Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Sat, 21 May 2022 10:56:57 +0200 Subject: [PATCH 4/4] Fix dynamic CMake install tests To find dynamic libraries which are only indirect dependencies the variable LD_LIBRARY_PATH (Linux) or PATH (Windows) must contain the folder of the binaries. --- .github/workflows/ci.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d08456ce..aaabaa71 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -416,4 +416,12 @@ jobs: mkdir __build_cmake_install_test__ && cd __build_cmake_install_test__ cmake -G "${{matrix.generator}}" -DBOOST_CI_INSTALL_TEST=ON -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DBUILD_SHARED_LIBS=${{matrix.build_shared}} -DCMAKE_PREFIX_PATH="$BCM_INSTALL_PATH" .. cmake --build . --config ${{matrix.build_type}} -j$B2_JOBS + if [[ "${{matrix.build_shared}}" == "ON" ]]; then + # Make sure shared libs can be found at runtime + if [ "$RUNNER_OS" == "Windows" ]; then + export PATH="$BCM_INSTALL_PATH/bin:$PATH" + else + export LD_LIBRARY_PATH="$BCM_INSTALL_PATH/lib:$LD_LIBRARY_PATH" + fi + fi ctest --output-on-failure --build-config ${{matrix.build_type}}