From 1ab44981c3f68a08b9700aea5ec95ded866e2202 Mon Sep 17 00:00:00 2001 From: Eugene Lozko Date: Mon, 3 Aug 2026 00:57:55 +0300 Subject: [PATCH 1/7] build: add c++ modules support --- CMakeLists.txt | 41 +++++++++++++++++++++++++++++++++++------ modules/miniocpp.cc | 26 ++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 6 deletions(-) create mode 100644 modules/miniocpp.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 631e951..d6a70f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -174,6 +174,25 @@ target_include_directories(miniocpp PUBLIC $ ) target_link_libraries(miniocpp PUBLIC ${MINIO_CPP_LIBS}) + +# Optional C++20 module interface for the public API (modules/miniocpp.cc). +# FILE_SET CXX_MODULES (CMake 3.28+) attaches it as a real part of the miniocpp +# target's build - the compiler gets whatever flags it needs for a module +# interface unit (e.g. /interface for MSVC) based on this declaration, not on +# the file's extension, so any CMake/MSBuild/Meson (via cmake.subproject()) +# consumer of this target picks up `import miniocpp;` automatically. Requires +# C++20 (MINIO_CPP_STD=20); silently skipped otherwise for older setups. +set(MINIO_CPP_HAS_CXX_MODULE OFF) +if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.28" AND MINIO_CPP_STD STREQUAL "20") + set(MINIO_CPP_HAS_CXX_MODULE ON) + target_sources(miniocpp + PUBLIC + FILE_SET CXX_MODULES + BASE_DIRS modules + FILES modules/miniocpp.cc + ) +endif() + if (MINIO_CPP_ENABLE_RDMA) target_compile_definitions(miniocpp PUBLIC MINIO_CPP_RDMA) endif() @@ -295,12 +314,22 @@ configure_package_config_file( NO_CHECK_REQUIRED_COMPONENTS_MACRO ) -install(TARGETS miniocpp - EXPORT miniocpp-targets - RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" - ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" - LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" - INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") +if (MINIO_CPP_HAS_CXX_MODULE) + install(TARGETS miniocpp + EXPORT miniocpp-targets + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" + FILE_SET CXX_MODULES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/miniocpp/modules") +else() + install(TARGETS miniocpp + EXPORT miniocpp-targets + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") +endif() install(EXPORT miniocpp-targets NAMESPACE miniocpp:: diff --git a/modules/miniocpp.cc b/modules/miniocpp.cc new file mode 100644 index 0000000..e4c4e11 --- /dev/null +++ b/modules/miniocpp.cc @@ -0,0 +1,26 @@ +module; + +#include + +export module miniocpp; + +// Re-exporting the public API through the module requires an EXPLICIT using- +// declaration per symbol (using ns::Symbol;) - not a using-directive (using +// namespace ns;), because declarations from the global module fragment (the +// #include above) only become "reachable", not automatic members of an export +// namespace. The list below covers what a typical consumer needs today - +// extend it by adding more using-declarations as needed. +export namespace minio::s3 { + using s3::BaseUrl; + using s3::Client; + using s3::BucketExistsArgs; + using s3::BucketExistsResponse; +} + +export namespace minio::creds { + using minio::creds::StaticProvider; +} + +export namespace minio { + using minio::Result; +} From 7a2520ac89d3e0271e99f71da38259bfb9963843 Mon Sep 17 00:00:00 2001 From: Eugene Lozko Date: Mon, 3 Aug 2026 01:00:22 +0300 Subject: [PATCH 2/7] build: add meson support, fix pc.in deps --- meson.build | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++ miniocpp.pc.in | 2 +- 2 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 meson.build diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..ba20ad2 --- /dev/null +++ b/meson.build @@ -0,0 +1,56 @@ +project('miniocpp', 'cpp', version : '0.4.0') + +cxx = meson.get_compiler('cpp') + +openssl_dep = dependency('openssl') +curlpp_dep = dependency('curlpp') +inih_dep = dependency('INIReader') +nlohmann_json_dep = dependency('nlohmann_json') +pugixml_dep = dependency('pugixml') +zlib_dep = dependency('zlib') + +extra_libs = [] +if host_machine.system() == 'windows' + extra_libs = [cxx.find_library('ws2_32'), cxx.find_library('wsock32')] +endif + +all_deps = [openssl_dep, curlpp_dep, inih_dep, nlohmann_json_dep, pugixml_dep, zlib_dep] + extra_libs +miniocpp_include = include_directories('include') + +miniocpp_sources = files( + 'src/args.cc', + 'src/baseclient.cc', + 'src/client.cc', + 'src/credentials.cc', + 'src/error.cc', + 'src/http.cc', + 'src/providers.cc', + 'src/request.cc', + 'src/response.cc', + 'src/select.cc', + 'src/signer.cc', + 'src/sse.cc', + 'src/types.cc', + 'src/utils.cc', +) + +# The real library - all .cc files from this repo, not the official minio-cpp +# vcpkg package. +miniocpp_lib = static_library('miniocpp', miniocpp_sources, + include_directories : miniocpp_include, + dependencies : all_deps, +) + +# Module as its own target - /interface only applies to this one file, not to +# every .cc source. +miniocpp_module_lib = static_library('miniocpp_module', 'modules/miniocpp.cc', + include_directories : miniocpp_include, + dependencies : all_deps, + cpp_args : ['/interface'], +) + +miniocpp_dep = declare_dependency( + link_with : [miniocpp_lib, miniocpp_module_lib], + include_directories : miniocpp_include, + dependencies : all_deps, +) diff --git a/miniocpp.pc.in b/miniocpp.pc.in index ef7d572..7d142ba 100644 --- a/miniocpp.pc.in +++ b/miniocpp.pc.in @@ -7,6 +7,6 @@ Name: @PROJECT_NAME@ Description: @PROJECT_DESCRIPTION@ Version: @PROJECT_VERSION@ -Requires: +Requires: curlpp libcrypto libssl pugixml zlib Libs: -L${libdir} -lminiocpp Cflags: -I${includedir} \ No newline at end of file From 0bc22b5d2261dfd179d3e3c5ec371ff86528c2e3 Mon Sep 17 00:00:00 2001 From: Eugene Lozko Date: Mon, 3 Aug 2026 01:15:41 +0300 Subject: [PATCH 3/7] fix(module): use clang-format (Google style) --- modules/miniocpp.cc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/miniocpp.cc b/modules/miniocpp.cc index e4c4e11..95fbc25 100644 --- a/modules/miniocpp.cc +++ b/modules/miniocpp.cc @@ -11,16 +11,16 @@ export module miniocpp; // namespace. The list below covers what a typical consumer needs today - // extend it by adding more using-declarations as needed. export namespace minio::s3 { - using s3::BaseUrl; - using s3::Client; - using s3::BucketExistsArgs; - using s3::BucketExistsResponse; -} +using s3::BaseUrl; +using s3::BucketExistsArgs; +using s3::BucketExistsResponse; +using s3::Client; +} // namespace minio::s3 export namespace minio::creds { - using minio::creds::StaticProvider; +using minio::creds::StaticProvider; } export namespace minio { - using minio::Result; +using minio::Result; } From 10b36c8c5dbc599930817d8f21cc54ed83f5586f Mon Sep 17 00:00:00 2001 From: Eugene Lozko Date: Mon, 3 Aug 2026 23:18:55 +0300 Subject: [PATCH 4/7] build(meson): fix build for non-MSVC compilers --- CMakeLists.txt | 9 +++++++++ meson.build | 3 ++- miniocpp.pc.in | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d6a70f5..075388f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -104,6 +104,10 @@ list(APPEND MINIO_CPP_LIBS if (WIN32) list(APPEND MINIO_CPP_LIBS wsock32) list(APPEND MINIO_CPP_LIBS ws2_32) + # miniocpp.pc.in has no visibility into target_link_libraries() - without this, + # pkg-config consumers (non-CMake) are missing wsock32/ws2_32 at link time + # (getaddrinfo, select, ...). + set(MINIO_CPP_PC_EXTRA_LIBS " -lwsock32 -lws2_32") endif() # Minio C++ Library @@ -137,6 +141,7 @@ set(MINIO_CPP_HEADERS include/miniocpp/providers.h include/miniocpp/request.h include/miniocpp/response.h + include/miniocpp/result.h include/miniocpp/select.h include/miniocpp/signer.h include/miniocpp/sse.h @@ -342,5 +347,9 @@ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/miniocpp-config.cmake" install(FILES ${MINIO_CPP_HEADERS} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/miniocpp") +# error.h/credentials.h depend on the vendored tl::expected, which is otherwise +# never installed - without this, consumers (e.g. via vcpkg) fail to build. +install(DIRECTORY include/tl DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") + configure_file(miniocpp.pc.in ${CMAKE_CURRENT_BINARY_DIR}/miniocpp.pc @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/miniocpp.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) diff --git a/meson.build b/meson.build index ba20ad2..e32e237 100644 --- a/meson.build +++ b/meson.build @@ -46,7 +46,8 @@ miniocpp_lib = static_library('miniocpp', miniocpp_sources, miniocpp_module_lib = static_library('miniocpp_module', 'modules/miniocpp.cc', include_directories : miniocpp_include, dependencies : all_deps, - cpp_args : ['/interface'], + cpp_args : cxx.get_id() == 'msvc' ? ['/interface'] : [], + override_options : ['cpp_std=c++20'], ) miniocpp_dep = declare_dependency( diff --git a/miniocpp.pc.in b/miniocpp.pc.in index 7d142ba..06e69f5 100644 --- a/miniocpp.pc.in +++ b/miniocpp.pc.in @@ -8,5 +8,5 @@ Description: @PROJECT_DESCRIPTION@ Version: @PROJECT_VERSION@ Requires: curlpp libcrypto libssl pugixml zlib -Libs: -L${libdir} -lminiocpp +Libs: -L${libdir} -lminiocpp@MINIO_CPP_PC_EXTRA_LIBS@ Cflags: -I${includedir} \ No newline at end of file From 9df265457357077c5467133c1b13cb7b0b313675 Mon Sep 17 00:00:00 2001 From: Eugene Lozko Date: Wed, 5 Aug 2026 01:01:29 +0300 Subject: [PATCH 5/7] build(cmake): skip C++20 module on generators that don't support it --- CMakeLists.txt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 075388f..9912f85 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -187,8 +187,18 @@ target_link_libraries(miniocpp PUBLIC ${MINIO_CPP_LIBS}) # the file's extension, so any CMake/MSBuild/Meson (via cmake.subproject()) # consumer of this target picks up `import miniocpp;` automatically. Requires # C++20 (MINIO_CPP_STD=20); silently skipped otherwise for older setups. +# +# CMake's module dependency scanning is only implemented for the Ninja, +# Ninja Multi-Config, and Visual Studio (17.4+) generators - with any other +# generator (e.g. the Linux/macOS default "Unix Makefiles") CMake hard-errors +# at the Generate step as soon as it sees FILE_SET CXX_MODULES sources, even +# if MINIO_CPP_STD=20 was requested intentionally. So gate on the generator +# too, and silently fall back to a module-less build rather than failing. set(MINIO_CPP_HAS_CXX_MODULE OFF) -if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.28" AND MINIO_CPP_STD STREQUAL "20") +if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.28" AND MINIO_CPP_STD STREQUAL "20" + AND (CMAKE_GENERATOR STREQUAL "Ninja" + OR CMAKE_GENERATOR STREQUAL "Ninja Multi-Config" + OR CMAKE_GENERATOR MATCHES "^Visual Studio ")) set(MINIO_CPP_HAS_CXX_MODULE ON) target_sources(miniocpp PUBLIC From db177f918338956dbe9f3706510aa529b32e22f0 Mon Sep 17 00:00:00 2001 From: Eugene Lozko Date: Wed, 5 Aug 2026 01:17:10 +0300 Subject: [PATCH 6/7] build(cmake): check actual Ninja/MSVC versions for module support --- CMakeLists.txt | 54 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9912f85..6521ae2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -192,20 +192,48 @@ target_link_libraries(miniocpp PUBLIC ${MINIO_CPP_LIBS}) # Ninja Multi-Config, and Visual Studio (17.4+) generators - with any other # generator (e.g. the Linux/macOS default "Unix Makefiles") CMake hard-errors # at the Generate step as soon as it sees FILE_SET CXX_MODULES sources, even -# if MINIO_CPP_STD=20 was requested intentionally. So gate on the generator -# too, and silently fall back to a module-less build rather than failing. +# if MINIO_CPP_STD=20 was requested intentionally. Generator *name* alone is +# not enough either: CMake 3.28 requires Ninja 1.11+ for the dyndep-based +# scanning, and MSVC itself only gained module support with the 14.34 (VS +# 17.4) toolset (cl.exe reports this as compiler version 19.34) - an older +# Ninja or older MSVC can still match the generator check above and then +# break module dependency scanning instead of falling back cleanly. So +# gate on actual tool versions too, and silently fall back to a module-less +# build rather than failing. set(MINIO_CPP_HAS_CXX_MODULE OFF) -if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.28" AND MINIO_CPP_STD STREQUAL "20" - AND (CMAKE_GENERATOR STREQUAL "Ninja" - OR CMAKE_GENERATOR STREQUAL "Ninja Multi-Config" - OR CMAKE_GENERATOR MATCHES "^Visual Studio ")) - set(MINIO_CPP_HAS_CXX_MODULE ON) - target_sources(miniocpp - PUBLIC - FILE_SET CXX_MODULES - BASE_DIRS modules - FILES modules/miniocpp.cc - ) +if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.28" AND MINIO_CPP_STD STREQUAL "20") + set(MINIO_CPP_MODULE_TOOLCHAIN_OK OFF) + if (CMAKE_GENERATOR STREQUAL "Ninja" OR CMAKE_GENERATOR STREQUAL "Ninja Multi-Config") + execute_process( + COMMAND "${CMAKE_MAKE_PROGRAM}" --version + OUTPUT_VARIABLE MINIO_CPP_NINJA_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + if (MINIO_CPP_NINJA_VERSION VERSION_GREATER_EQUAL "1.11") + set(MINIO_CPP_MODULE_TOOLCHAIN_OK ON) + endif() + elseif (CMAKE_GENERATOR MATCHES "^Visual Studio ") + set(MINIO_CPP_MODULE_TOOLCHAIN_OK ON) + endif() + + # Applies regardless of which of the generators above is in use - Ninja can + # also drive an MSVC toolchain on Windows, and MSVC's own module support is + # gated on the toolset version, not the generator. + if (MINIO_CPP_MODULE_TOOLCHAIN_OK AND CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" + AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "19.34") + set(MINIO_CPP_MODULE_TOOLCHAIN_OK OFF) + endif() + + if (MINIO_CPP_MODULE_TOOLCHAIN_OK) + set(MINIO_CPP_HAS_CXX_MODULE ON) + target_sources(miniocpp + PUBLIC + FILE_SET CXX_MODULES + BASE_DIRS modules + FILES modules/miniocpp.cc + ) + endif() endif() if (MINIO_CPP_ENABLE_RDMA) From 3a10f70a214888584a0e9b3bf78f1a875b253071 Mon Sep 17 00:00:00 2001 From: Eugene Lozko Date: Wed, 5 Aug 2026 01:34:38 +0300 Subject: [PATCH 7/7] build(cmake): reject unsupported compilers for CXX_MODULES, document export gap --- CMakeLists.txt | 47 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6521ae2..5313b46 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -194,12 +194,13 @@ target_link_libraries(miniocpp PUBLIC ${MINIO_CPP_LIBS}) # at the Generate step as soon as it sees FILE_SET CXX_MODULES sources, even # if MINIO_CPP_STD=20 was requested intentionally. Generator *name* alone is # not enough either: CMake 3.28 requires Ninja 1.11+ for the dyndep-based -# scanning, and MSVC itself only gained module support with the 14.34 (VS -# 17.4) toolset (cl.exe reports this as compiler version 19.34) - an older -# Ninja or older MSVC can still match the generator check above and then -# break module dependency scanning instead of falling back cleanly. So -# gate on actual tool versions too, and silently fall back to a module-less -# build rather than failing. +# scanning, and each compiler has its own minimum version for module support +# (MSVC 14.34 / VS 17.4, reported as compiler version 19.34; Clang 16; +# GCC 14) - see https://cmake.org/cmake/help/v3.28/manual/cmake-cxxmodules.7.html. +# An older or unrecognized compiler can still match the generator check +# above and then break module dependency scanning instead of falling back +# cleanly, so reject anything not explicitly known-good rather than +# defaulting to allowed. set(MINIO_CPP_HAS_CXX_MODULE OFF) if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.28" AND MINIO_CPP_STD STREQUAL "20") set(MINIO_CPP_MODULE_TOOLCHAIN_OK OFF) @@ -218,11 +219,25 @@ if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.28" AND MINIO_CPP_STD STREQUAL "20") endif() # Applies regardless of which of the generators above is in use - Ninja can - # also drive an MSVC toolchain on Windows, and MSVC's own module support is - # gated on the toolset version, not the generator. - if (MINIO_CPP_MODULE_TOOLCHAIN_OK AND CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" - AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "19.34") - set(MINIO_CPP_MODULE_TOOLCHAIN_OK OFF) + # also drive an MSVC/Clang/GCC toolchain, and each compiler's own module + # support is gated on its own version, not the generator. Reject any + # compiler not explicitly listed here, rather than silently allowing it. + if (MINIO_CPP_MODULE_TOOLCHAIN_OK) + if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "19.34") + set(MINIO_CPP_MODULE_TOOLCHAIN_OK OFF) + endif() + elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "16.0") + set(MINIO_CPP_MODULE_TOOLCHAIN_OK OFF) + endif() + elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "14") + set(MINIO_CPP_MODULE_TOOLCHAIN_OK OFF) + endif() + else() + set(MINIO_CPP_MODULE_TOOLCHAIN_OK OFF) + endif() endif() if (MINIO_CPP_MODULE_TOOLCHAIN_OK) @@ -374,6 +389,16 @@ else() INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") endif() +# Known limitation: this export does not pass CXX_MODULES_DIRECTORY, so an +# installed package (via find_package(miniocpp) + CMake, as opposed to +# consuming subprojects/miniocpp source directly, or via pkg-config/vcpkg) +# is missing the generated module metadata CMake needs to let a downstream +# CMake consumer `import miniocpp;` - see +# https://cmake.org/cmake/help/latest/command/install.html#exporting-c-modules. +# Separately, installing module interfaces is not supported at all with +# the Visual Studio generator (independent of the MINIO_CPP_HAS_CXX_MODULE +# toolchain gate above, which only covers the build step). Neither gap is +# covered by an automated test yet. install(EXPORT miniocpp-targets NAMESPACE miniocpp:: DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/miniocpp"