Skip to content

Commit 306d8a1

Browse files
authored
Implement initial version of C++20 module boost.any (#30)
`#include <boost/any...` is now implicitly does `import boost.any` if the modules are supported All the library internals now have unconditional module level linkage. Significant differences from https://anarthal.github.io/cppblog/modules3: * `BOOST_ANY_USE_STD_MODULE` macro switch for `import std;` / `includes` while building module. This allows to use module in C++20 and even without usable `std` module.
1 parent 8292e18 commit 306d8a1

File tree

16 files changed

+369
-29
lines changed

16 files changed

+369
-29
lines changed

.github/workflows/ci.yml

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ jobs:
2727
compiler: clang++-14
2828
cxxstd: "03,11,14,17,2a"
2929
os: ubuntu-22.04
30+
- toolset: clang-19
31+
cxxstd: "20,23"
32+
os: ubuntu-24.04
33+
install: clang-19 llvm-19 libclang-rt-19-dev libc++-19-dev libc++abi-19-dev clang-tools-19
3034
# - toolset: clang
3135
# cxxstd: "03,11,14,17,2a"
3236
# os: macos-10.15
@@ -65,7 +69,32 @@ jobs:
6569
python tools/boostdep/depinst/depinst.py --include benchmark --include example --include examples --include tools --git_args "--depth 10 --jobs 3" $LIBRARY
6670
./bootstrap.sh
6771
./b2 -d0 headers
68-
./b2 -j4 variant=debug tools/inspect/build
72+
./b2 -j4 variant=debug tools/inspect
73+
74+
- name: Run modules tests wihtout 'import std;'
75+
if: ${{matrix.toolset == 'clang-19'}}
76+
run: |
77+
cd ../boost-root/libs/any
78+
mkdir build_module
79+
cd build_module
80+
cmake -DBOOST_USE_MODULES=1 -DBUILD_TESTING=1 -GNinja -DCMAKE_CXX_COMPILER=clang++-19 ../test/cmake_subdir_test/
81+
cmake --build .
82+
ctest -V
83+
cd ..
84+
rm -rf build_module
85+
86+
- name: Run modules tests
87+
if: false
88+
# if: ${{matrix.toolset == 'clang-19'}}
89+
run: |
90+
cd ../boost-root/libs/any
91+
mkdir build_module
92+
cd build_module
93+
cmake -DBUILD_TESTING=1 -DBOOST_USE_MODULES=1 -DCMAKE_CXX_COMPILER=clang++-19 -DCMAKE_CXX_FLAGS=-stdlib=libc++ -DCMAKE_EXE_LINKER_FLAGS=-stdlib=libc++ -DCMAKE_CXX_STANDARD=23 -DCMAKE_EXPERIMENTAL_CXX_IMPORT_STD=0e5b6991-d74f-4b3d-a41c-cf096e0b2508 -G Ninja ../test/cmake_subdir_test/
94+
cmake --build .
95+
ctest -V
96+
cd ..
97+
rm -rf build_module
6998
7099
- name: Run tests
71100
run: |
@@ -114,6 +143,10 @@ jobs:
114143
cxxstd: "03,11,14,17,2a"
115144
addrmd: 64
116145
os: windows-2019
146+
- toolset: msvc-14.3
147+
cxxstd: "14,17,20,latest"
148+
addrmd: 32,64
149+
os: windows-2022
117150

118151
runs-on: ${{matrix.os}}
119152

@@ -142,6 +175,36 @@ jobs:
142175
cmd /c bootstrap
143176
b2 -d0 headers
144177
178+
- name: Run modules tests
179+
if: ${{matrix.toolset == 'msvc-14.3'}}
180+
shell: cmd
181+
run: |
182+
choco install --no-progress ninja
183+
call "C:/Program Files/Microsoft Visual Studio/2022/Enterprise/VC/Auxiliary/Build/vcvarsall.bat" x64
184+
cd ../boost-root/libs/any
185+
mkdir build_module
186+
cd build_module
187+
cmake -DBOOST_USE_MODULES=1 -DBUILD_TESTING=1 -DCMAKE_CXX_STANDARD=23 -DCMAKE_EXPERIMENTAL_CXX_IMPORT_STD=0e5b6991-d74f-4b3d-a41c-cf096e0b2508 -G Ninja ../test/cmake_subdir_test/
188+
cmake --build .
189+
ctest --no-tests=error -V
190+
cd ..
191+
rm -rf build_module
192+
193+
- name: Run modules tests wihtout 'import std;'
194+
if: ${{matrix.toolset == 'msvc-14.3'}}
195+
shell: cmd
196+
run: |
197+
choco install --no-progress ninja
198+
call "C:/Program Files/Microsoft Visual Studio/2022/Enterprise/VC/Auxiliary/Build/vcvarsall.bat" x64
199+
cd ../boost-root/libs/any
200+
mkdir build_module
201+
cd build_module
202+
cmake -DBOOST_USE_MODULES=1 -DBUILD_TESTING=1 -DCMAKE_CXX_STANDARD=20 -G Ninja ../test/cmake_subdir_test/
203+
cmake --build .
204+
ctest --no-tests=error -V
205+
cd ..
206+
rm -rf build_module
207+
145208
- name: Run tests
146209
shell: cmd
147210
run: |

CMakeLists.txt

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,43 @@
22
# Distributed under the Boost Software License, Version 1.0.
33
# See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt
44

5-
cmake_minimum_required( VERSION 3.5...3.20 )
5+
cmake_minimum_required( VERSION 3.5...3.31 )
66
project( boost_any VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX )
77

8-
add_library( boost_any INTERFACE )
9-
add_library( Boost::any ALIAS boost_any )
8+
if (BOOST_USE_MODULES)
9+
add_library(boost_any)
10+
target_sources(boost_any PUBLIC
11+
FILE_SET modules_public TYPE CXX_MODULES FILES
12+
${CMAKE_CURRENT_LIST_DIR}/modules/boost_any.cppm
13+
)
1014

11-
target_include_directories( boost_any INTERFACE include )
15+
target_compile_features(boost_any PUBLIC cxx_std_20)
16+
target_compile_definitions(boost_any PUBLIC BOOST_USE_MODULES)
17+
if (CMAKE_CXX_COMPILER_IMPORT_STD)
18+
target_compile_definitions(boost_any PRIVATE BOOST_ANY_USE_STD_MODULE)
19+
message(STATUS "Using `import std;`")
20+
else()
21+
message(STATUS "`import std;` is not awailable")
22+
endif()
23+
set(__scope PUBLIC)
24+
else()
25+
add_library(boost_any INTERFACE)
26+
set(__scope INTERFACE)
27+
endif()
1228

29+
target_include_directories(boost_any ${__scope} include)
1330
target_link_libraries( boost_any
14-
INTERFACE
31+
${__scope}
1532
Boost::config
1633
Boost::throw_exception
1734
Boost::type_index
1835
)
36+
37+
add_library( Boost::any ALIAS boost_any )
38+
39+
enable_testing()
40+
if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
41+
42+
add_subdirectory(test)
43+
44+
endif()

doc/any.qbk

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,40 @@ The specific requirements on value types to be used in an
237237

238238
[endsect]
239239

240+
[section C++20 module]
241+
242+
[caution C++20 module support is on early stage, targets, flags and behavior may change in the future]
243+
244+
If using modern CMake define CMake option `-DBOOST_USE_MODULES=1` to build a C++20 module and
245+
make the `Boost::any` CMake target provide it. After that an explicit usage of C++20 module `boost.any` is allowed:
246+
247+
[import ../modules/usage_sample.cpp]
248+
[any_module_example]
249+
250+
The `Boost::any` CMake target gives an ability to mix includes and imports of the library in different translation units. Moreover,
251+
if `BOOST_USE_MODULES` macro is defined then all the `boost/any...` includes implicilty do `import boost.any;` to give all the
252+
benifits of modules without changing the existing code.
253+
254+
[note For better compile times make sure that `import std;` is available when building the `boost.any` module (in CMake logs there should be
255+
a 'Using `import std;`' message). ]
256+
257+
If not using CMake, then the module could be build manually from the `modules/boost_any.cppm` file.
258+
259+
For manual module build the following commands could be used for clang compiler:
260+
261+
```
262+
cd any/modules
263+
clang++ -I ../include -std=c++20 --precompile -x c++-module boost_any.cppm
264+
```
265+
266+
After that, the module could be used in the following way:
267+
268+
```
269+
clang++ -std=c++20 -fmodule-file=boost_any.pcm boost_any.pcm usage_sample.cpp
270+
```
271+
272+
[endsect]
273+
240274
[xinclude autodoc_any.xml]
241275

242276
[section Acknowledgements]

include/boost/any.hpp

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,26 @@
33
#ifndef BOOST_ANY_INCLUDED
44
#define BOOST_ANY_INCLUDED
55

6+
#include <boost/any/detail/config.hpp>
7+
8+
#if !defined(BOOST_USE_MODULES) || defined(BOOST_ANY_INTERFACE_UNIT)
9+
10+
/// \file boost/any.hpp
11+
/// \brief \copybrief boost::any
12+
13+
#ifndef BOOST_ANY_INTERFACE_UNIT
614
#include <boost/config.hpp>
715
#ifdef BOOST_HAS_PRAGMA_ONCE
816
# pragma once
917
#endif
1018

11-
/// \file boost/any.hpp
12-
/// \brief \copybrief boost::any
19+
#include <memory> // for std::addressof
20+
#include <type_traits>
21+
22+
#include <boost/throw_exception.hpp>
23+
#include <boost/type_index.hpp>
24+
25+
#endif // #ifndef BOOST_ANY_INTERFACE_UNIT
1326

1427
// what: variant type boost::any
1528
// who: contributed by Kevlin Henney,
@@ -21,14 +34,11 @@
2134
#include <boost/any/bad_any_cast.hpp>
2235
#include <boost/any/fwd.hpp>
2336
#include <boost/any/detail/placeholder.hpp>
24-
#include <boost/throw_exception.hpp>
25-
#include <boost/type_index.hpp>
2637

27-
#include <memory> // for std::addressof
28-
#include <type_traits>
38+
namespace boost {
39+
40+
BOOST_ANY_BEGIN_MODULE_EXPORT
2941

30-
namespace boost
31-
{
3242
/// \brief A class whose instances can hold instances of any
3343
/// type that satisfies \forcedlink{ValueType} requirements.
3444
class any
@@ -355,6 +365,9 @@ namespace boost
355365
);
356366
return boost::any_cast<ValueType>(operand);
357367
}
368+
369+
BOOST_ANY_END_MODULE_EXPORT
370+
358371
}
359372

