diff --git a/.github/workflows/cmake-multi-platform.yml b/.github/workflows/cmake-multi-platform.yml new file mode 100644 index 0000000..65e35bb --- /dev/null +++ b/.github/workflows/cmake-multi-platform.yml @@ -0,0 +1,154 @@ +# This starter workflow is for a CMake project running on multiple platforms. There is a different starter workflow if you just want a single platform. +# See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-single-platform.yml +name: Multiplatform Build + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + build: + runs-on: ${{ matrix.runner }} + strategy: + # Set fail-fast to false to ensure that feedback is delivered for all matrix combinations. Consider changing this to true when your workflow is stable. + fail-fast: false + + # Set up a matrix to run the following 3 configurations: + # 1. + # 2. + # 3. + # + # To add more build types (Release, Debug, RelWithDebInfo, etc.) customize the build_type list. + matrix: + runner: [ubuntu-26.04, windows-2025-vs2026] + build_type: [Release] + c_compiler: [gcc-15, clang-22, cl] + include: + - runner: windows-2025-vs2026 + os: Windows + c_compiler: cl + cpp_compiler: cl + - runner: ubuntu-26.04 + c_compiler: gcc-15 + cpp_compiler: g++-15 + - runner: ubuntu-26.04 + c_compiler: clang-22 + cpp_compiler: clang++-22 + exclude: + - runner: windows-2025-vs2026 + c_compiler: gcc-15 + - runner: windows-2025-vs2026 + c_compiler: clang-22 + - runner: ubuntu-26.04 + c_compiler: cl + + steps: + - uses: actions/checkout@v5 + + - name: Install libc++ for Clang + if: matrix.c_compiler == 'clang-22' + run: | + sudo apt-get update + sudo apt-get install -y clang-22 clang-tools-22 libc++-22-dev libc++abi-22-dev + + - uses: ilammy/msvc-dev-cmd@v1 + if: matrix.c_compiler == 'cl' + with: + arch: x64 + + - name: Set reusable strings + # Turn repeated input strings (such as the build output directory) into step outputs. These step outputs can be used throughout the workflow file. + id: strings + shell: bash + run: | + echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT" + + case "${{ matrix.c_compiler }}" in + gcc*) + conan_compiler=gcc + ;; + clang*) + conan_compiler=clang + ;; + cl) + conan_compiler=msvc + ;; + esac + echo "conan_compiler=$conan_compiler" >> "$GITHUB_OUTPUT" + + case "${{ matrix.c_compiler }}" in + gcc*) + conan_compiler_version=$(${{ matrix.c_compiler }} -dumpversion | cut -d. -f1) + ;; + clang*) + conan_compiler_version=$(${{ matrix.c_compiler }} -dumpversion | cut -d. -f1) + ;; + cl) + conan_compiler_version=195 + ;; + esac + echo "conan_compiler_version=$conan_compiler_version" >> "$GITHUB_OUTPUT" + + - name: Create Conan Dependencies Profile + shell: bash + run: | + cat << EOF > profile.txt + [settings] + arch=x86_64 + os=$RUNNER_OS + compiler=${{ steps.strings.outputs.conan_compiler }} + compiler.version=${{ steps.strings.outputs.conan_compiler_version }} + compiler.cppstd=23 + $([[ "${{ steps.strings.outputs.conan_compiler }}" == "gcc" ]] && echo "compiler.libcxx=libstdc++11") + $([[ "${{ steps.strings.outputs.conan_compiler }}" == "clang" ]] && echo "compiler.libcxx=libc++") + $([[ "${{ steps.strings.outputs.conan_compiler }}" == "msvc" ]] && echo "compiler.runtime=static") + + [buildenv] + CC=${{ matrix.c_compiler }} + CXX=${{ matrix.cpp_compiler }} + + [conf] + tools.cmake.cmaketoolchain:generator=Ninja Multi-Config + tools.cmake.cmake_layout:build_folder_vars=['settings.compiler', 'settings.arch'] + EOF + + - name: Install Conan + shell: bash + run: | + pip install conan==2.31.2 + conan profile detect + + - name: Configure Conan Dependencies + shell: bash + run: > + conan install + -of build + -s build_type=${{ matrix.build_type }} + -b=missing + -pr:a=profile.txt + . + + - name: Configure CMake + # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. + # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type + shell: bash + run: > + cmake + -B build + --preset=conan-${{ steps.strings.outputs.conan_compiler }}-x86_64 + . + + - name: Build + # Build your program with the given configuration. Note that --config is needed because the default Windows generator is a multi-config generator (Visual Studio generator). + run: > + cmake + --build ${{ steps.strings.outputs.build-output-dir }} + --config ${{ matrix.build_type }} + + - name: Test + working-directory: ${{ steps.strings.outputs.build-output-dir }} + # Execute tests defined by the CMake configuration. Note that --build-config is needed because the default Windows generator is a multi-config generator (Visual Studio generator). + # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail + run: ctest --preset=conan-${{ steps.strings.outputs.conan_compiler }}-x86_64-release diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 0861f1b..7e256a5 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -1,21 +1,21 @@ -name: Docker Image CI +# name: Docker Image CI -on: - push: - branches: [ "main" ] - pull_request: - branches: [ "main" ] +# on: +# push: +# branches: [ "main" ] +# pull_request: +# branches: [ "main" ] -jobs: - build-gnu: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v5 - - name: Build the GNU Docker image - run: docker build . --file docker/Dockerfile-gcc --tag cmake-cpp-modules-template-gcc:$(date +%s) - build-clang: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v5 - - name: Build the Clang Docker image - run: docker build . --file docker/Dockerfile-clang --tag cmake-cpp-modules-template-clang:$(date +%s) +# jobs: +# build-gnu: +# runs-on: ubuntu-latest +# steps: +# - uses: actions/checkout@v5 +# - name: Build the GNU Docker image +# run: docker build . --file docker/Dockerfile-gcc --tag cmake-cpp-modules-template-gcc:$(date +%s) +# build-clang: +# runs-on: ubuntu-latest +# steps: +# - uses: actions/checkout@v5 +# - name: Build the Clang Docker image +# run: docker build . --file docker/Dockerfile-clang --tag cmake-cpp-modules-template-clang:$(date +%s) diff --git a/CMakeLists.txt b/CMakeLists.txt index e0b2f3b..35fd7db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,8 +7,10 @@ if (CMAKE_VERSION VERSION_LESS "4.0.3") set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "a9e1cf81-9932-4810-974b-6eccaf14e457") elseif (CMAKE_VERSION VERSION_LESS "4.3.0") set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "d0edc3af-4c50-42ea-a356-e2862fe7a444") -else() +elseif (CMAKE_VERSION VERSION_LESS "4.4.0") set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "451f2fe2-a8a2-47c3-bc32-94786d8fc91b") +else() + set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "f35a9ac6-8463-4d38-8eec-5d6008153e7d") endif() # Project + Language @@ -22,12 +24,15 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") # Disable linking to compiler included std library module # will instead link std to libcxx wrapper set(CMAKE_CXX_MODULE_STD OFF) +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + # problematic in github CI + set(CMAKE_CXX_MODULE_STD OFF) else() set(CMAKE_CXX_MODULE_STD ON) endif() # Options -option(ENABLE_EIGEN "Add Eigen support?" ON) +option(ENABLE_EIGEN "Add Eigen support?" OFF) option(ENABLE_CUDA "Add Cuda support?" OFF) option(BUILD_TESTING "Enable Testing?" ON) @@ -39,7 +44,9 @@ include(cmake/cpp_modules.cmake) # Ninja has a bug where color terminal isnt detected when piping if (CMAKE_GENERATOR STREQUAL "Ninja Multi-Config") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color=always") + if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color=always") + endif() endif() if(ENABLE_CUDA) diff --git a/README.md b/README.md index 53a0d9d..ec85836 100644 --- a/README.md +++ b/README.md @@ -99,7 +99,7 @@ cmake -B build/clang --preset=conan-clang-x86_64 # build cmake --build build/clang --config Release -j8 # test -ctest -C Release --test-dir build/clang --no-compress-output --verbose +ctest -preset=${CONAN_PROFILE} --no-compress-output --verbose ``` ### GNU @@ -115,7 +115,7 @@ cmake -B build/gcc --preset=conan-gcc-x86_64 # build cmake --build build/gcc --config Release -j8 # test -ctest -C Release --test-dir build/gcc --no-compress-output --verbose +ctest -preset=${CONAN_PROFILE} --no-compress-output --verbose ``` ## Dockerfile diff --git a/targets/cpp-deps-modules/eigen/CMakeLists.txt b/targets/cpp-deps-modules/eigen/CMakeLists.txt index 39a891d..23d7e72 100644 --- a/targets/cpp-deps-modules/eigen/CMakeLists.txt +++ b/targets/cpp-deps-modules/eigen/CMakeLists.txt @@ -18,20 +18,6 @@ target_sources(eigen-modules PUBLIC # cppm is non-standard by gcc set_source_files_properties(${SRCS} PROPERTIES LANGUAGE CXX) - -# PATCHES -# conan list "eigen/5.0.1:*" -fp=profile-clang-manjaro.txt -# patch -f -d $(conan cache path eigen/5.0.1:da39a3ee5e6b4b0d3255bfef95601890afd80709) -p0 < patches/patch_eigen_5_0_1_static.patch - -# set(CONAN_REF "eigen/5.0.1:da39a3ee5e6b4b0d3255bfef95601890afd80709") - -# execute_process( -# COMMAND conan cache path ${CONAN_REF} -# OUTPUT_VARIABLE EIGEN_CACHE_PATH -# OUTPUT_STRIP_TRAILING_WHITESPACE -# COMMAND_ERROR_IS_FATAL ANY -# ) - # HEADER PATCHES set(EIGEN_PATCH ${CMAKE_CURRENT_SOURCE_DIR}/patches/patch_eigen_5_0_1_static.patch diff --git a/targets/cpp-deps-modules/libcxx/CMakeLists.txt b/targets/cpp-deps-modules/libcxx/CMakeLists.txt index dc32150..0a10811 100644 --- a/targets/cpp-deps-modules/libcxx/CMakeLists.txt +++ b/targets/cpp-deps-modules/libcxx/CMakeLists.txt @@ -21,7 +21,6 @@ target_compile_definitions(${TARGET_NAME} PRIVATE _LIBCPP_HAS_WIDE_CHARACTERS=1) target_compile_definitions(${TARGET_NAME} PRIVATE _LIBCPP_HAS_THREADS=1) target_compile_definitions(${TARGET_NAME} PRIVATE _LIBCPP_HAS_RANDOM_DEVICE=1) -FILE(GLOB_RECURSE SRCS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cppm) target_sources(${TARGET_NAME} PUBLIC FILE_SET CXX_MODULES BASE_DIRS diff --git a/targets/cpp-deps-modules/libcxx/std/algorithm.inc b/targets/cpp-deps-modules/libcxx/std/algorithm.inc index efc73e6..b6821e0 100644 --- a/targets/cpp-deps-modules/libcxx/std/algorithm.inc +++ b/targets/cpp-deps-modules/libcxx/std/algorithm.inc @@ -155,7 +155,7 @@ export namespace std { } namespace ranges { -#if _LIBCPP_STD_VER >= 23 +#if _LIBCPP_STD_VER >= 26 # if !__GNUC__ // [alg.starts.with], starts with using std::ranges::starts_with; diff --git a/targets/cpp-deps-modules/libcxx/std/iterator.inc b/targets/cpp-deps-modules/libcxx/std/iterator.inc index fa79f22..6ce8e7c 100644 --- a/targets/cpp-deps-modules/libcxx/std/iterator.inc +++ b/targets/cpp-deps-modules/libcxx/std/iterator.inc @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// -#ifdef __GNUC__ +#if defined(__GNUC__) && !defined(__clang__) export namespace __gnu_cxx { using __gnu_cxx::operator-; using __gnu_cxx::operator==; @@ -198,6 +198,7 @@ export namespace std { using std::insert_iterator; using std::inserter; +#if not defined(__clang__) // [const.iterators], constant iterators and sentinels // [const.iterators.alias], alias templates using std::const_iterator; @@ -207,9 +208,10 @@ export namespace std { // [const.iterators.iterator], class template basic_const_iterator using std::basic_const_iterator; - using std::common_type; - using std::make_const_iterator; +#endif + + using std::common_type; // [move.iterators], move iterators and sentinels using std::move_iterator; diff --git a/targets/cpp-deps-modules/libcxx/std/ranges.inc b/targets/cpp-deps-modules/libcxx/std/ranges.inc index fe3efe0..7c500e8 100644 --- a/targets/cpp-deps-modules/libcxx/std/ranges.inc +++ b/targets/cpp-deps-modules/libcxx/std/ranges.inc @@ -351,7 +351,7 @@ export namespace std { } #endif -#if _LIBCPP_STD_VER >= 23 +#if _LIBCPP_STD_VER >= 26 // [range.chunk.by], chunk by view using std::ranges::chunk_by_view; diff --git a/targets/cpp-deps-modules/range-v3/src/range_v3.views.cppm b/targets/cpp-deps-modules/range-v3/src/range_v3.views.cppm index 2184fc6..922d99e 100644 --- a/targets/cpp-deps-modules/range-v3/src/range_v3.views.cppm +++ b/targets/cpp-deps-modules/range-v3/src/range_v3.views.cppm @@ -8,10 +8,12 @@ export module range_v3:views; export namespace ranges { + using ranges::view_interface; using ranges::iota_view; using ranges::join_view; using ranges::common_view; using ranges::drop_view; + using ranges::invocable_view_closure; using ranges::view_facade; using ranges::operator==; using ranges::operator!=; @@ -26,4 +28,6 @@ export namespace ranges::views using ranges::views::intersperse; using ranges::views::filter; using ranges::views::transform; + + using ranges::views::view_closure; } diff --git a/targets/cpp-deps-modules/unifex/src/unifex.cppm b/targets/cpp-deps-modules/unifex/src/unifex.cppm index e024b4a..5ec6588 100644 --- a/targets/cpp-deps-modules/unifex/src/unifex.cppm +++ b/targets/cpp-deps-modules/unifex/src/unifex.cppm @@ -25,8 +25,10 @@ module; #include #include +#if defined(__linux__) #include "io_uring_context.hpp" -//#include +// #include +#endif // __linux__ export module unifex; @@ -116,8 +118,10 @@ export namespace unifex { using unifex::_wsa::_wsa_sender_wrapper; } +#if defined(__linux) namespace linuxos { using unifex::linuxos::io_uring_context; } +#endif // __linux__ } // namespace unifex diff --git a/targets/cpp-deps-modules/ut/src/boost/ut.cppm b/targets/cpp-deps-modules/ut/src/boost/ut.cppm index cb5cafc..250e7a3 100644 --- a/targets/cpp-deps-modules/ut/src/boost/ut.cppm +++ b/targets/cpp-deps-modules/ut/src/boost/ut.cppm @@ -5,12 +5,17 @@ module; #include #endif +#if defined(_MSC_VER) +#include +#endif + export module boost.ut; export import std; #define BOOST_UT_CXX_MODULES 1 -#include "custom_ut.hpp" +#include "./ut.hpp" +#if !defined(_MSC_VER) template class boost::ut::reporter_junit; template void boost::ut::reporter_junit::on(boost::ut::events::log); template void boost::ut::reporter_junit::on(boost::ut::events::assertion_pass); @@ -20,3 +25,4 @@ template auto boost::ut::expect(const bool&expr,const reflection::source_l template void boost::ut::reporter_junit<>::on>(events::assertion_fail>); template void boost::ut::reporter_junit<>::on>(events::assertion_pass>); template void boost::ut::reporter_junit<>::on>(events::log>); +#endif //!defined(_MSC_VER) diff --git a/targets/cpp-deps-modules/ut/src/boost/custom_ut.hpp b/targets/cpp-deps-modules/ut/src/boost/ut.hpp similarity index 99% rename from targets/cpp-deps-modules/ut/src/boost/custom_ut.hpp rename to targets/cpp-deps-modules/ut/src/boost/ut.hpp index c4f79b7..6e4c467 100644 --- a/targets/cpp-deps-modules/ut/src/boost/custom_ut.hpp +++ b/targets/cpp-deps-modules/ut/src/boost/ut.hpp @@ -1732,7 +1732,9 @@ class reporter_junit { ss_out_ << "Running test \"" << test_event.name << "\" ... "; } ss_out_ << color_.pass << "PASSED " << color_.none; + #if !defined(_MSC_VER) print_duration(ss_out_); + #endif // !defined(_MSC_VER) lcout_ << ss_out_.str(); } } @@ -1777,7 +1779,9 @@ class reporter_junit { lcout_ << getLeadingSpace(); lcout_ << "Running test \"" << current_node_->test_name << "\"... "; lcout_ << color_.fail << "FAILED " << color_.none; + #if !defined(_MSC_VER) print_duration(lcout_); + #endif // !defined(_MSC_VER) lcout_ << '\n'; lcout_ << current_node_->report_string << '\n'; } @@ -1801,7 +1805,9 @@ class reporter_junit { if (report_type_ == CONSOLE) { ss << getLeadingSpace(); ss << color_.fail << "FAILED " << color_.none; + #if !defined(_MSC_VER) print_duration(ss); + #endif // !defined(_MSC_VER) } ss << "in: " << assertion.location.file_name() << ':' << assertion.location.line(); diff --git a/targets/foobar/tests/performance/benchmark_unifex.cxx b/targets/foobar/tests/performance/benchmark_unifex.cxx index 8f7199a..3745e71 100644 --- a/targets/foobar/tests/performance/benchmark_unifex.cxx +++ b/targets/foobar/tests/performance/benchmark_unifex.cxx @@ -1,3 +1,6 @@ + +#if !defined(_MSC_VER) + #include import boost.ut; @@ -18,6 +21,7 @@ namespace unifex using unifex::static_thread_pool; using unifex::timed_single_thread_context; +#if defined(__linux) namespace linuxos { using unifex::linuxos::io_uring_context; @@ -50,6 +54,7 @@ namespace unifex } }; } +#endif // __linux__ } ut::suite<"unifex"> unifex_suite = [] { @@ -75,6 +80,8 @@ ut::suite<"unifex"> unifex_suite = [] { ex::sync_wait(std::move(all)); }); } + +#if defined(__linux__) { ex::linuxos::io_uring_thread_context io_ctx; auto ioSched = io_ctx.get_scheduler(); @@ -90,5 +97,8 @@ ut::suite<"unifex"> unifex_suite = [] { ex::sync_wait(std::move(all)); }); } +#endif // __linux__ }; -}; \ No newline at end of file +}; + +#endif // !defined(_MSC_VER) \ No newline at end of file diff --git a/targets/foobar/tests/unit/test_foo_ranges.cxx b/targets/foobar/tests/unit/test_foo_ranges.cxx index 0b4c6b8..c3163c6 100644 --- a/targets/foobar/tests/unit/test_foo_ranges.cxx +++ b/targets/foobar/tests/unit/test_foo_ranges.cxx @@ -2,31 +2,37 @@ import boost.ut; import cmake_cpp_modules_template.foobar.foo; import std; -using namespace boost::ut; +namespace ut = boost::ut; +using namespace boost::ut::literals; + +// NOTE: using namespace boost::ut polutes the foo +// module resolution on MSVC +using boost::ut::operators::operator==; + using namespace cmake_cpp_modules_template::foobar; -suite<"foo_ranges"> foo_ranges_suite = [] { +ut::suite<"foo_ranges"> foo_ranges_suite = [] { const foo f; "simple"_test = [&] { - expect(1 == 1_i); + ut::expect(1 == 1_i); }; "name"_test = [&] { - expect(f.name() == "foo"); + ut::expect(f.name() == "foo"); }; "std_iota_str"_test = [&] { - expect(f.std_iota_str(0,5) == "[0,1,2,3,4]"); + ut::expect(f.std_iota_str(0,5) == "[0,1,2,3,4]"); }; "ranges_iota_str"_test = [&] { - expect(f.ranges_iota_str(0,5) == "[0,1,2,3,4]"); + ut::expect(f.ranges_iota_str(0,5) == "[0,1,2,3,4]"); }; "ranges_trange_str"_test = [&] { - expect( + ut::expect( f.ranges_range_str(std::vector{0,0.5,1,1.5,2}) == "[0,0.5,1,1.5,2]" ); }; "fibonacci_str"_test = [&] { - expect(f.fibonacci_str(5) == "[0,1,1,2,3]"); + ut::expect(f.fibonacci_str(5) == "[0,1,1,2,3]"); }; };