Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
348a583
Add C++20 module infrastructure and foundation components
mborland Jul 15, 2026
f9861a7
Guard std includes for module builds across all headers
mborland Jul 15, 2026
2a1c7af
Export the special functions for the boost.math module
mborland Jul 15, 2026
5ee0d77
Export the statistical distributions for the boost.math module
mborland Jul 15, 2026
8a5dcf9
Export ccmath for the boost.math module
mborland Jul 15, 2026
cf76357
Export the public tools for the boost.math module
mborland Jul 15, 2026
88d19ef
Export quadrature and the modern interpolators for the boost.math module
mborland Jul 15, 2026
39b0970
Export statistics and optimization for the boost.math module
mborland Jul 15, 2026
18f8fb7
Export differentiation and the algebra types for the boost.math module
mborland Jul 15, 2026
0fd6b77
Add documentation of module support
mborland Jul 15, 2026
f431389
Clarify that the module is consumable from C++20
mborland Jul 15, 2026
ff56f1c
Remove accidental commit test folder
mborland Jul 15, 2026
4014fa4
Silence the reserved module identifier warning in module builds
mborland Jul 15, 2026
5e49f1c
Add a GCC module test to CI
mborland Jul 15, 2026
5b18f2c
Fix doc inspection failure
mborland Jul 15, 2026
74fc0c0
Keep cstdfloat out of the module purview
mborland Jul 15, 2026
3986feb
Change module file extension and add extern "C++"
mborland Jul 16, 2026
e5b102e
Update references to file extension
mborland Jul 16, 2026
70ec7a7
Add CPPM to allowable extensions
mborland Jul 16, 2026
d89dc67
Remove workaround that doesn't work with modules
mborland Jul 16, 2026
3614727
Add MSVC modules testing
mborland Jul 16, 2026
f096e4a
Ignore clang warnings
mborland Jul 16, 2026
03b38db
Remove anonymous namespace breaking module linkage
mborland Jul 16, 2026
0246361
Attempt fix MSVC problem
mborland Jul 16, 2026
0270056
Fix John's initial issue
mborland Jul 17, 2026
2492498
Inline constexpr variable templates
mborland Jul 17, 2026
b76b7c4
Add tests for functions previously causing module linkage issues
mborland Jul 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
225 changes: 225 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -830,3 +830,228 @@ jobs:
# run: |
# cd ../boost-root/__build__
# ctest --output-on-failure --no-tests=error

cmake-module-test:
strategy:
fail-fast: false

runs-on: ubuntu-24.04

env:
# clang/libc++ version used to build the module. Needs a libc++ new enough to
# mix `import std` with textual libc++ includes (18 and 19 have std-module bugs).
LLVM_VERSION: "20"
# Pinned so the experimental `import std` feature UUID below stays valid.
CMAKE_VERSION: 4.4.0
# CMake gates `import std` behind this UUID; it is specific to the CMake version.
IMPORT_STD_UUID: f35a9ac6-8463-4d38-8eec-5d6008153e7d

steps:
- uses: actions/checkout@v6

- name: Install toolchain
run: |
# A recent clang + libc++ (for `import std`), clang-scan-deps (module
# dependency scanning), Ninja (required for C++ modules) and a pinned CMake.
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh $LLVM_VERSION
sudo apt-get install -y clang-tools-$LLVM_VERSION libc++-$LLVM_VERSION-dev libc++abi-$LLVM_VERSION-dev ninja-build
wget -q https://github.com/Kitware/CMake/releases/download/v$CMAKE_VERSION/cmake-$CMAKE_VERSION-linux-x86_64.tar.gz
sudo tar -xzf cmake-$CMAKE_VERSION-linux-x86_64.tar.gz -C /opt
echo "/opt/cmake-$CMAKE_VERSION-linux-x86_64/bin" >> "$GITHUB_PATH"

- 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
python3 tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY

- name: Configure
run: |
cd ../boost-root
mkdir __build__ && cd __build__
cmake -G Ninja \
-DBOOST_INCLUDE_LIBRARIES=$LIBRARY \
-DBUILD_TESTING=ON \
-DBOOST_MATH_BUILD_MODULE=ON \
-DCMAKE_CXX_COMPILER=clang++-$LLVM_VERSION \
-DCMAKE_CXX_FLAGS="-stdlib=libc++ -Wno-reserved-module-identifier" \
-DCMAKE_EXPERIMENTAL_CXX_IMPORT_STD=$IMPORT_STD_UUID \
-DCMAKE_CXX_STDLIB_MODULES_JSON=/usr/lib/llvm-$LLVM_VERSION/lib/libc++.modules.json \
..

# Kept as a separate step so the boost.math module build time is visible on its own.
- name: Build the Boost.Math module
run: |
cd ../boost-root/__build__
cmake --build . --target boost_math_module

- name: Build and run the tests
run: |
cd ../boost-root/__build__
cmake --build . --target tests
ctest --output-on-failure --no-tests=error

cmake-module-test-gcc:
strategy:
fail-fast: false

runs-on: ubuntu-latest

# GCC 15 (the first release with import std support and
# libstdc++.modules.json) is not packaged for the runner image, so the job
# runs in a container that ships it.
container: ubuntu:26.04

env:
GCC_VERSION: "15"
# Pinned so the experimental `import std` feature UUID below stays valid.
CMAKE_VERSION: 4.4.0
# CMake gates `import std` behind this UUID; it is specific to the CMake version.
IMPORT_STD_UUID: f35a9ac6-8463-4d38-8eec-5d6008153e7d

steps:
- name: Install toolchain
run: |
apt-get update
apt-get install -y g++-$GCC_VERSION gcc-$GCC_VERSION ninja-build wget ca-certificates git python3
wget -q https://github.com/Kitware/CMake/releases/download/v$CMAKE_VERSION/cmake-$CMAKE_VERSION-linux-x86_64.tar.gz
tar -xzf cmake-$CMAKE_VERSION-linux-x86_64.tar.gz -C /opt
echo "/opt/cmake-$CMAKE_VERSION-linux-x86_64/bin" >> "$GITHUB_PATH"

- uses: actions/checkout@v6

- 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
python3 tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY

- name: Configure
run: |
cd ../boost-root
mkdir __build__ && cd __build__
cmake -G Ninja \
-DBOOST_INCLUDE_LIBRARIES=$LIBRARY \
-DBUILD_TESTING=ON \
-DBOOST_MATH_BUILD_MODULE=ON \
-DCMAKE_C_COMPILER=gcc-$GCC_VERSION \
-DCMAKE_CXX_COMPILER=g++-$GCC_VERSION \
-DCMAKE_EXPERIMENTAL_CXX_IMPORT_STD=$IMPORT_STD_UUID \
..

# Kept as a separate step so the boost.math module build time is visible on its own.
- name: Build the Boost.Math module
run: |
cd ../boost-root/__build__
cmake --build . --target boost_math_module

- name: Build and run the tests
run: |
cd ../boost-root/__build__
cmake --build . --target tests
ctest --output-on-failure --no-tests=error

cmake-module-test-msvc:
strategy:
fail-fast: false

runs-on: windows-2025

env:
# Pinned so the experimental import std feature UUID below stays valid.
CMAKE_VERSION: 4.4.0
# CMake gates import std behind this UUID; it is specific to the CMake version.
IMPORT_STD_UUID: f35a9ac6-8463-4d38-8eec-5d6008153e7d

steps:
- uses: actions/checkout@v6

# Puts cl.exe and the MSVC INCLUDE/LIB environment on PATH for the later steps.
- name: Set up the MSVC environment
uses: ilammy/msvc-dev-cmd@v1

- name: Install toolchain
shell: pwsh
run: |
# A pinned CMake (the import std UUID is tied to the version) and Ninja
# (required for C++ modules).
curl.exe -L -o cmake.zip "https://github.com/Kitware/CMake/releases/download/v$env:CMAKE_VERSION/cmake-$env:CMAKE_VERSION-windows-x86_64.zip"
Expand-Archive -Path cmake.zip -DestinationPath C:\tools
"C:\tools\cmake-$env:CMAKE_VERSION-windows-x86_64\bin" | Out-File -FilePath $env:GITHUB_PATH -Append -Encoding utf8
choco install ninja -y

- name: Setup Boost
shell: pwsh
run: |
$LIBRARY = ($env:GITHUB_REPOSITORY -split '/')[-1]
"LIBRARY=$LIBRARY" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
$ref = if ($env:GITHUB_BASE_REF) { $env:GITHUB_BASE_REF } else { $env:GITHUB_REF }
$ref = $ref -replace '^refs/heads/', ''
$branch = if ($ref -eq 'master') { 'master' } else { 'develop' }
cd ..
git clone -b $branch --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
New-Item -ItemType Directory -Force -Path "libs/$LIBRARY" | Out-Null
Copy-Item -Recurse -Force "$env:GITHUB_WORKSPACE/*" "libs/$LIBRARY"
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY

- name: Configure
shell: pwsh
run: |
cd ../boost-root
New-Item -ItemType Directory -Force -Path __build__ | Out-Null
cd __build__
cmake -G Ninja `
-DBOOST_INCLUDE_LIBRARIES="$env:LIBRARY" `
-DBUILD_TESTING=ON `
-DBOOST_MATH_BUILD_MODULE=ON `
-DCMAKE_CXX_COMPILER=cl `
-DCMAKE_EXPERIMENTAL_CXX_IMPORT_STD="$env:IMPORT_STD_UUID" `
..

# Kept as a separate step so the boost.math module build time is visible on its own.
- name: Build the Boost.Math module
shell: pwsh
run: |
cd ../boost-root/__build__
cmake --build . --target boost_math_module

- name: Build and run the tests
shell: pwsh
run: |
cd ../boost-root/__build__
cmake --build . --target tests
ctest --output-on-failure --no-tests=error
1 change: 1 addition & 0 deletions doc/math.qbk
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,7 @@ and as a CD ISBN 0-9504833-2-X 978-0-9504833-2-0, Classification 519.2-dc22.
[include overview/result_type_calc.qbk]
[include overview/error_handling.qbk]
[include overview/gpu.qbk]
[include overview/modules.qbk]

[section:compilers_overview Compilers]
[compilers_overview]
Expand Down
57 changes: 57 additions & 0 deletions doc/overview/modules.qbk
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
[section:cxx20_modules Support for C++20 Modules]

[h4 C++20 Modules Support]

Boost.Math can be consumed as the named module `boost.math`.
The module covers the public interface of the library: special functions, statistical distributions, constants, policies, ccmath, the public tools (root finding, minima, polynomials, rational and series evaluation, norms, condition numbers and friends), quadrature, the modern interpolators, statistics, optimization, differentiation (autodiff, finite differences and Lanczos smoothing), the complex inverse trigonometric functions, and the quaternion and octonion types.

import boost.math;

int main()
{
return boost::math::cdf(boost::math::normal_distribution<>(), 0.0) == 0.5 ? 0 : 1;
}

Module support is completely inert unless the module is built and consumed explicitly: nothing changes for existing header users.

[h4 How to build]

The module is consumable from C++20 onward.
The interface unit lives in `libs/math/module/math.cppm` and builds with any toolchain that provides the standard library module (`import std`); the standard library maintainers agreed to make `import std` available in C++20 mode as well as C++23, so a C++23 compilation mode is not required.
CI exercises two configurations, both with CMake 4.4, Ninja and the matching `CMAKE_EXPERIMENTAL_CXX_IMPORT_STD` UUID: clang 20 with libc++ runs the full module test suite, and GCC 15 with libstdc++ builds the module and runs the quick test (libstdc++ cannot yet mix the textual standard library includes used by the wider test sources with `import std` in the same translation unit).
From a Boost superproject checkout:

cmake -G Ninja -DBOOST_INCLUDE_LIBRARIES=math -DBUILD_TESTING=ON \
-DBOOST_MATH_BUILD_MODULE=ON \
-DCMAKE_CXX_COMPILER=clang++-20 \
-DCMAKE_CXX_FLAGS="-stdlib=libc++ -Wno-reserved-module-identifier" \
-DCMAKE_EXPERIMENTAL_CXX_IMPORT_STD=<uuid-for-your-cmake-version> \
-DCMAKE_CXX_STDLIB_MODULES_JSON=/usr/lib/llvm-20/lib/libc++.modules.json ..
cmake --build . --target tests
ctest

The module test suite reuses a curated subset of the regular test files, which switch from textual inclusion to `import boost.math;` when `BOOST_MATH_BUILD_MODULE` is defined.
The `cmake-module-test` job in the library's CI runs this configuration on every commit.

[h4 Limitations]

* The module is always built in standalone mode, so it has no dependencies on other Boost libraries.
* Macros do not cross module boundaries.
The policy configuration macros (`BOOST_MATH_DOMAIN_ERROR_POLICY` and friends) and the convenience macros `BOOST_MATH_DECLARE_DISTRIBUTIONS` and `BOOST_MATH_DECLARE_SPECIAL_FUNCTIONS` therefore have no effect on an importing translation unit.
Configure policies at the call site with `boost::math::policies::make_policy` or a `policy<...>` type instead; those interfaces are fully available through the import.
* The `user_error` policy is not supported through the module, because a user supplied `boost::math::policies::user_..._error` definition cannot attach to the module.
* A program should consume Boost.Math either through the module or through textual includes, not both.
The only headers that are safe to include textually alongside the import are `boost/math/tools/config.hpp` and `boost/math/tools/assert.hpp`, which the test support headers rely on.
* Excluded from the module: the TR1/C99 interfaces and `common_factor` headers, `boost/math/bindings`, `boost/math/concepts`, `boost/math/cstdfloat`, all deprecated headers, and the headers that require external non-Boost dependencies (`chebyshev_transform.hpp` and `interpolators/cardinal_trigonometric.hpp` need FFTW, `optimization/cma_es.hpp` needs Eigen).
These remain available as ordinary includes.
* `__float128` support (`BOOST_MATH_USE_FLOAT128`) is not enabled in the module build.
* On libc++ the parallel execution policy overloads in statistics compile out (no `<execution>` support), matching the ordinary header behavior on that standard library.

