diff --git a/.github/workflows/modules-ci.yml b/.github/workflows/modules-ci.yml new file mode 100644 index 000000000..6d98b9131 --- /dev/null +++ b/.github/workflows/modules-ci.yml @@ -0,0 +1,173 @@ +name: C++20 Modules CI +on: [push, workflow_dispatch, pull_request] + +env: + # Enable verbose output for CMake and tests + VERBOSE: 1 + CTEST_OUTPUT_ON_FAILURE: 1 + +jobs: + ubuntu-clang-modules: + strategy: + matrix: + buildType: [Debug, Release] + runs-on: ubuntu-latest + steps: + - name: Update package list + run: sudo apt update + - name: Install Dependencies + run: | + sudo apt install -y git libssl-dev build-essential libcurl4-openssl-dev libpsl-dev meson libunistring-dev ninja-build wget + # Install Clang 21+ + wget https://apt.llvm.org/llvm.sh + chmod +x llvm.sh + sudo ./llvm.sh 21 + sudo apt install -y libc++-21-dev libc++abi-21-dev + env: + DEBIAN_FRONTEND: noninteractive + - name: Install CMake 3.28+ + run: | + wget -O cmake.sh https://github.com/Kitware/CMake/releases/download/v3.28.3/cmake-3.28.3-linux-x86_64.sh + sudo sh cmake.sh --prefix=/usr/local --skip-license + cmake --version + - name: Checkout + uses: actions/checkout@v5 + - name: Configure + run: | + cmake -S . -B build \ + -DCMAKE_BUILD_TYPE=${{ matrix.buildType }} \ + -DCMAKE_CXX_COMPILER=clang++-21 \ + -DCMAKE_C_COMPILER=clang-21 \ + -DCPR_BUILD_MODULES=ON \ + -DCPR_BUILD_TESTS=ON \ + -DCPR_BUILD_TESTS_SSL=ON \ + -DCPR_FORCE_OPENSSL_BACKEND=ON \ + -DCPR_USE_SYSTEM_CURL=OFF \ + -G Ninja + - name: Build + run: cmake --build build --verbose + - name: Test + run: ctest --test-dir build --output-on-failure --repeat until-pass:5 + - name: Verify Module Build + run: | + echo "Contents of build/modules:" + ls -la build/modules/ + if [ -f build/modules/libcpr_module.a ] || [ -f build/modules/libcpr_module.so ] || [ -f build/modules/cpr_module.a ] || find build/modules -name "*cpr_module*" -type f | grep -q .; then + echo "Module library built successfully" + else + echo "Error: Module library not found" + exit 1 + fi + + fedora-gcc-modules: + runs-on: ubuntu-latest + container: "fedora:latest" + steps: + - name: Update package list + run: dnf update -y + - name: Install Dependencies + run: dnf install -y gcc g++ git make openssl-devel libcurl-devel cmake libpsl-devel libunistring-devel meson ninja-build + - name: Checkout + uses: actions/checkout@v5 + - name: Configure + run: | + cmake -S . -B build \ + -DCMAKE_BUILD_TYPE=Release \ + -DCPR_BUILD_MODULES=ON \ + -DCPR_BUILD_TESTS=ON \ + -DCPR_BUILD_TESTS_SSL=ON \ + -DCPR_FORCE_OPENSSL_BACKEND=ON \ + -DCPR_USE_SYSTEM_CURL=OFF \ + -G Ninja + - name: Build + run: cmake --build build --verbose + - name: Test + run: ctest --test-dir build --output-on-failure --repeat until-pass:5 + - name: Verify Module Build + run: | + echo "Searching for module build artifacts:" + find build -name "*cpr_module*" -type f || true + find build -name "cpr.gcm" -type f || true + # GCC stores the compiled module interface (BMI) as cpr.gcm rather than + # a traditional archive when all sources are in FILE_SET CXX_MODULES. + # Also check build/lib/ in case LIBRARY_OUTPUT_PATH redirected the archive. + if find build \( -name "*cpr_module*" -o -name "cpr.gcm" \) -type f | grep -q .; then + echo "Module build artifacts found successfully" + else + echo "Error: No module build artifacts found" + exit 1 + fi + + windows-msvc-modules: + runs-on: windows-latest + steps: + - uses: actions/setup-python@v6 + - name: Install meson + run: pip install meson + - name: Setup MSVC environment + uses: ilammy/msvc-dev-cmd@v1 + - name: Checkout + uses: actions/checkout@v5 + - name: Install dependencies via vcpkg + run: | + vcpkg install curl zlib openssl --triplet x64-windows + shell: pwsh + - name: Configure + run: | + cmake -S . -B build ` + -DCMAKE_BUILD_TYPE=Release ` + -DCMAKE_TOOLCHAIN_FILE="C:/vcpkg/scripts/buildsystems/vcpkg.cmake" ` + -DVCPKG_TARGET_TRIPLET=x64-windows ` + -DCPR_BUILD_MODULES=ON ` + -DCPR_BUILD_TESTS=ON ` + -DCPR_BUILD_TESTS_SSL=OFF ` + -DCPR_USE_SYSTEM_CURL=ON ` + -G "Visual Studio 17 2022" + shell: pwsh + - name: Build + run: cmake --build build --config Release --verbose + - name: Test + run: ctest --test-dir build -C Release --output-on-failure --repeat until-pass:5 + - name: Verify Module Build + run: | + Write-Host "Contents of build/modules/Release:" + Get-ChildItem -Path build/modules/Release -Force + if (!(Test-Path "build/modules/Release/cpr_module.lib") -and !(Get-ChildItem -Path build/modules -Recurse -Filter "*cpr_module*")) { + throw "Module library not found" + } + Write-Host "Module library built successfully" + shell: pwsh + + macos-clang-modules: + runs-on: macos-latest + steps: + - name: Install Dependencies + run: | + brew install llvm libpsl ninja + - name: Checkout + uses: actions/checkout@v5 + - name: Configure + run: | + cmake -S . -B build \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_CXX_COMPILER=$(brew --prefix llvm)/bin/clang++ \ + -DCMAKE_C_COMPILER=$(brew --prefix llvm)/bin/clang \ + -DCPR_BUILD_MODULES=ON \ + -DCPR_BUILD_TESTS=ON \ + -DCPR_BUILD_TESTS_SSL=OFF \ + -DCPR_USE_SYSTEM_LIB_PSL=ON \ + -G Ninja + - name: Build + run: cmake --build build --verbose + - name: Test + run: ctest --test-dir build --output-on-failure --repeat until-pass:5 + - name: Verify Module Build + run: | + echo "Contents of build/modules:" + ls -la build/modules/ + if [ -f build/modules/libcpr_module.a ] || [ -f build/modules/libcpr_module.dylib ] || [ -f build/modules/cpr_module.a ] || find build/modules -name "*cpr_module*" -type f | grep -q .; then + echo "Module library built successfully" + else + echo "Error: Module library not found" + exit 1 + fi diff --git a/CMakeLists.txt b/CMakeLists.txt index 360818a0c..10100d97e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,6 +68,7 @@ cpr_option(CPR_FORCE_DARWINSSL_BACKEND "Force to use the DarwinSSL backend. If C cpr_option(CPR_FORCE_MBEDTLS_BACKEND "Force to use the Mbed TLS backend. If CPR_FORCE_OPENSSL_BACKEND, CPR_FORCE_DARWINSSL_BACKEND, CPR_FORCE_MBEDTLS_BACKEND, and CPR_FORCE_WINSSL_BACKEND are set to to OFF, cpr will try to automatically detect the best available SSL backend (WinSSL - Windows, OpenSSL - Linux, DarwinSSL - Mac ...)." OFF) cpr_option(CPR_ENABLE_LINTING "Set to ON to enable clang linting." OFF) cpr_option(CPR_ENABLE_CPPCHECK "Set to ON to enable Cppcheck static analysis. Requires CPR_BUILD_TESTS and CPR_BUILD_TESTS_SSL to be OFF to prevent checking google tests source code." OFF) +cpr_option(CPR_BUILD_MODULES "Set to ON to build cpr as a C++ module." OFF) cpr_option(CPR_BUILD_TESTS "Set to ON to build cpr tests." OFF) cpr_option(CPR_BUILD_TESTS_SSL "Set to ON to build cpr ssl tests" ${CPR_BUILD_TESTS}) cpr_option(CPR_BUILD_TESTS_PROXY "Set to ON to build proxy tests. They fail in case there is no valid proxy server available in proxy_tests.cpp" OFF) @@ -323,6 +324,10 @@ else() set(CURL_LIB CURL::libcurl) endif() +if(CPR_BUILD_MODULES) + add_subdirectory(modules) +endif() + # GTest configuration if(CPR_BUILD_TESTS) if(CPR_USE_SYSTEM_GTEST) diff --git a/README.md b/README.md index b052e768a..906616f5d 100644 --- a/README.md +++ b/README.md @@ -181,6 +181,7 @@ The only explicit requirements are: * A `C++17` compatible compiler such as Clang or GCC. The minimum required version of GCC is unknown, so if anyone has trouble building this library with a specific version of GCC, do let us know. * In case you only have a `C++11` compatible compiler available, all versions below cpr 1.9.x are for you. The 1.10.0 release of cpr switches to `C++17` as a requirement. +* If you would like to use cpr as a C++20 module, you must have CMake 3.28 enabled. Enable `CPR_BUILD_MODULES` to activate the feature. * If you would like to perform https requests `OpenSSL` and its development libraries are required. * If you do not use the built-in version of [curl](https://github.com/curl/curl) but instead use your systems version, make sure you use a version `>= 7.71.0`. Lower versions are not supported. This means you need Debian `>= 11` or Ubuntu `>= 22.04 LTS`. * [`The Meson Build System`](https://mesonbuild.com/) is required build PSL from source ([PSL support for curl](https://everything.curl.dev/build/deps.html#libpsl)). For more information take a look at the `CPR_CURL_USE_LIBPSL` and `CPR_USE_SYSTEM_LIB_PSL` CMake options. diff --git a/include/cpr/accept_encoding.h b/include/cpr/accept_encoding.h index 65a08e058..549ed3ff4 100644 --- a/include/cpr/accept_encoding.h +++ b/include/cpr/accept_encoding.h @@ -20,7 +20,7 @@ enum class AcceptEncodingMethods : uint8_t { }; // NOLINTNEXTLINE(cert-err58-cpp) -static const std::map AcceptEncodingMethodsStringMap{{AcceptEncodingMethods::identity, "identity"}, {AcceptEncodingMethods::deflate, "deflate"}, {AcceptEncodingMethods::zlib, "zlib"}, {AcceptEncodingMethods::gzip, "gzip"}, {AcceptEncodingMethods::disabled, "disabled"}}; +inline const std::map AcceptEncodingMethodsStringMap{{AcceptEncodingMethods::identity, "identity"}, {AcceptEncodingMethods::deflate, "deflate"}, {AcceptEncodingMethods::zlib, "zlib"}, {AcceptEncodingMethods::gzip, "gzip"}, {AcceptEncodingMethods::disabled, "disabled"}}; class AcceptEncoding { public: diff --git a/include/cpr/cookies.h b/include/cpr/cookies.h index 53f0c0a29..88f42561d 100644 --- a/include/cpr/cookies.h +++ b/include/cpr/cookies.h @@ -12,7 +12,7 @@ namespace cpr { * EXPIRES_STRING_SIZE is an explicitly static and const variable that could be only accessed within the same namespace and is immutable. * To be used for "std::array", the expression must have a constant value, so EXPIRES_STRING_SIZE must be a const value. **/ -static const std::size_t EXPIRES_STRING_SIZE = 100; +inline const std::size_t EXPIRES_STRING_SIZE = 100; class Cookie { public: diff --git a/include/cpr/cpr.h b/include/cpr/cpr.h index a42058fbd..d72aa62b5 100644 --- a/include/cpr/cpr.h +++ b/include/cpr/cpr.h @@ -10,7 +10,9 @@ #include "cpr/connection_pool.h" #include "cpr/cookies.h" #include "cpr/cprtypes.h" +#ifndef CPR_AS_MODULE #include "cpr/cprver.h" +#endif #include "cpr/curl_container.h" #include "cpr/curlholder.h" #include "cpr/error.h" diff --git a/include/cpr/status_codes.h b/include/cpr/status_codes.h index 53e0d251d..38dc0eb97 100644 --- a/include/cpr/status_codes.h +++ b/include/cpr/status_codes.h @@ -1,82 +1,81 @@ #ifndef CPR_STATUS_CODES #define CPR_STATUS_CODES -namespace cpr { -namespace status { +namespace cpr::status { // Information responses -constexpr long HTTP_CONTINUE = 100; -constexpr long HTTP_SWITCHING_PROTOCOL = 101; -constexpr long HTTP_PROCESSING = 102; -constexpr long HTTP_EARLY_HINTS = 103; +inline constexpr long HTTP_CONTINUE = 100; +inline constexpr long HTTP_SWITCHING_PROTOCOL = 101; +inline constexpr long HTTP_PROCESSING = 102; +inline constexpr long HTTP_EARLY_HINTS = 103; // Successful responses -constexpr long HTTP_OK = 200; -constexpr long HTTP_CREATED = 201; -constexpr long HTTP_ACCEPTED = 202; -constexpr long HTTP_NON_AUTHORITATIVE_INFORMATION = 203; -constexpr long HTTP_NO_CONTENT = 204; -constexpr long HTTP_RESET_CONTENT = 205; -constexpr long HTTP_PARTIAL_CONTENT = 206; -constexpr long HTTP_MULTI_STATUS = 207; -constexpr long HTTP_ALREADY_REPORTED = 208; -constexpr long HTTP_IM_USED = 226; +inline constexpr long HTTP_OK = 200; +inline constexpr long HTTP_CREATED = 201; +inline constexpr long HTTP_ACCEPTED = 202; +inline constexpr long HTTP_NON_AUTHORITATIVE_INFORMATION = 203; +inline constexpr long HTTP_NO_CONTENT = 204; +inline constexpr long HTTP_RESET_CONTENT = 205; +inline constexpr long HTTP_PARTIAL_CONTENT = 206; +inline constexpr long HTTP_MULTI_STATUS = 207; +inline constexpr long HTTP_ALREADY_REPORTED = 208; +inline constexpr long HTTP_IM_USED = 226; // Redirection messages -constexpr long HTTP_MULTIPLE_CHOICE = 300; -constexpr long HTTP_MOVED_PERMANENTLY = 301; -constexpr long HTTP_FOUND = 302; -constexpr long HTTP_SEE_OTHER = 303; -constexpr long HTTP_NOT_MODIFIED = 304; -constexpr long HTTP_USE_PROXY = 305; -constexpr long HTTP_UNUSED = 306; -constexpr long HTTP_TEMPORARY_REDIRECT = 307; -constexpr long HTTP_PERMANENT_REDIRECT = 308; +inline constexpr long HTTP_MULTIPLE_CHOICE = 300; +inline constexpr long HTTP_MOVED_PERMANENTLY = 301; +inline constexpr long HTTP_FOUND = 302; +inline constexpr long HTTP_SEE_OTHER = 303; +inline constexpr long HTTP_NOT_MODIFIED = 304; +inline constexpr long HTTP_USE_PROXY = 305; +inline constexpr long HTTP_UNUSED = 306; +inline constexpr long HTTP_TEMPORARY_REDIRECT = 307; +inline constexpr long HTTP_PERMANENT_REDIRECT = 308; // Client error responses -constexpr long HTTP_BAD_REQUEST = 400; -constexpr long HTTP_UNAUTHORIZED = 401; -constexpr long HTTP_PAYMENT_REQUIRED = 402; -constexpr long HTTP_FORBIDDEN = 403; -constexpr long HTTP_NOT_FOUND = 404; -constexpr long HTTP_METHOD_NOT_ALLOWED = 405; -constexpr long HTTP_NOT_ACCEPTABLE = 406; -constexpr long HTTP_PROXY_AUTHENTICATION_REQUIRED = 407; -constexpr long HTTP_REQUEST_TIMEOUT = 408; -constexpr long HTTP_CONFLICT = 409; -constexpr long HTTP_GONE = 410; -constexpr long HTTP_LENGTH_REQUIRED = 411; -constexpr long HTTP_PRECONDITION_FAILED = 412; -constexpr long HTTP_PAYLOAD_TOO_LARGE = 413; -constexpr long HTTP_URI_TOO_LONG = 414; -constexpr long HTTP_UNSUPPORTED_MEDIA_TYPE = 415; -constexpr long HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416; -constexpr long HTTP_EXPECTATION_FAILED = 417; -constexpr long HTTP_IM_A_TEAPOT = 418; -constexpr long HTTP_MISDIRECTED_REQUEST = 421; -constexpr long HTTP_UNPROCESSABLE_ENTITY = 422; -constexpr long HTTP_LOCKED = 423; -constexpr long HTTP_FAILED_DEPENDENCY = 424; -constexpr long HTTP_TOO_EARLY = 425; -constexpr long HTTP_UPGRADE_REQUIRED = 426; -constexpr long HTTP_PRECONDITION_REQUIRED = 428; -constexpr long HTTP_TOO_MANY_REQUESTS = 429; -constexpr long HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE = 431; -constexpr long HTTP_UNAVAILABLE_FOR_LEGAL_REASONS = 451; +inline constexpr long HTTP_BAD_REQUEST = 400; +inline constexpr long HTTP_UNAUTHORIZED = 401; +inline constexpr long HTTP_PAYMENT_REQUIRED = 402; +inline constexpr long HTTP_FORBIDDEN = 403; +inline constexpr long HTTP_NOT_FOUND = 404; +inline constexpr long HTTP_METHOD_NOT_ALLOWED = 405; +inline constexpr long HTTP_NOT_ACCEPTABLE = 406; +inline constexpr long HTTP_PROXY_AUTHENTICATION_REQUIRED = 407; +inline constexpr long HTTP_REQUEST_TIMEOUT = 408; +inline constexpr long HTTP_CONFLICT = 409; +inline constexpr long HTTP_GONE = 410; +inline constexpr long HTTP_LENGTH_REQUIRED = 411; +inline constexpr long HTTP_PRECONDITION_FAILED = 412; +inline constexpr long HTTP_PAYLOAD_TOO_LARGE = 413; +inline constexpr long HTTP_URI_TOO_LONG = 414; +inline constexpr long HTTP_UNSUPPORTED_MEDIA_TYPE = 415; +inline constexpr long HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416; +inline constexpr long HTTP_EXPECTATION_FAILED = 417; +inline constexpr long HTTP_IM_A_TEAPOT = 418; +inline constexpr long HTTP_MISDIRECTED_REQUEST = 421; +inline constexpr long HTTP_UNPROCESSABLE_ENTITY = 422; +inline constexpr long HTTP_LOCKED = 423; +inline constexpr long HTTP_FAILED_DEPENDENCY = 424; +inline constexpr long HTTP_TOO_EARLY = 425; +inline constexpr long HTTP_UPGRADE_REQUIRED = 426; +inline constexpr long HTTP_PRECONDITION_REQUIRED = 428; +inline constexpr long HTTP_TOO_MANY_REQUESTS = 429; +inline constexpr long HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE = 431; +inline constexpr long HTTP_UNAVAILABLE_FOR_LEGAL_REASONS = 451; // Server response errors -constexpr long HTTP_INTERNAL_SERVER_ERROR = 500; -constexpr long HTTP_NOT_IMPLEMENTED = 501; -constexpr long HTTP_BAD_GATEWAY = 502; -constexpr long HTTP_SERVICE_UNAVAILABLE = 503; -constexpr long HTTP_GATEWAY_TIMEOUT = 504; -constexpr long HTTP_HTTP_VERSION_NOT_SUPPORTED = 505; -constexpr long HTTP_VARIANT_ALSO_NEGOTIATES = 506; -constexpr long HTTP_INSUFFICIENT_STORAGE = 507; -constexpr long HTTP_LOOP_DETECTED = 508; -constexpr long HTTP_NOT_EXTENDED = 510; -constexpr long HTTP_NETWORK_AUTHENTICATION_REQUIRED = 511; +inline constexpr long HTTP_INTERNAL_SERVER_ERROR = 500; +inline constexpr long HTTP_NOT_IMPLEMENTED = 501; +inline constexpr long HTTP_BAD_GATEWAY = 502; +inline constexpr long HTTP_SERVICE_UNAVAILABLE = 503; +inline constexpr long HTTP_GATEWAY_TIMEOUT = 504; +inline constexpr long HTTP_HTTP_VERSION_NOT_SUPPORTED = 505; +inline constexpr long HTTP_VARIANT_ALSO_NEGOTIATES = 506; +inline constexpr long HTTP_INSUFFICIENT_STORAGE = 507; +inline constexpr long HTTP_LOOP_DETECTED = 508; +inline constexpr long HTTP_NOT_EXTENDED = 510; +inline constexpr long HTTP_NETWORK_AUTHENTICATION_REQUIRED = 511; -constexpr long INFO_CODE_OFFSET = 100; -constexpr long SUCCESS_CODE_OFFSET = 200; -constexpr long REDIRECT_CODE_OFFSET = 300; -constexpr long CLIENT_ERROR_CODE_OFFSET = 400; -constexpr long SERVER_ERROR_CODE_OFFSET = 500; -constexpr long MISC_CODE_OFFSET = 600; +inline constexpr long INFO_CODE_OFFSET = 100; +inline constexpr long SUCCESS_CODE_OFFSET = 200; +inline constexpr long REDIRECT_CODE_OFFSET = 300; +inline constexpr long CLIENT_ERROR_CODE_OFFSET = 400; +inline constexpr long SERVER_ERROR_CODE_OFFSET = 500; +inline constexpr long MISC_CODE_OFFSET = 600; constexpr bool is_informational(const long code) { return (code >= INFO_CODE_OFFSET && code < SUCCESS_CODE_OFFSET); @@ -93,7 +92,5 @@ constexpr bool is_client_error(const long code) { constexpr bool is_server_error(const long code) { return (code >= SERVER_ERROR_CODE_OFFSET && code < MISC_CODE_OFFSET); } - -} // namespace status -} // namespace cpr +} // namespace cpr::status #endif diff --git a/include/cpr/threadpool.h b/include/cpr/threadpool.h index 0532a5bed..a32c33fe7 100644 --- a/include/cpr/threadpool.h +++ b/include/cpr/threadpool.h @@ -16,8 +16,8 @@ #define CPR_DEFAULT_THREAD_POOL_MAX_THREAD_NUM std::thread::hardware_concurrency() -constexpr size_t CPR_DEFAULT_THREAD_POOL_MIN_THREAD_NUM = 1; -constexpr std::chrono::milliseconds CPR_DEFAULT_THREAD_POOL_MAX_IDLE_TIME{250}; +inline constexpr size_t CPR_DEFAULT_THREAD_POOL_MIN_THREAD_NUM = 1; +inline constexpr std::chrono::milliseconds CPR_DEFAULT_THREAD_POOL_MAX_IDLE_TIME{250}; namespace cpr { diff --git a/include/cpr/timeout.h b/include/cpr/timeout.h index e2464803d..6f532d306 100644 --- a/include/cpr/timeout.h +++ b/include/cpr/timeout.h @@ -16,7 +16,8 @@ class Timeout { // No way around since curl uses a long here. // NOLINTNEXTLINE(google-runtime-int) - [[nodiscard]] long Milliseconds() const; + [[nodiscard]] + long Milliseconds() const; std::chrono::milliseconds ms; }; diff --git a/include/cpr/unix_socket.h b/include/cpr/unix_socket.h index 4b8701634..5597ac921 100644 --- a/include/cpr/unix_socket.h +++ b/include/cpr/unix_socket.h @@ -9,7 +9,8 @@ class UnixSocket { public: UnixSocket(std::string unix_socket) : unix_socket_(std::move(unix_socket)) {} - [[nodiscard]] const char* GetUnixSocketString() const noexcept; + [[nodiscard]] + const char* GetUnixSocketString() const noexcept; private: const std::string unix_socket_; diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt new file mode 100644 index 000000000..a49dfa2db --- /dev/null +++ b/modules/CMakeLists.txt @@ -0,0 +1,46 @@ +cmake_minimum_required(VERSION 3.28) + +# Apple Clang does not ship clang-scan-deps, which CMake requires for module +# dependency scanning. Use LLVM clang (e.g. from Homebrew) instead. +if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") + message(FATAL_ERROR + "Apple Clang does not support C++20 module dependency scanning.\n" + "Use LLVM clang (e.g. 'brew install llvm') and pass " + "-DCMAKE_CXX_COMPILER=$(brew --prefix llvm)/bin/clang++ to CMake.") +endif() + +# GCC gained module scanning support in version 14. +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND + CMAKE_CXX_COMPILER_VERSION VERSION_LESS "14") + message(FATAL_ERROR + "C++20 module scanning requires GCC 14 or later " + "(found ${CMAKE_CXX_COMPILER_VERSION}).") +endif() + +set(CMAKE_CXX_SCAN_FOR_MODULES ON) + +add_library(cpr_module) + +target_sources(cpr_module + PUBLIC + FILE_SET CXX_MODULES FILES + cpr.cxx +) + +target_compile_features(cpr_module PUBLIC cxx_std_20) + +target_include_directories(cpr_module PUBLIC + $ + $ +) + +add_library(cpr::module ALIAS cpr_module) + +# Installation +install(TARGETS cpr_module + EXPORT ${PROJECT_NAME}Targets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + FILE_SET CXX_MODULES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/module +) diff --git a/modules/cpr.cxx b/modules/cpr.cxx new file mode 100644 index 000000000..2e82643b0 --- /dev/null +++ b/modules/cpr.cxx @@ -0,0 +1,334 @@ +module; + +#define CPR_AS_MODULE +#include "cpr/cpr.h" +#include "cpr/secure_string.h" + +export module cpr; + +export namespace cpr { + using cpr::AcceptEncodingMethods; + using cpr::AcceptEncoding; + using cpr::AsyncResponse; + using cpr::Get; + using cpr::GetAsync; + using cpr::GetCallback; + using cpr::Post; + using cpr::PostAsync; + using cpr::PostCallback; + using cpr::Put; + using cpr::PutAsync; + using cpr::PutCallback; + using cpr::Head; + using cpr::HeadAsync; + using cpr::HeadCallback; + using cpr::Delete; + using cpr::DeleteAsync; + using cpr::DeleteCallback; + using cpr::Options; + using cpr::OptionsAsync; + using cpr::OptionsCallback; + using cpr::Patch; + using cpr::PatchAsync; + using cpr::PatchCallback; + using cpr::Download; + using cpr::DownloadAsync; + using cpr::MultiGet; + using cpr::MultiDelete; + using cpr::MultiPut; + using cpr::MultiHead; + using cpr::MultiOptions; + using cpr::MultiPatch; + using cpr::MultiPost; + using cpr::MultiGetAsync; + using cpr::MultiDeleteAsync; + using cpr::MultiPutAsync; + using cpr::MultiHeadAsync; + using cpr::MultiOptionsAsync; + using cpr::MultiPatchAsync; + using cpr::MultiPostAsync; + using cpr::MultiPutAsync; + using cpr::CancellationResult; + using cpr::AsyncWrapper; + using cpr::GlobalThreadPool; + using cpr::AuthMode; + using cpr::Authentication; + #if LIBCURL_VERSION_NUM >= 0x073D00 + using cpr::Bearer; + #endif + using cpr::BodyView; + using cpr::Body; + using cpr::Buffer; + using cpr::ReadCallback; + using cpr::HeaderCallback; + using cpr::WriteCallback; + using cpr::ProgressCallback; + using cpr::DebugCallback; + using cpr::CancellationCallback; + using cpr::CertInfo; + using cpr::ConnectTimeout; + using cpr::ConnectionPool; + using cpr::Cookie; + using cpr::Cookies; + using cpr::StringHolder; + using cpr::Url; + using cpr::Parameter; + using cpr::Pair; + using cpr::CurlContainer; + using cpr::CurlHolder; + using cpr::CurlMultiHolder; + using cpr::ErrorCode; + using cpr::Error; + using cpr::File; + using cpr::Files; + using cpr::HttpVersionCode; + using cpr::HttpVersion; + using cpr::Interceptor; + using cpr::InterceptorMulti; + using cpr::Interface; + using cpr::LimitRate; + using cpr::LocalPortRange; + using cpr::LocalPort; + using cpr::LowSpeed; + using cpr::Part; + using cpr::Multipart; + using cpr::InterceptorMulti; + using cpr::MultiPerform; + using cpr::Parameters; + using cpr::Payload; + using cpr::Proxies; + using cpr::ProxyAuthentication; + using cpr::EncodedAuthentication; + using cpr::Range; + using cpr::MultiRange; + using cpr::PostRedirectFlags; + using cpr::Redirect; + using cpr::ReserveSize; + using cpr::Resolve; + using cpr::Response; + using cpr::Content; + using cpr::Session; + using cpr::ServerSentEvent; + using cpr::ServerSentEventParser; + using cpr::ServerSentEventCallback; + #if SUPPORT_CURLOPT_SSL_CTX_FUNCTION + using cpr::sslctx_function_load_ca_cert_from_buffer; + #endif + using cpr::VerifySsl; + + namespace ssl { + using cpr::ssl::CertFile; + using cpr::ssl::PemCert; + using cpr::ssl::DerCert; + #if SUPPORT_CURLOPT_SSLCERT_BLOB + using cpr::ssl::CertBlob; + using cpr::ssl::PemBlob; + using cpr::ssl::DerBlob; + #endif + using cpr::ssl::KeyFile; + #if SUPPORT_CURLOPT_SSLKEY_BLOB + using cpr::ssl::KeyBlob; + #endif + using cpr::ssl::PemKey; + using cpr::ssl::DerKey; + using cpr::ssl::PinnedPublicKey; + #if SUPPORT_ALPN + using cpr::ssl::ALPN; + #endif + #if SUPPORT_NPN + using cpr::ssl::NPN; + #endif + using cpr::ssl::VerifyHost; + using cpr::ssl::VerifyPeer; + using cpr::ssl::VerifyStatus; + using cpr::ssl::TLSv1; + #if SUPPORT_SSLv2 + using cpr::ssl::SSLv2; + #endif + #if SUPPORT_SSLv3 + using cpr::ssl::SSLv3; + #endif + #if SUPPORT_TLSv1_0 + using cpr::ssl::TLSv1_0; + #endif + #if SUPPORT_TLSv1_1 + using cpr::ssl::TLSv1_1; + #endif + #if SUPPORT_TLSv1_2 + using cpr::ssl::TLSv1_2; + #endif + #if SUPPORT_TLSv1_3 + using cpr::ssl::TLSv1_3; + #endif + #if SUPPORT_MAX_TLS_VERSION + using cpr::ssl::MaxTLSVersion; + #endif + #if SUPPORT_MAX_TLSv1_0 + using cpr::ssl::MaxTLSv1_0; + #endif + #if SUPPORT_MAX_TLSv1_1 + using cpr::ssl::MaxTLSv1_1; + #endif + #if SUPPORT_MAX_TLSv1_2 + using cpr::ssl::MaxTLSv1_2; + #endif + #if SUPPORT_MAX_TLSv1_3 + using cpr::ssl::MaxTLSv1_3; + #endif + using cpr::ssl::CaInfo; + #if SUPPORT_CURLOPT_CAINFO_BLOB + using cpr::ssl::CaInfoBlob; + #endif + using cpr::ssl::CaPath; + #if SUPPORT_CURLOPT_SSL_CTX_FUNCTION + using cpr::ssl::CaBuffer; + #endif + using cpr::ssl::Crl; + using cpr::ssl::Ciphers; + #if SUPPORT_TLSv13_CIPHERS + using cpr::ssl::TLS13_Ciphers; + #endif + #if SUPPORT_SESSIONID_CACHE + using cpr::ssl::SessionIdCache; + #endif + #if SUPPORT_SSL_FALSESTART + using cpr::ssl::SslFastStart; + #endif + using cpr::ssl::NoRevoke; + } + + using cpr::SslOptions; + using cpr::ThreadPool; + using cpr::Timeout; + using cpr::UnixSocket; + using cpr::UserAgent; + using cpr::Verbose; + + using cpr::cpr_off_t; + using cpr::cpr_pf_arg_t; + + using cpr::async; + using cpr::get_error_code_to_string_mapping; + using cpr::Ssl; + + namespace status { + using cpr::status::HTTP_CONTINUE; + using cpr::status::HTTP_SWITCHING_PROTOCOL; + using cpr::status::HTTP_PROCESSING; + using cpr::status::HTTP_EARLY_HINTS; + using cpr::status::HTTP_OK; + using cpr::status::HTTP_CREATED; + using cpr::status::HTTP_ACCEPTED; + using cpr::status::HTTP_NON_AUTHORITATIVE_INFORMATION; + using cpr::status::HTTP_NO_CONTENT; + using cpr::status::HTTP_RESET_CONTENT; + using cpr::status::HTTP_PARTIAL_CONTENT; + using cpr::status::HTTP_MULTI_STATUS; + using cpr::status::HTTP_ALREADY_REPORTED; + using cpr::status::HTTP_IM_USED; + using cpr::status::HTTP_MULTIPLE_CHOICE; + using cpr::status::HTTP_MOVED_PERMANENTLY; + using cpr::status::HTTP_FOUND; + using cpr::status::HTTP_SEE_OTHER; + using cpr::status::HTTP_NOT_MODIFIED; + using cpr::status::HTTP_USE_PROXY; + using cpr::status::HTTP_UNUSED; + using cpr::status::HTTP_TEMPORARY_REDIRECT; + using cpr::status::HTTP_PERMANENT_REDIRECT; + using cpr::status::HTTP_BAD_REQUEST; + using cpr::status::HTTP_UNAUTHORIZED; + using cpr::status::HTTP_PAYMENT_REQUIRED; + using cpr::status::HTTP_FORBIDDEN; + using cpr::status::HTTP_NOT_FOUND; + using cpr::status::HTTP_METHOD_NOT_ALLOWED; + using cpr::status::HTTP_NOT_ACCEPTABLE; + using cpr::status::HTTP_PROXY_AUTHENTICATION_REQUIRED; + using cpr::status::HTTP_REQUEST_TIMEOUT; + using cpr::status::HTTP_CONFLICT; + using cpr::status::HTTP_GONE; + using cpr::status::HTTP_LENGTH_REQUIRED; + using cpr::status::HTTP_PRECONDITION_FAILED; + using cpr::status::HTTP_PAYLOAD_TOO_LARGE; + using cpr::status::HTTP_URI_TOO_LONG; + using cpr::status::HTTP_UNSUPPORTED_MEDIA_TYPE; + using cpr::status::HTTP_REQUESTED_RANGE_NOT_SATISFIABLE; + using cpr::status::HTTP_EXPECTATION_FAILED; + using cpr::status::HTTP_IM_A_TEAPOT; + using cpr::status::HTTP_MISDIRECTED_REQUEST; + using cpr::status::HTTP_UNPROCESSABLE_ENTITY; + using cpr::status::HTTP_LOCKED; + using cpr::status::HTTP_FAILED_DEPENDENCY; + using cpr::status::HTTP_TOO_EARLY; + using cpr::status::HTTP_UPGRADE_REQUIRED; + using cpr::status::HTTP_PRECONDITION_REQUIRED; + using cpr::status::HTTP_TOO_MANY_REQUESTS; + using cpr::status::HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE; + using cpr::status::HTTP_UNAVAILABLE_FOR_LEGAL_REASONS; + using cpr::status::HTTP_INTERNAL_SERVER_ERROR; + using cpr::status::HTTP_NOT_IMPLEMENTED; + using cpr::status::HTTP_BAD_GATEWAY; + using cpr::status::HTTP_SERVICE_UNAVAILABLE; + using cpr::status::HTTP_GATEWAY_TIMEOUT; + using cpr::status::HTTP_HTTP_VERSION_NOT_SUPPORTED; + using cpr::status::HTTP_VARIANT_ALSO_NEGOTIATES; + using cpr::status::HTTP_INSUFFICIENT_STORAGE; + using cpr::status::HTTP_LOOP_DETECTED; + using cpr::status::HTTP_NOT_EXTENDED; + using cpr::status::HTTP_NETWORK_AUTHENTICATION_REQUIRED; + using cpr::status::INFO_CODE_OFFSET; + using cpr::status::SUCCESS_CODE_OFFSET; + using cpr::status::REDIRECT_CODE_OFFSET; + using cpr::status::CLIENT_ERROR_CODE_OFFSET; + using cpr::status::SERVER_ERROR_CODE_OFFSET; + using cpr::status::MISC_CODE_OFFSET; + + using cpr::status::is_informational; + using cpr::status::is_success; + using cpr::status::is_redirect; + using cpr::status::is_client_error; + using cpr::status::is_server_error; + } + + namespace util { + using cpr::util::SecureAllocator; + using cpr::util::SecureString; + + using cpr::util::parseHeader; + using cpr::util::parseCookies; + using cpr::util::readUserFunction; + using cpr::util::headerUserFunction; + using cpr::util::writeFunction; + using cpr::util::writeFileFunction; + using cpr::util::writeUserFunction; + using cpr::util::writeSSEFunction; + using cpr::util::progressUserFunction; + using cpr::util::debugUserFunction; + using cpr::util::split; + using cpr::util::urlEncode; + using cpr::util::urlDecode; + using cpr::util::isTrue; + using cpr::util::sTimestampToT; + + using cpr::util::operator==; + using cpr::util::operator!=; + } + + using cpr::operator<<; + using cpr::operator|; + using cpr::operator&; + using cpr::operator^; + using cpr::operator~; + using cpr::operator|=; + using cpr::operator&=; + using cpr::operator^=; + using cpr::any; + + using cpr::AcceptEncodingMethodsStringMap; + using cpr::EXPIRES_STRING_SIZE; + using ::CPR_DEFAULT_THREAD_POOL_MAX_IDLE_TIME; + using ::CPR_DEFAULT_THREAD_POOL_MIN_THREAD_NUM; +} + +export namespace std { + using std::to_string; +}