diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fee18d22c7..0750f95e63 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -486,6 +486,175 @@ jobs: cd ../boost-root/__build__ cmake --build . --target tests + posix-cmake-subdir: + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-22.04 + - os: ubuntu-24.04 + - os: macos-15 + + runs-on: ${{matrix.os}} + + steps: + - uses: actions/checkout@v4 + + - name: Use library with add_subdirectory (header-only) + run: | + cd test/cmake_subdir_test + mkdir __build__ && cd __build__ + cmake .. + cmake --build . + ctest --output-on-failure --no-tests=error + + posix-cmake-subdir-legacy: + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-22.04 + - os: ubuntu-24.04 + - os: macos-15 + + runs-on: ${{matrix.os}} + + steps: + - uses: actions/checkout@v4 + + - name: Setup Boost + run: | + echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY + LIBRARY=${GITHUB_REPOSITORY#*/} + echo LIBRARY: $LIBRARY + echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV + echo GITHUB_BASE_REF: $GITHUB_BASE_REF + echo GITHUB_REF: $GITHUB_REF + REF=${GITHUB_BASE_REF:-$GITHUB_REF} + REF=${REF#refs/heads/} + echo REF: $REF + BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true + echo BOOST_BRANCH: $BOOST_BRANCH + cd .. + git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root + cd boost-root + mkdir -p libs/$LIBRARY + cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY + git submodule update --init tools/boostdep + python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY + + - name: Use library with add_subdirectory (legacy compiled) + run: | + cd ../boost-root/libs/$LIBRARY/test/cmake_subdir_test_legacy + mkdir __build__ && cd __build__ + cmake .. + cmake --build . + ctest --output-on-failure --no-tests=error + + posix-cmake-install: + strategy: + fail-fast: false + matrix: + include: + - os: macos-15 + + runs-on: ${{matrix.os}} + + steps: + - uses: actions/checkout@v4 + + - name: Setup Boost + run: | + echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY + LIBRARY=${GITHUB_REPOSITORY#*/} + echo LIBRARY: $LIBRARY + echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV + echo GITHUB_BASE_REF: $GITHUB_BASE_REF + echo GITHUB_REF: $GITHUB_REF + REF=${GITHUB_BASE_REF:-$GITHUB_REF} + REF=${REF#refs/heads/} + echo REF: $REF + BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true + echo BOOST_BRANCH: $BOOST_BRANCH + cd .. + git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root + cd boost-root + mkdir -p libs/$LIBRARY + cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY + git submodule update --init tools/boostdep + python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY + + - name: Configure + run: | + cd ../boost-root + mkdir __build__ && cd __build__ + cmake -DBOOST_INCLUDE_LIBRARIES=$LIBRARY -DCMAKE_INSTALL_PREFIX=~/.local .. + + - name: Install + run: | + cd ../boost-root/__build__ + cmake --build . --target install + + - name: Use the installed library (header-only) + run: | + cd ../boost-root/libs/$LIBRARY/test/cmake_install_test + mkdir __build__ && cd __build__ + cmake -DCMAKE_INSTALL_PREFIX=~/.local .. + cmake --build . + ctest --output-on-failure --no-tests=error + + posix-cmake-install-legacy: + strategy: + fail-fast: false + matrix: + include: + - os: macos-15 + + runs-on: ${{matrix.os}} + + steps: + - uses: actions/checkout@v4 + + - name: Setup Boost + run: | + echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY + LIBRARY=${GITHUB_REPOSITORY#*/} + echo LIBRARY: $LIBRARY + echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV + echo GITHUB_BASE_REF: $GITHUB_BASE_REF + echo GITHUB_REF: $GITHUB_REF + REF=${GITHUB_BASE_REF:-$GITHUB_REF} + REF=${REF#refs/heads/} + echo REF: $REF + BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true + echo BOOST_BRANCH: $BOOST_BRANCH + cd .. + git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root + cd boost-root + mkdir -p libs/$LIBRARY + cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY + git submodule update --init tools/boostdep + python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY + + - name: Configure + run: | + cd ../boost-root + mkdir __build__ && cd __build__ + cmake -DBOOST_INCLUDE_LIBRARIES=$LIBRARY -DBOOST_MATH_BUILD_WITH_LEGACY_FUNCTIONS=ON -DCMAKE_INSTALL_PREFIX=~/.local .. + + - name: Install + run: | + cd ../boost-root/__build__ + cmake --build . --target install + + - name: Use the installed library (legacy compiled) + run: | + cd ../boost-root/libs/$LIBRARY/test/cmake_install_test_legacy + mkdir __build__ && cd __build__ + cmake -DCMAKE_INSTALL_PREFIX=~/.local .. + cmake --build . + ctest --output-on-failure --no-tests=error + sycl-cmake-test: strategy: fail-fast: false diff --git a/CMakeLists.txt b/CMakeLists.txt index b789eb22aa..e2d6c055d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,6 +46,128 @@ endif() target_compile_features(boost_math INTERFACE cxx_std_14) +# Legacy C99/TR1 compiled libraries +option(BOOST_MATH_BUILD_WITH_LEGACY_FUNCTIONS "Build the C99 and TR1 compiled libraries" OFF) + +if(BOOST_MATH_BUILD_WITH_LEGACY_FUNCTIONS) + +include(CheckCXXSourceCompiles) +get_target_property(_config_type Boost::config TYPE) +if(_config_type STREQUAL "INTERFACE_LIBRARY") + get_target_property(_config_inc Boost::config INTERFACE_INCLUDE_DIRECTORIES) +else() + set(_config_inc "") +endif() +set(CMAKE_REQUIRED_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/include" ${_config_inc}) +check_cxx_source_compiles("#include <${CMAKE_CURRENT_SOURCE_DIR}/config/has_long_double_support.cpp> \n int main() { return 0;}" BOOST_MATH_HAS_LONG_DOUBLE) +unset(CMAKE_REQUIRED_INCLUDES) + +set(C99_SOURCES + acosh + asinh + atanh + cbrt + copysign + erfc + erf + expm1 + fmax + fmin + fpclassify + hypot + lgamma + llround + log1p + lround + nextafter + nexttoward + round + tgamma + trunc +) + +set(TR1_SOURCES + assoc_laguerre + assoc_legendre + beta + comp_ellint_1 + comp_ellint_2 + comp_ellint_3 + cyl_bessel_i + cyl_bessel_j + cyl_bessel_k + cyl_neumann + ellint_1 + ellint_2 + ellint_3 + expint + hermite + laguerre + legendre + riemann_zeta + sph_bessel + sph_legendre + sph_neumann +) + +list(TRANSFORM C99_SOURCES PREPEND "src/tr1/") +list(TRANSFORM TR1_SOURCES PREPEND "src/tr1/") + +list(TRANSFORM C99_SOURCES APPEND "f.cpp" OUTPUT_VARIABLE C99_SOURCESf) +list(TRANSFORM TR1_SOURCES APPEND "f.cpp" OUTPUT_VARIABLE TR1_SOURCESf) + +set(types "" f) + +if(BOOST_MATH_HAS_LONG_DOUBLE) + list(TRANSFORM C99_SOURCES APPEND "l.cpp" OUTPUT_VARIABLE C99_SOURCESl) + list(TRANSFORM TR1_SOURCES APPEND "l.cpp" OUTPUT_VARIABLE TR1_SOURCESl) + list(APPEND types l) +endif() + +list(TRANSFORM C99_SOURCES APPEND ".cpp") +list(TRANSFORM TR1_SOURCES APPEND ".cpp") + +foreach(type IN LISTS types) + add_library(boost_math_tr1${type} ${TR1_SOURCES${type}}) + add_library(Boost::math_tr1${type} ALIAS boost_math_tr1${type}) + target_link_libraries(boost_math_tr1${type} PUBLIC Boost::config) + target_include_directories(boost_math_tr1${type} PRIVATE src/tr1) + target_include_directories(boost_math_tr1${type} PRIVATE include) + + add_library(boost_math_c99${type} ${C99_SOURCES${type}}) + add_library(Boost::math_c99${type} ALIAS boost_math_c99${type}) + target_link_libraries(boost_math_c99${type} PUBLIC Boost::config) + target_include_directories(boost_math_c99${type} PRIVATE src/tr1) + target_include_directories(boost_math_c99${type} PRIVATE include) + + if(BUILD_SHARED_LIBS) + target_compile_definitions(boost_math_tr1${type} PUBLIC BOOST_MATH_TR1_DYN_LINK=1) + target_compile_definitions(boost_math_c99${type} PUBLIC BOOST_MATH_TR1_DYN_LINK=1) + if(MSVC) + target_compile_definitions(boost_math_tr1${type} PRIVATE "BOOST_SYMBOL_EXPORT=__declspec(dllexport)" BOOST_ALL_NO_LIB) + target_compile_definitions(boost_math_c99${type} PRIVATE "BOOST_SYMBOL_EXPORT=__declspec(dllexport)" BOOST_ALL_NO_LIB) + endif() + endif() + + target_compile_features(boost_math_tr1${type} PUBLIC cxx_std_14) + target_compile_features(boost_math_c99${type} PUBLIC cxx_std_14) + + if(APPLE) + target_compile_definitions(boost_math_tr1${type} PRIVATE _DARWIN_C_SOURCE) + target_compile_definitions(boost_math_c99${type} PRIVATE _DARWIN_C_SOURCE) + endif() +endforeach() + +if(BOOST_SUPERPROJECT_VERSION AND NOT CMAKE_VERSION VERSION_LESS 3.13) + set(boost_math_legacy_targets "") + foreach(type IN LISTS types) + list(APPEND boost_math_legacy_targets boost_math_c99${type} boost_math_tr1${type}) + endforeach() + boost_install(TARGETS ${boost_math_legacy_targets} VERSION "${BOOST_SUPERPROJECT_VERSION}") +endif() + +endif() + if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt") add_subdirectory(test) diff --git a/test/cmake_install_test/CMakeLists.txt b/test/cmake_install_test/CMakeLists.txt new file mode 100644 index 0000000000..010d5e9fe3 --- /dev/null +++ b/test/cmake_install_test/CMakeLists.txt @@ -0,0 +1,17 @@ +# Copyright 2025 Matt Borland +# Distributed under the Boost Software License, Version 1.0. +# https://www.boost.org/LICENSE_1_0.txt + +cmake_minimum_required(VERSION 3.8...3.16) + +project(cmake_install_test LANGUAGES CXX) + +find_package(boost_math REQUIRED) + +add_executable(quick ../quick.cpp) +target_link_libraries(quick Boost::math) + +enable_testing() +add_test(quick quick) + +add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $) diff --git a/test/cmake_install_test_legacy/CMakeLists.txt b/test/cmake_install_test_legacy/CMakeLists.txt new file mode 100644 index 0000000000..b5db787104 --- /dev/null +++ b/test/cmake_install_test_legacy/CMakeLists.txt @@ -0,0 +1,19 @@ +# Copyright 2025 Matt Borland +# Distributed under the Boost Software License, Version 1.0. +# https://www.boost.org/LICENSE_1_0.txt + +cmake_minimum_required(VERSION 3.8...3.16) + +project(cmake_install_test_legacy LANGUAGES CXX) + +find_package(boost_math REQUIRED) +find_package(boost_math_c99 REQUIRED) +find_package(boost_math_tr1 REQUIRED) + +add_executable(quick_tr1 ../quick_tr1.cpp) +target_link_libraries(quick_tr1 Boost::math Boost::math_c99 Boost::math_tr1) + +enable_testing() +add_test(quick_tr1 quick_tr1) + +add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $) diff --git a/test/cmake_subdir_test/CMakeLists.txt b/test/cmake_subdir_test/CMakeLists.txt new file mode 100644 index 0000000000..09d57446d7 --- /dev/null +++ b/test/cmake_subdir_test/CMakeLists.txt @@ -0,0 +1,18 @@ +# Copyright 2025 Matt Borland +# Distributed under the Boost Software License, Version 1.0. +# https://www.boost.org/LICENSE_1_0.txt + +cmake_minimum_required(VERSION 3.8...3.20) + +project(cmake_subdir_test LANGUAGES CXX) + +# Math is header-only and standalone by default (no deps needed) +add_subdirectory(../.. boostorg/math) + +add_executable(quick ../quick.cpp) +target_link_libraries(quick Boost::math) + +enable_testing() +add_test(quick quick) + +add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $) diff --git a/test/cmake_subdir_test_legacy/CMakeLists.txt b/test/cmake_subdir_test_legacy/CMakeLists.txt new file mode 100644 index 0000000000..c606705fa0 --- /dev/null +++ b/test/cmake_subdir_test_legacy/CMakeLists.txt @@ -0,0 +1,23 @@ +# Copyright 2025 Matt Borland +# Distributed under the Boost Software License, Version 1.0. +# https://www.boost.org/LICENSE_1_0.txt + +cmake_minimum_required(VERSION 3.8...3.20) + +project(cmake_subdir_test_legacy LANGUAGES CXX) + +# config must be added before math (compiled targets depend on Boost::config) +add_subdirectory(../../../config boostorg/config) + +# Enable legacy compiled targets before adding math +set(BOOST_MATH_BUILD_WITH_LEGACY_FUNCTIONS ON CACHE BOOL "" FORCE) + +add_subdirectory(../.. boostorg/math) + +add_executable(quick_tr1 ../quick_tr1.cpp) +target_link_libraries(quick_tr1 Boost::math Boost::math_c99 Boost::math_tr1) + +enable_testing() +add_test(quick_tr1 quick_tr1) + +add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $) diff --git a/test/quick.cpp b/test/quick.cpp new file mode 100644 index 0000000000..30ac1b896b --- /dev/null +++ b/test/quick.cpp @@ -0,0 +1,17 @@ +// Copyright 2026 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include + +int main() +{ + auto result = boost::math::tgamma(2.0); + // tgamma(2) == 1! == 1.0 + if (result < 0.99 || result > 1.01) + { + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} diff --git a/test/quick_tr1.cpp b/test/quick_tr1.cpp new file mode 100644 index 0000000000..33e21a1495 --- /dev/null +++ b/test/quick_tr1.cpp @@ -0,0 +1,26 @@ +// Copyright 2026 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include + +int main() +{ + // boost_cbrt from boost_math_c99 + auto cbrt_result = boost::math::tr1::boost_cbrt(8.0); + if (cbrt_result < 1.99 || cbrt_result > 2.01) + { + return EXIT_FAILURE; + } + + // boost_riemann_zeta from boost_math_tr1 + // zeta(2) == pi^2/6 ~= 1.6449 + auto zeta_result = boost::math::tr1::boost_riemann_zeta(2.0); + if (zeta_result < 1.64 || zeta_result > 1.65) + { + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +}