diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cb3d579..a2faaf3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,6 +27,10 @@ jobs: compiler: clang++-14 cxxstd: "03,11,14,17,2a" os: ubuntu-22.04 + - toolset: clang-19 + cxxstd: "20,23" + os: ubuntu-24.04 + install: clang-19 llvm-19 libclang-rt-19-dev libc++-19-dev libc++abi-19-dev clang-tools-19 # - toolset: clang # cxxstd: "03,11,14,17,2a" # os: macos-10.15 @@ -67,6 +71,31 @@ jobs: ./b2 -d0 headers ./b2 -j4 variant=debug tools/inspect/build + - name: Run modules tests wihtout 'import std;' + if: ${{matrix.toolset == 'clang-19'}} + run: | + cd ../boost-root/libs/any + mkdir build_module + cd build_module + cmake -DBOOST_USE_MODULES=1 -DBUILD_TESTING=1 -GNinja -DCMAKE_CXX_COMPILER=clang++-19 ../test/cmake_subdir_test/ + cmake --build . + ctest -V + cd .. + rm -rf build_module + + - name: Run modules tests + if: false + # if: ${{matrix.toolset == 'clang-19'}} + run: | + cd ../boost-root/libs/any + mkdir build_module + cd build_module + 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/ + cmake --build . + ctest -V + cd .. + rm -rf build_module + - name: Run tests run: | cd ../boost-root @@ -114,6 +143,10 @@ jobs: cxxstd: "03,11,14,17,2a" addrmd: 64 os: windows-2019 + - toolset: msvc-14.3 + cxxstd: "14,17,20,latest" + addrmd: 32,64 + os: windows-2022 runs-on: ${{matrix.os}} @@ -142,6 +175,36 @@ jobs: cmd /c bootstrap b2 -d0 headers + - name: Run modules tests + if: ${{matrix.toolset == 'msvc-14.3'}} + shell: cmd + run: | + choco install --no-progress ninja + call "C:/Program Files/Microsoft Visual Studio/2022/Enterprise/VC/Auxiliary/Build/vcvarsall.bat" x64 + cd ../boost-root/libs/any + mkdir build_module + cd build_module + 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/ + cmake --build . + ctest --no-tests=error -V + cd .. + rm -rf build_module + + - name: Run modules tests wihtout 'import std;' + if: ${{matrix.toolset == 'msvc-14.3'}} + shell: cmd + run: | + choco install --no-progress ninja + call "C:/Program Files/Microsoft Visual Studio/2022/Enterprise/VC/Auxiliary/Build/vcvarsall.bat" x64 + cd ../boost-root/libs/any + mkdir build_module + cd build_module + cmake -DBOOST_USE_MODULES=1 -DBUILD_TESTING=1 -DCMAKE_CXX_STANDARD=20 -G Ninja ../test/cmake_subdir_test/ + cmake --build . + ctest --no-tests=error -V + cd .. + rm -rf build_module + - name: Run tests shell: cmd run: | diff --git a/CMakeLists.txt b/CMakeLists.txt index 792cece..2b56842 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,17 +2,43 @@ # Distributed under the Boost Software License, Version 1.0. # See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt -cmake_minimum_required( VERSION 3.5...3.20 ) +cmake_minimum_required( VERSION 3.5...3.31 ) project( boost_any VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX ) -add_library( boost_any INTERFACE ) -add_library( Boost::any ALIAS boost_any ) +if (BOOST_USE_MODULES) + add_library(boost_any) + target_sources(boost_any PUBLIC + FILE_SET modules_public TYPE CXX_MODULES FILES + ${CMAKE_CURRENT_LIST_DIR}/modules/boost_any.cppm + ) -target_include_directories( boost_any INTERFACE include ) + target_compile_features(boost_any PUBLIC cxx_std_20) + target_compile_definitions(boost_any PUBLIC BOOST_USE_MODULES) + if (CMAKE_CXX_COMPILER_IMPORT_STD) + target_compile_definitions(boost_any PRIVATE BOOST_ANY_USE_STD_MODULE) + message(STATUS "Using `import std;`") + else() + message(STATUS "`import std;` is not awailable") + endif() + set(__scope PUBLIC) +else() + add_library(boost_any INTERFACE) + set(__scope INTERFACE) +endif() +target_include_directories(boost_any ${__scope} include) target_link_libraries( boost_any - INTERFACE + ${__scope} Boost::config Boost::throw_exception Boost::type_index ) + +add_library( Boost::any ALIAS boost_any ) + +enable_testing() +if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt") + + add_subdirectory(test) + +endif() diff --git a/doc/any.qbk b/doc/any.qbk index 6e560e4..d081c08 100644 --- a/doc/any.qbk +++ b/doc/any.qbk @@ -237,6 +237,40 @@ The specific requirements on value types to be used in an [endsect] +[section C++20 module] + +[caution C++20 module support is on early stage, targets, flags and behavior may change in the future] + +If using modern CMake define CMake option `-DBOOST_USE_MODULES=1` to build a C++20 module and +make the `Boost::any` CMake target provide it. After that an explicit usage of C++20 module `boost.any` is allowed: + +[import ../modules/usage_sample.cpp] +[any_module_example] + +The `Boost::any` CMake target gives an ability to mix includes and imports of the library in different translation units. Moreover, +if `BOOST_USE_MODULES` macro is defined then all the `boost/any...` includes implicilty do `import boost.any;` to give all the +benifits of modules without changing the existing code. + +[note For better compile times make sure that `import std;` is available when building the `boost.any` module (in CMake logs there should be + a 'Using `import std;`' message). ] + +If not using CMake, then the module could be build manually from the `modules/boost_any.cppm` file. + +For manual module build the following commands could be used for clang compiler: + +``` +cd any/modules +clang++ -I ../include -std=c++20 --precompile -x c++-module boost_any.cppm +``` + +After that, the module could be used in the following way: + +``` +clang++ -std=c++20 -fmodule-file=boost_any.pcm boost_any.pcm usage_sample.cpp +``` + +[endsect] + [xinclude autodoc_any.xml] [section Acknowledgements] diff --git a/include/boost/any.hpp b/include/boost/any.hpp index a8e4d8e..331eb2f 100644 --- a/include/boost/any.hpp +++ b/include/boost/any.hpp @@ -3,13 +3,26 @@ #ifndef BOOST_ANY_INCLUDED #define BOOST_ANY_INCLUDED +#include + +#if !defined(BOOST_USE_MODULES) || defined(BOOST_ANY_INTERFACE_UNIT) + +/// \file boost/any.hpp +/// \brief \copybrief boost::any + +#ifndef BOOST_ANY_INTERFACE_UNIT #include #ifdef BOOST_HAS_PRAGMA_ONCE # pragma once #endif -/// \file boost/any.hpp -/// \brief \copybrief boost::any +#include // for std::addressof +#include + +#include +#include + +#endif // #ifndef BOOST_ANY_INTERFACE_UNIT // what: variant type boost::any // who: contributed by Kevlin Henney, @@ -21,14 +34,11 @@ #include #include #include -#include -#include -#include // for std::addressof -#include +namespace boost { + +BOOST_ANY_BEGIN_MODULE_EXPORT -namespace boost -{ /// \brief A class whose instances can hold instances of any /// type that satisfies \forcedlink{ValueType} requirements. class any @@ -355,6 +365,9 @@ namespace boost ); return boost::any_cast(operand); } + +BOOST_ANY_END_MODULE_EXPORT + } // Copyright Kevlin Henney, 2000, 2001, 2002. All rights reserved. @@ -364,4 +377,6 @@ namespace boost // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_ANY_INTERFACE_UNIT) + #endif diff --git a/include/boost/any/bad_any_cast.hpp b/include/boost/any/bad_any_cast.hpp index 647f2c5..e15ce16 100644 --- a/include/boost/any/bad_any_cast.hpp +++ b/include/boost/any/bad_any_cast.hpp @@ -9,6 +9,11 @@ #ifndef BOOST_ANYS_BAD_ANY_CAST_HPP_INCLUDED #define BOOST_ANYS_BAD_ANY_CAST_HPP_INCLUDED +#include + +#if !defined(BOOST_USE_MODULES) || defined(BOOST_ANY_INTERFACE_UNIT) + +#ifndef BOOST_ANY_INTERFACE_UNIT #include #ifdef BOOST_HAS_PRAGMA_ONCE # pragma once @@ -19,9 +24,12 @@ #endif #include +#endif // #ifndef BOOST_ANY_INTERFACE_UNIT namespace boost { +BOOST_ANY_BEGIN_MODULE_EXPORT + /// The exception thrown in the event of a failed boost::any_cast of /// an boost::any, boost::anys::basic_any or boost::anys::unique_any value. class BOOST_SYMBOL_VISIBLE bad_any_cast : @@ -39,7 +47,10 @@ class BOOST_SYMBOL_VISIBLE bad_any_cast : } }; +BOOST_ANY_END_MODULE_EXPORT + } // namespace boost +#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_ANY_INTERFACE_UNIT) #endif // #ifndef BOOST_ANYS_BAD_ANY_CAST_HPP_INCLUDED diff --git a/include/boost/any/basic_any.hpp b/include/boost/any/basic_any.hpp index 7911849..127f293 100644 --- a/include/boost/any/basic_any.hpp +++ b/include/boost/any/basic_any.hpp @@ -10,28 +10,36 @@ #ifndef BOOST_ANYS_BASIC_ANY_HPP_INCLUDED #define BOOST_ANYS_BASIC_ANY_HPP_INCLUDED +#include + +#if !defined(BOOST_USE_MODULES) || defined(BOOST_ANY_INTERFACE_UNIT) + +/// \file boost/any/basic_any.hpp +/// \brief \copybrief boost::anys::basic_any + +#ifndef BOOST_ANY_INTERFACE_UNIT #include #ifdef BOOST_HAS_PRAGMA_ONCE # pragma once #endif -/// \file boost/any/basic_any.hpp -/// \brief \copybrief boost::anys::basic_any +#include // for std::addressof +#include -#include -#include #include #include #include +#endif // #ifndef BOOST_ANY_INTERFACE_UNIT -#include // for std::addressof -#include - +#include +#include namespace boost { namespace anys { +BOOST_ANY_BEGIN_MODULE_EXPORT + /// \brief A class with customizable Small Object Optimization whose /// instances can hold instances of any type that satisfies /// \forcedlink{ValueType} requirements. Use boost::any instead if not sure. @@ -546,11 +554,19 @@ namespace anys { } /// @endcond +BOOST_ANY_END_MODULE_EXPORT + } // namespace anys +BOOST_ANY_BEGIN_MODULE_EXPORT + using boost::anys::any_cast; using boost::anys::unsafe_any_cast; +BOOST_ANY_END_MODULE_EXPORT + } // namespace boost +#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_ANY_INTERFACE_UNIT) + #endif // #ifndef BOOST_ANYS_BASIC_ANY_HPP_INCLUDED diff --git a/include/boost/any/detail/config.hpp b/include/boost/any/detail/config.hpp new file mode 100644 index 0000000..1de5977 --- /dev/null +++ b/include/boost/any/detail/config.hpp @@ -0,0 +1,22 @@ +// Copyright Antony Polukhin, 2021-2025. +// +// 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) + +#ifndef BOOST_ANY_ANYS_DETAIL_CONFIG_HPP +#define BOOST_ANY_ANYS_DETAIL_CONFIG_HPP + +#ifdef BOOST_ANY_INTERFACE_UNIT +# define BOOST_ANY_BEGIN_MODULE_EXPORT export { +# define BOOST_ANY_END_MODULE_EXPORT } +#else +# define BOOST_ANY_BEGIN_MODULE_EXPORT +# define BOOST_ANY_END_MODULE_EXPORT +#endif + +#if defined(BOOST_USE_MODULES) && !defined(BOOST_ANY_INTERFACE_UNIT) +import boost.any; +#endif + +#endif // #ifndef BOOST_ANY_ANYS_DETAIL_CONFIG_HPP diff --git a/include/boost/any/detail/placeholder.hpp b/include/boost/any/detail/placeholder.hpp index 8035dc9..4e8036a 100644 --- a/include/boost/any/detail/placeholder.hpp +++ b/include/boost/any/detail/placeholder.hpp @@ -7,12 +7,18 @@ #ifndef BOOST_ANY_ANYS_DETAIL_PLACEHOLDER_HPP #define BOOST_ANY_ANYS_DETAIL_PLACEHOLDER_HPP +#include + +#if !defined(BOOST_USE_MODULES) || defined(BOOST_ANY_INTERFACE_UNIT) + +#ifndef BOOST_ANY_INTERFACE_UNIT #include #ifdef BOOST_HAS_PRAGMA_ONCE # pragma once #endif #include +#endif /// @cond namespace boost { @@ -30,4 +36,6 @@ class BOOST_SYMBOL_VISIBLE placeholder { } // namespace boost /// @endcond +#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_ANY_INTERFACE_UNIT) + #endif // #ifndef BOOST_ANY_ANYS_DETAIL_PLACEHOLDER_HPP diff --git a/include/boost/any/fwd.hpp b/include/boost/any/fwd.hpp index 047d955..0263a61 100644 --- a/include/boost/any/fwd.hpp +++ b/include/boost/any/fwd.hpp @@ -8,10 +8,16 @@ #ifndef BOOST_ANY_ANYS_FWD_HPP #define BOOST_ANY_ANYS_FWD_HPP +#include + +#if !defined(BOOST_USE_MODULES) || defined(BOOST_ANY_INTERFACE_UNIT) + +#ifndef BOOST_ANY_INTERFACE_UNIT #include #ifdef BOOST_HAS_PRAGMA_ONCE # pragma once #endif +#endif // #ifndef BOOST_ANY_INTERFACE_UNIT /// \file boost/any/fwd.hpp /// \brief Forward declarations of Boost.Any library types. @@ -19,15 +25,23 @@ /// @cond namespace boost { +BOOST_ANY_BEGIN_MODULE_EXPORT + class any; +BOOST_ANY_END_MODULE_EXPORT + namespace anys { +BOOST_ANY_BEGIN_MODULE_EXPORT + class unique_any; template class basic_any; +BOOST_ANY_END_MODULE_EXPORT + namespace detail { template @@ -52,4 +66,6 @@ namespace detail { } // namespace boost /// @endcond +#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_ANY_INTERFACE_UNIT) + #endif // #ifndef BOOST_ANY_ANYS_FWD_HPP diff --git a/include/boost/any/unique_any.hpp b/include/boost/any/unique_any.hpp index 8183113..6af8406 100644 --- a/include/boost/any/unique_any.hpp +++ b/include/boost/any/unique_any.hpp @@ -9,27 +9,35 @@ #ifndef BOOST_ANYS_UNIQUE_ANY_HPP_INCLUDED #define BOOST_ANYS_UNIQUE_ANY_HPP_INCLUDED +#include + +#if !defined(BOOST_USE_MODULES) || defined(BOOST_ANY_INTERFACE_UNIT) + +/// \file boost/any/unique_any.hpp +/// \brief \copybrief boost::anys::unique_any + +#ifndef BOOST_ANY_INTERFACE_UNIT #include #ifdef BOOST_HAS_PRAGMA_ONCE # pragma once #endif -/// \file boost/any/unique_any.hpp -/// \brief \copybrief boost::anys::unique_any - #include // for std::unique_ptr #include #include +#include +#include +#endif // #ifndef BOOST_ANY_INTERFACE_UNIT + #include #include #include -#include -#include - namespace boost { namespace anys { +BOOST_ANY_BEGIN_MODULE_EXPORT + /// Helper type for providing emplacement type to the constructor. template struct in_place_type_t @@ -342,12 +350,19 @@ inline T any_cast(unique_any&& operand) return std::move(anys::any_cast(operand)); } +BOOST_ANY_END_MODULE_EXPORT + } // namespace anys +BOOST_ANY_BEGIN_MODULE_EXPORT + using boost::anys::any_cast; using boost::anys::unsafe_any_cast; +BOOST_ANY_END_MODULE_EXPORT + } // namespace boost +#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_ANY_INTERFACE_UNIT) #endif // BOOST_ANYS_UNIQUE_ANY_HPP_INCLUDED diff --git a/modules/boost_any.cppm b/modules/boost_any.cppm new file mode 100644 index 0000000..9e8256b --- /dev/null +++ b/modules/boost_any.cppm @@ -0,0 +1,37 @@ +// Copyright (c) 2016-2025 Antony Polukhin +// +// 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) + +// To compile manually use a command like the folowing: +// clang++ -I ../include -std=c++20 --precompile -x c++-module any.cppm + +module; + +#include +#include +#include +#include + +#ifdef BOOST_ANY_USE_STD_MODULE +import std; +#else +#include +#include +#include +#include +#include +#endif + +#define BOOST_ANY_INTERFACE_UNIT + +export module boost.any; + +#ifdef __clang__ +# pragma clang diagnostic ignored "-Winclude-angled-in-module-purview" +#endif + +#include +#include +#include + diff --git a/modules/usage_sample.cpp b/modules/usage_sample.cpp new file mode 100644 index 0000000..95f4fea --- /dev/null +++ b/modules/usage_sample.cpp @@ -0,0 +1,17 @@ +// Copyright (c) 2016-2025 Antony Polukhin +// +// 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) + +// To compile manually use a command like the folowing: +// clang++ -std=c++20 -fmodule-file=type_index.pcm type_index.pcm usage_sample.cpp + +//[any_module_example +import boost.any; + +int main() { + boost::any a = 42; +} +//] + + diff --git a/test/basic_any_test.cpp b/test/basic_any_test.cpp index 271dd07..587ad6b 100644 --- a/test/basic_any_test.cpp +++ b/test/basic_any_test.cpp @@ -6,7 +6,7 @@ // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#include "boost/any/basic_any.hpp" +#include #include "basic_test.hpp" int main() { diff --git a/test/basic_test.hpp b/test/basic_test.hpp index e3dbf62..73f515a 100644 --- a/test/basic_test.hpp +++ b/test/basic_test.hpp @@ -1,5 +1,5 @@ // Copyright Kevlin Henney, 2000, 2001. All rights reserved. -// Copyright Antony Polukhin, 2013-2019. +// Copyright Antony Polukhin, 2013-2025. // Copyright Ruslan Arutyunyan, 2019-2021. // // Distributed under the Boost Software License, Version 1.0. (See @@ -20,6 +20,8 @@ #include #include +#include + #include namespace any_tests { diff --git a/test/cmake_subdir_test/CMakeLists.txt b/test/cmake_subdir_test/CMakeLists.txt new file mode 100644 index 0000000..a934b81 --- /dev/null +++ b/test/cmake_subdir_test/CMakeLists.txt @@ -0,0 +1,56 @@ +# Copyright (c) 2016-2025 Antony Polukhin +# 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 + +cmake_minimum_required(VERSION 3.5...4.0) + +project(any_subdir_test LANGUAGES CXX) + +add_subdirectory(../../../assert boostorg/assert) +add_subdirectory(../../../core boostorg/core) +add_subdirectory(../../../config boostorg/config) +add_subdirectory(../../../container_hash boostorg/container_hash) +add_subdirectory(../../../describe boostorg/describe) +add_subdirectory(../../../detail boostorg/detail) +add_subdirectory(../../../integer boostorg/integer) +add_subdirectory(../../../mp11 boostorg/mp11) +add_subdirectory(../../../preprocessor boostorg/preprocessor) +add_subdirectory(../../../static_assert boostorg/static_assert) +add_subdirectory(../../../throw_exception boostorg/throw_exception) +add_subdirectory(../../../type_index boostorg/type_index) +add_subdirectory(../../../type_traits boostorg/type_traits) + +add_subdirectory(../../ boostorg/any) + +enable_testing() + +if (BOOST_USE_MODULES) + add_executable(boost_any_module_usage ../modules/usage_sample.cpp) + target_link_libraries(boost_any_module_usage PRIVATE Boost::any) + add_test(NAME boost_any_module_usage COMMAND boost_any_module_usage) +endif() + +list(APPEND RUN_TESTS_SOURCES + any_test_mplif.cpp + basic_any_test_small_object.cpp + any_test_rv.cpp + basic_any_test.cpp + + unique_any/from_any.cpp + unique_any/move.cpp + unique_any/emplace.cpp + unique_any/base.cpp + + basic_any_test_mplif.cpp + basic_any_test_rv.cpp + basic_any_test_large_object.cpp + # any_test.cpp # Ambiguous with modules, because all the anys now available +) + +foreach (testsourcefile ${RUN_TESTS_SOURCES}) + get_filename_component(testname ${testsourcefile} NAME_WLE) + add_executable(${PROJECT_NAME}_${testname} ../${testsourcefile}) + target_link_libraries(${PROJECT_NAME}_${testname} Boost::any) + add_test(NAME ${PROJECT_NAME}_${testname} COMMAND ${PROJECT_NAME}_${testname}) +endforeach() + diff --git a/test/unique_any/move.cpp b/test/unique_any/move.cpp index a0c0c08..8803911 100644 --- a/test/unique_any/move.cpp +++ b/test/unique_any/move.cpp @@ -6,6 +6,8 @@ #include +#include + #include void test_move_construct_unique_ptr() {