360373
// Copyright Kevlin Henney, 2000, 2001, 2002. All rights reserved.
@@ -364,4 +377,6 @@ namespace boost
364377
// accompanying file LICENSE_1_0.txt or copy at
365378
// http://www.boost.org/LICENSE_1_0.txt)
366379

380+
#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_ANY_INTERFACE_UNIT)
381+
367382
#endif

include/boost/any/bad_any_cast.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99
#ifndef BOOST_ANYS_BAD_ANY_CAST_HPP_INCLUDED
1010
#define BOOST_ANYS_BAD_ANY_CAST_HPP_INCLUDED
1111

12+
#include <boost/any/detail/config.hpp>
13+
14+
#if !defined(BOOST_USE_MODULES) || defined(BOOST_ANY_INTERFACE_UNIT)
15+
16+
#ifndef BOOST_ANY_INTERFACE_UNIT
1217
#include <boost/config.hpp>
1318
#ifdef BOOST_HAS_PRAGMA_ONCE
1419
# pragma once
@@ -19,9 +24,12 @@
1924
#endif
2025

2126
#include <stdexcept>
27+
#endif // #ifndef BOOST_ANY_INTERFACE_UNIT
2228

2329
namespace boost {
2430

31+
BOOST_ANY_BEGIN_MODULE_EXPORT
32+
2533
/// The exception thrown in the event of a failed boost::any_cast of
2634
/// an boost::any, boost::anys::basic_any or boost::anys::unique_any value.
2735
class BOOST_SYMBOL_VISIBLE bad_any_cast :
@@ -39,7 +47,10 @@ class BOOST_SYMBOL_VISIBLE bad_any_cast :
3947
}
4048
};
4149

50+
BOOST_ANY_END_MODULE_EXPORT
51+
4252
} // namespace boost
4353

54+
#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_ANY_INTERFACE_UNIT)
4455

4556
#endif // #ifndef BOOST_ANYS_BAD_ANY_CAST_HPP_INCLUDED

include/boost/any/basic_any.hpp

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,28 +10,36 @@
1010
#ifndef BOOST_ANYS_BASIC_ANY_HPP_INCLUDED
1111
#define BOOST_ANYS_BASIC_ANY_HPP_INCLUDED
1212

13+
#include <boost/any/detail/config.hpp>
14+
15+
#if !defined(BOOST_USE_MODULES) || defined(BOOST_ANY_INTERFACE_UNIT)
16+
17+
/// \file boost/any/basic_any.hpp
18+
/// \brief \copybrief boost::anys::basic_any
19+
20+
#ifndef BOOST_ANY_INTERFACE_UNIT
1321
#include <boost/config.hpp>
1422
#ifdef BOOST_HAS_PRAGMA_ONCE
1523
# pragma once
1624
#endif
1725

18-
/// \file boost/any/basic_any.hpp
19-
/// \brief \copybrief boost::anys::basic_any
26+
#include <memory> // for std::addressof
27+
#include <type_traits>
2028

21-
#include <boost/any/bad_any_cast.hpp>
22-
#include <boost/any/fwd.hpp>
2329
#include <boost/assert.hpp>
2430
#include <boost/type_index.hpp>
2531
#include <boost/throw_exception.hpp>
32+
#endif // #ifndef BOOST_ANY_INTERFACE_UNIT
2633

27-
#include <memory> // for std::addressof
28-
#include <type_traits>
29-
34+
#include <boost/any/bad_any_cast.hpp>
35+
#include <boost/any/fwd.hpp>
3036

3137
namespace boost {
3238

3339
namespace anys {
3440

41+
BOOST_ANY_BEGIN_MODULE_EXPORT
42+
3543
/// \brief A class with customizable Small Object Optimization whose
3644
/// instances can hold instances of any type that satisfies
3745
/// \forcedlink{ValueType} requirements. Use boost::any instead if not sure.
@@ -546,11 +554,19 @@ namespace anys {
546554
}
547555
/// @endcond
548556

557+
BOOST_ANY_END_MODULE_EXPORT
558+
549559
} // namespace anys
550560

561+
BOOST_ANY_BEGIN_MODULE_EXPORT
562+
551563
using boost::anys::any_cast;
552564
using boost::anys::unsafe_any_cast;
553565

566+
BOOST_ANY_END_MODULE_EXPORT
567+
554568
} // namespace boost
555569

570+
#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_ANY_INTERFACE_UNIT)
571+
556572
#endif // #ifndef BOOST_ANYS_BASIC_ANY_HPP_INCLUDED

include/boost/any/detail/config.hpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright Antony Polukhin, 2021-2025.
2+
//
3+
// Distributed under the Boost Software License, Version 1.0. (See
4+
// accompanying file LICENSE_1_0.txt or copy at
5+
// http://www.boost.org/LICENSE_1_0.txt)
6+
7+
#ifndef BOOST_ANY_ANYS_DETAIL_CONFIG_HPP
8+
#define BOOST_ANY_ANYS_DETAIL_CONFIG_HPP
9+
10+
#ifdef BOOST_ANY_INTERFACE_UNIT
11+
# define BOOST_ANY_BEGIN_MODULE_EXPORT export {
12+
# define BOOST_ANY_END_MODULE_EXPORT }
13+
#else
14+
# define BOOST_ANY_BEGIN_MODULE_EXPORT
15+
# define BOOST_ANY_END_MODULE_EXPORT
16+
#endif
17+
18+
#if defined(BOOST_USE_MODULES) && !defined(BOOST_ANY_INTERFACE_UNIT)
19+
import boost.any;
20+
#endif
21+
22+
#endif // #ifndef BOOST_ANY_ANYS_DETAIL_CONFIG_HPP

include/boost/any/detail/placeholder.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,18 @@
77
#ifndef BOOST_ANY_ANYS_DETAIL_PLACEHOLDER_HPP
88
#define BOOST_ANY_ANYS_DETAIL_PLACEHOLDER_HPP
99

10+
#include <boost/any/detail/config.hpp>
11+
12+
#if !defined(BOOST_USE_MODULES) || defined(BOOST_ANY_INTERFACE_UNIT)
13+
14+
#ifndef BOOST_ANY_INTERFACE_UNIT
1015
#include <boost/config.hpp>
1116
#ifdef BOOST_HAS_PRAGMA_ONCE
1217
# pragma once
1318
#endif
1419

1520
#include <boost/type_index.hpp>
21+
#endif
1622

1723
/// @cond
1824
namespace boost {
@@ -30,4 +36,6 @@ class BOOST_SYMBOL_VISIBLE placeholder {
3036
} // namespace boost
3137
/// @endcond
3238

39+
#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_ANY_INTERFACE_UNIT)
40+
3341
#endif // #ifndef BOOST_ANY_ANYS_DETAIL_PLACEHOLDER_HPP

0 commit comments

Comments
 (0)