Comment thread
mborland marked this conversation as resolved.
[endsect] [/section:cxx20_modules Support for C++20 Modules]

[/
Copyright 2026 Matt Borland.
Distributed under 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).
]
4 changes: 2 additions & 2 deletions include/boost/math/ccmath/abs.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ constexpr T abs_impl(T x) noexcept

} // Namespace detail

template <typename T, std::enable_if_t<!std::is_unsigned_v<T>, bool> = true>
BOOST_MATH_EXPORT template <typename T, std::enable_if_t<!std::is_unsigned_v<T>, bool> = true>
constexpr T abs(T x) noexcept
{
if(BOOST_MATH_IS_CONSTANT_EVALUATED(x))
Expand All @@ -60,7 +60,7 @@ constexpr T abs(T x) noexcept

// If abs() is called with an argument of type X for which is_unsigned_v<X> is true and if X
// cannot be converted to int by integral promotion (7.3.7), the program is ill-formed.
template <typename T, std::enable_if_t<std::is_unsigned_v<T>, bool> = true>
BOOST_MATH_EXPORT template <typename T, std::enable_if_t<std::is_unsigned_v<T>, bool> = true>
constexpr T abs(T x) noexcept
{
if constexpr (std::is_convertible_v<T, int>)
Expand Down
4 changes: 2 additions & 2 deletions include/boost/math/ccmath/ceil.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ inline constexpr T ceil_impl(T arg) noexcept

} // Namespace detail

template <typename Real, std::enable_if_t<!std::is_integral_v<Real>, bool> = true>
BOOST_MATH_EXPORT template <typename Real, std::enable_if_t<!std::is_integral_v<Real>, bool> = true>
inline constexpr Real ceil(Real arg) noexcept
{
if(BOOST_MATH_IS_CONSTANT_EVALUATED(arg))
Expand All @@ -55,7 +55,7 @@ inline constexpr Real ceil(Real arg) noexcept
}
}

template <typename Z, std::enable_if_t<std::is_integral_v<Z>, bool> = true>
BOOST_MATH_EXPORT template <typename Z, std::enable_if_t<std::is_integral_v<Z>, bool> = true>
inline constexpr double ceil(Z arg) noexcept
{
return boost::math::ccmath::ceil(static_cast<double>(arg));
Expand Down
6 changes: 4 additions & 2 deletions include/boost/math/ccmath/copysign.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
#ifndef BOOST_MATH_CCMATH_COPYSIGN_HPP
#define BOOST_MATH_CCMATH_COPYSIGN_HPP

#ifndef BOOST_MATH_BUILD_MODULE
#include <cmath>
#include <cstdint>
#include <limits>
#include <type_traits>
#endif
#include <boost/math/tools/is_constant_evaluated.hpp>
#include <boost/math/tools/promotion.hpp>
#include <boost/math/tools/config.hpp>
Expand All @@ -35,7 +37,7 @@ constexpr T copysign_impl(const T mag, const T sgn) noexcept

} // Namespace detail

template <typename Real, std::enable_if_t<!std::is_integral_v<Real>, bool> = true>
BOOST_MATH_EXPORT template <typename Real, std::enable_if_t<!std::is_integral_v<Real>, bool> = true>
constexpr Real copysign(Real mag, Real sgn) noexcept
{
if(BOOST_MATH_IS_CONSTANT_EVALUATED(mag))
Expand All @@ -49,7 +51,7 @@ constexpr Real copysign(Real mag, Real sgn) noexcept
}
}

template <typename T1, typename T2>
BOOST_MATH_EXPORT template <typename T1, typename T2>
constexpr auto copysign(T1 mag, T2 sgn) noexcept
{
if (BOOST_MATH_IS_CONSTANT_EVALUATED(mag))
Expand Down
2 changes: 2 additions & 0 deletions include/boost/math/ccmath/detail/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
#ifndef BOOST_MATH_CCMATH_DETAIL_CONFIG
#define BOOST_MATH_CCMATH_DETAIL_CONFIG

#ifndef BOOST_MATH_BUILD_MODULE
#include <cmath>
#include <type_traits>
#include <limits>
#endif
#include <boost/math/tools/is_constant_evaluated.hpp>
#include <boost/math/tools/is_standalone.hpp>

Expand Down
Loading
Loading