From c048707a421c1d631e03505f5ad24a80f42be9f6 Mon Sep 17 00:00:00 2001 From: Toyosatomimi no Miko <110693261+mikomikotaishi@users.noreply.github.com> Date: Sat, 17 Jan 2026 14:05:52 -0500 Subject: [PATCH 1/9] Add C++ module support --- CMakeLists.txt | 5 + README.md | 1 + include/cpr/accept_encoding.h | 2 +- include/cpr/cookies.h | 2 +- include/cpr/cpr.h | 2 + include/cpr/status_codes.h | 145 ++++++++------- include/cpr/threadpool.h | 4 +- include/cpr/timeout.h | 3 +- include/cpr/unix_socket.h | 3 +- modules/CMakeLists.txt | 27 +++ modules/cpr.cxx | 334 ++++++++++++++++++++++++++++++++++ 11 files changed, 448 insertions(+), 80 deletions(-) create mode 100644 modules/CMakeLists.txt create mode 100644 modules/cpr.cxx 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 5749cad9c..343c9f476 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 68cc2cb19..6e6d09f0e 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..d6a2a5b88 --- /dev/null +++ b/modules/CMakeLists.txt @@ -0,0 +1,27 @@ +cmake_minimum_required(VERSION 3.28) + +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; +} From 6ca8ff2c79747be3cb01e77a74cacbbfbc69a13e Mon Sep 17 00:00:00 2001 From: Toyosatomimi no Miko <110693261+mikomikotaishi@users.noreply.github.com> Date: Sun, 1 Feb 2026 11:20:26 -0500 Subject: [PATCH 2/9] Add modules CI for building the modules --- .github/workflows/modules-ci.yml | 173 +++++++++++++++++++++++++++++++ modules/CMakeLists.txt | 19 ++++ 2 files changed, 192 insertions(+) create mode 100644 .github/workflows/modules-ci.yml 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/modules/CMakeLists.txt b/modules/CMakeLists.txt index d6a2a5b88..a49dfa2db 100644 --- a/modules/CMakeLists.txt +++ b/modules/CMakeLists.txt @@ -1,5 +1,24 @@ 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 From b36ecd89a22ff55a88ae3763a817b446465b3fb8 Mon Sep 17 00:00:00 2001 From: Fabian Sauter Date: Thu, 14 May 2026 13:53:00 +0200 Subject: [PATCH 3/9] Modules raw --- CMakeLists.txt | 98 ++++++---- cmake/cprver.h.in | 13 +- cpr/CMakeLists.txt | 12 +- include/CMakeLists.txt | 1 + include/cpr/accept_encoding.h | 8 +- include/cpr/api.h | 80 ++++---- include/cpr/async.h | 8 +- include/cpr/async_wrapper.h | 10 +- include/cpr/auth.h | 6 +- include/cpr/bearer.h | 4 +- include/cpr/body.h | 4 +- include/cpr/body_view.h | 4 +- include/cpr/buffer.h | 4 +- include/cpr/callback.h | 14 +- include/cpr/cert_info.h | 4 +- include/cpr/connect_timeout.h | 4 +- include/cpr/connection_pool.h | 4 +- include/cpr/cookies.h | 8 +- include/cpr/cpr.h | 2 - include/cpr/cprtypes.h | 18 +- include/cpr/curl_container.h | 8 +- include/cpr/curlholder.h | 4 +- include/cpr/curlmultiholder.h | 4 +- include/cpr/error.h | 8 +- include/cpr/export.h | 8 + include/cpr/file.h | 6 +- include/cpr/http_version.h | 6 +- include/cpr/interceptor.h | 6 +- include/cpr/interface.h | 4 +- include/cpr/limit_rate.h | 4 +- include/cpr/local_port.h | 4 +- include/cpr/local_port_range.h | 4 +- include/cpr/low_speed.h | 4 +- include/cpr/multipart.h | 6 +- include/cpr/multiperform.h | 6 +- include/cpr/parameters.h | 4 +- include/cpr/payload.h | 4 +- include/cpr/proxies.h | 4 +- include/cpr/proxyauth.h | 8 +- include/cpr/range.h | 8 +- include/cpr/redirect.h | 22 ++- include/cpr/reserve_size.h | 4 +- include/cpr/resolve.h | 5 +- include/cpr/response.h | 6 +- include/cpr/secure_string.h | 10 +- include/cpr/session.h | 12 +- include/cpr/sse.h | 8 +- include/cpr/ssl_ctx.h | 4 +- include/cpr/ssl_options.h | 84 +++++---- include/cpr/status_codes.h | 152 +++++++-------- include/cpr/threadpool.h | 8 +- include/cpr/timeout.h | 4 +- include/cpr/unix_socket.h | 4 +- include/cpr/user_agent.h | 4 +- include/cpr/util.h | 32 ++-- include/cpr/verbose.h | 4 +- modules/CMakeLists.txt | 25 +-- modules/cpr.cxx | 331 +-------------------------------- 58 files changed, 472 insertions(+), 663 deletions(-) create mode 100644 include/cpr/export.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 10100d97e..6e400aa10 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,9 +22,9 @@ endif() # Avoid the dll boilerplate code for windows set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) -if (PARENT_CXX_STANDARD) +if(PARENT_CXX_STANDARD) # Don't set CMAKE_CXX_STANDARD if it is already set by parent project - if (PARENT_CXX_STANDARD LESS 17) + if(PARENT_CXX_STANDARD LESS 17) message(FATAL_ERROR "cpr ${cpr_VERSION} does not support ${PARENT_CXX_STANDARD}. Please use cpr <= 1.9.x") endif() else() @@ -39,13 +39,16 @@ set(CPR_LIBRARIES cpr CACHE INTERNAL "") macro(cpr_option OPTION_NAME OPTION_TEXT OPTION_DEFAULT) option(${OPTION_NAME} ${OPTION_TEXT} ${OPTION_DEFAULT}) + if(DEFINED ENV{${OPTION_NAME}}) # Allow overriding the option through an environment variable set(${OPTION_NAME} $ENV{${OPTION_NAME}}) endif() + if(${OPTION_NAME}) add_definitions(-D${OPTION_NAME}) endif() + message(STATUS " ${OPTION_NAME}: ${${OPTION_NAME}}") endmacro() @@ -68,7 +71,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_MODULES "Set to ON to build cpr as a C++ module." ON) 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) @@ -82,8 +85,8 @@ cpr_option(CPR_DEBUG_SANITIZER_FLAG_UB "Enables the UndefinedBehaviorSanitizer f cpr_option(CPR_DEBUG_SANITIZER_FLAG_ALL "Enables all sanitizers for debug builds except the ThreadSanitizer since it is incompatible with the other sanitizers." OFF) message(STATUS "=======================================================") -if (MSVC) - if (BUILD_SHARED_LIBS) +if(MSVC) + if(BUILD_SHARED_LIBS) message(STATUS "Build windows dynamic libs.") else() # Add this to build windows pure static library. @@ -98,7 +101,7 @@ if(CPR_BUILD_VERSION_OUTPUT_ONLY) return() endif() -if (CPR_FORCE_USE_SYSTEM_CURL) +if(CPR_FORCE_USE_SYSTEM_CURL) message(WARNING "The variable CPR_FORCE_USE_SYSTEM_CURL is deprecated, please use CPR_USE_SYSTEM_CURL instead") set(CPR_USE_SYSTEM_CURL ${CPR_FORCE_USE_SYSTEM_CURL}) endif() @@ -122,6 +125,7 @@ if(CPR_ENABLE_CPPCHECK) if(CPR_BUILD_TESTS OR CPR_BUILD_TESTS_SSL) message(FATAL_ERROR "Cppcheck is incompatible with building tests. Make sure to disable CPR_ENABLE_CPPCHECK or disable tests by setting CPR_BUILD_TESTS and CPR_BUILD_TESTS_SSL to OFF. This is because Cppcheck would try to check the google tests source code and then fail. ") endif() + include(cmake/cppcheck.cmake) endif() @@ -135,12 +139,13 @@ if(CPR_ENABLE_SSL) set(DETECT_SSL_BACKEND ON CACHE INTERNAL "" FORCE) endif() - if(CPR_FORCE_WINSSL_BACKEND AND (NOT WIN32)) + if(CPR_FORCE_WINSSL_BACKEND AND(NOT WIN32)) message(FATAL_ERROR "WinSSL is only available on Windows! Use either OpenSSL (CPR_FORCE_OPENSSL_BACKEND) or DarwinSSL (CPR_FORCE_DARWINSSL_BACKEND) instead.") endif() if(DETECT_SSL_BACKEND) message(STATUS "Detecting SSL backend...") + if(WIN32) message(STATUS "SSL auto detect: Using WinSSL.") set(SSL_BACKEND_USED "WinSSL") @@ -150,11 +155,13 @@ if(CPR_ENABLE_SSL) set(SSL_BACKEND_USED "DarwinSSL") else() find_package(OpenSSL) + if(OPENSSL_FOUND) message(STATUS "SSL auto detect: Using OpenSSL.") set(SSL_BACKEND_USED "OpenSSL") else() find_package(MbedTLS) + if(MBEDTLS_FOUND) set(SSL_BACKEND_USED "MbedTLS") else() @@ -165,6 +172,7 @@ if(CPR_ENABLE_SSL) else() if(CPR_FORCE_OPENSSL_BACKEND) find_package(OpenSSL) + if(OPENSSL_FOUND) message(STATUS "Using OpenSSL.") set(SSL_BACKEND_USED "OpenSSL") @@ -187,8 +195,8 @@ if(CPR_ENABLE_SSL) endif() if(SSL_BACKEND_USED STREQUAL "OpenSSL") -# Fix missing OpenSSL includes for Windows since in 'ssl_ctx.cpp' we include OpenSSL directly -find_package(OpenSSL REQUIRED) + # Fix missing OpenSSL includes for Windows since in 'ssl_ctx.cpp' we include OpenSSL directly + find_package(OpenSSL REQUIRED) add_compile_definitions(OPENSSL_BACKEND_USED) endif() @@ -198,15 +206,17 @@ if(CPR_USE_EXISTING_CURL_TARGET) elseif(CPR_USE_SYSTEM_CURL) if(CPR_ENABLE_SSL) find_package(CURL COMPONENTS HTTP HTTPS) + if(CURL_FOUND) message(STATUS "Curl ${CURL_VERSION_STRING} found on this system.") # To be able to load certificates under Windows when using OpenSSL: - if(CMAKE_USE_OPENSSL AND WIN32 AND (NOT (CURL_VERSION_STRING VERSION_GREATER_EQUAL "7.71.0"))) + if(CMAKE_USE_OPENSSL AND WIN32 AND(NOT(CURL_VERSION_STRING VERSION_GREATER_EQUAL "7.71.0"))) message(FATAL_ERROR "Your system curl version (${CURL_VERSION_STRING}) is too old to support OpenSSL on Windows which requires curl >= 7.71.0. Update your curl version, use WinSSL, disable SSL or use the built-in version of curl.") endif() else() find_package(CURL COMPONENTS HTTP) + if(CURL_FOUND) message(FATAL_ERROR "Curl found on this system but WITHOUT HTTPS/SSL support. Either disable SSL by setting CPR_ENABLE_SSL to OFF or use the built-in version of curl by setting CPR_USE_SYSTEM_CURL to OFF.") else() @@ -215,6 +225,7 @@ elseif(CPR_USE_SYSTEM_CURL) endif() else() find_package(CURL COMPONENTS HTTP) + if(CURL_FOUND) message(STATUS "Curl found on this system.") else() @@ -222,8 +233,8 @@ elseif(CPR_USE_SYSTEM_CURL) endif() endif() - # Check for the minimum supported curl version - if(NOT (CURL_VERSION_STRING VERSION_GREATER_EQUAL "7.64.0")) + # Check for the minimum supported curl version + if(NOT(CURL_VERSION_STRING VERSION_GREATER_EQUAL "7.64.0")) message(FATAL_ERROR "Your system curl version (${CURL_VERSION_STRING}) is too old! curl >= 7.64.0 is required. Update your curl version, or use the build in curl version e.g. via `cmake .. -DCPR_USE_SYSTEM_CURL=OFF` during CMake configure.") endif() else() @@ -232,26 +243,28 @@ else() # ZLIB is optional for curl # to disable it: # * from command line: - # -DCURL_ZLIB=OFF + # -DCURL_ZLIB=OFF # * from CMake script: - if (CURL_ZLIB OR CURL_ZLIB STREQUAL AUTO OR NOT DEFINED CACHE{CURL_ZLIB}) + if(CURL_ZLIB OR CURL_ZLIB STREQUAL AUTO OR NOT DEFINED CACHE{CURL_ZLIB}) include(cmake/zlib_external.cmake) endif() - if (CPR_ENABLE_CURL_HTTP_ONLY) + if(CPR_ENABLE_CURL_HTTP_ONLY) # We only need HTTP (and HTTPS) support: set(HTTP_ONLY ON CACHE INTERNAL "" FORCE) endif() + set(BUILD_CURL_EXE OFF CACHE INTERNAL "" FORCE) set(BUILD_TESTING OFF) - if (CURL_VERBOSE_LOGGING) + if(CURL_VERBOSE_LOGGING) message(STATUS "Enabled curl debug features") set(ENABLE_DEBUG ON CACHE INTERNAL "" FORCE) endif() - if (CPR_ENABLE_SSL) + if(CPR_ENABLE_SSL) set(CURL_ENABLE_SSL ON CACHE INTERNAL "" FORCE) + if(ANDROID) set(CURL_CA_PATH "/system/etc/security/cacerts" CACHE INTERNAL "") elseif(CPR_SKIP_CA_BUNDLE_SEARCH) @@ -295,21 +308,23 @@ else() set(CURL_USE_MBEDTLS OFF CACHE INTERNAL "" FORCE) message(STATUS "Disabled curl SSL") endif() + # Disable linting for curl clear_variable(DESTINATION CMAKE_CXX_CLANG_TIDY BACKUP CMAKE_CXX_CLANG_TIDY_BKP) - if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0") + if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0") cmake_policy(SET CMP0135 NEW) endif() # Since curl 8.13, curl depends on lib psl set(CURL_USE_LIBPSL ${CPR_CURL_USE_LIBPSL} CACHE INTERNAL "" FORCE) + if(CPR_CURL_USE_LIBPSL AND NOT CPR_USE_SYSTEM_LIB_PSL) include(libpsl) endif() FetchContent_Declare(curl URL https://github.com/curl/curl/releases/download/curl-8_13_0/curl-8.13.0.tar.xz - URL_HASH SHA256=4a093979a3c2d02de2fbc00549a32771007f2e78032c6faa5ecd2f7a9e152025) # the file hash for curl-8.13.0.tar.xz + URL_HASH SHA256=4a093979a3c2d02de2fbc00549a32771007f2e78032c6faa5ecd2f7a9e152025) # the file hash for curl-8.13.0.tar.xz FetchContent_MakeAvailable(curl) restore_variable(DESTINATION CMAKE_CXX_CLANG_TIDY BACKUP CMAKE_CXX_CLANG_TIDY_BKP) @@ -324,17 +339,15 @@ 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) find_package(GTest) endif() + if(NOT CPR_USE_SYSTEM_GTEST OR NOT GTEST_FOUND) message(STATUS "Not using system gtest, using built-in googletest project instead.") + if(MSVC) # By default, GTest compiles on Windows in CRT static linkage mode. We use this # variable to force it into using the CRT in dynamic linkage (DLL), just as CPR @@ -346,26 +359,25 @@ if(CPR_BUILD_TESTS) clear_variable(DESTINATION CMAKE_CXX_CLANG_TIDY BACKUP CMAKE_CXX_CLANG_TIDY_BKP) FetchContent_Declare(googletest - URL https://github.com/google/googletest/archive/refs/tags/v1.14.0.tar.gz - URL_HASH SHA256=8ad598c73ad796e0d8280b082cebd82a630d73e73cd3c70057938a6501bba5d7 # the file hash for release-1.14.0.tar.gz - USES_TERMINAL_DOWNLOAD TRUE) # <---- This is needed only for Ninja to show download progress + URL https://github.com/google/googletest/archive/refs/tags/v1.14.0.tar.gz + URL_HASH SHA256=8ad598c73ad796e0d8280b082cebd82a630d73e73cd3c70057938a6501bba5d7 # the file hash for release-1.14.0.tar.gz + USES_TERMINAL_DOWNLOAD TRUE) # <---- This is needed only for Ninja to show download progress FetchContent_MakeAvailable(googletest) restore_variable(DESTINATION CMAKE_CXX_CLANG_TIDY BACKUP CMAKE_CXX_CLANG_TIDY_BKP) - + add_library(gtest_int INTERFACE) target_link_libraries(gtest_int INTERFACE gtest) target_include_directories(gtest_int INTERFACE ${googletest_SOURCE_DIR}/include) add_library(GTest::GTest ALIAS gtest_int) - + # Group under the "tests/gtest" project folder in IDEs such as Visual Studio. - set_property(TARGET gtest PROPERTY FOLDER "tests/gtest") - set_property(TARGET gtest_main PROPERTY FOLDER "tests/gtest") + set_property(TARGET gtest PROPERTY FOLDER "tests/gtest") + set_property(TARGET gtest_main PROPERTY FOLDER "tests/gtest") endif() endif() - # Mongoose configuration if(CPR_BUILD_TESTS) message(STATUS "Building mongoose project for test support.") @@ -387,28 +399,30 @@ if(CPR_BUILD_TESTS) # Disable linting for mongoose clear_variable(DESTINATION CMAKE_CXX_CLANG_TIDY BACKUP CMAKE_CXX_CLANG_TIDY_BKP) - FetchContent_Declare(mongoose - URL https://github.com/cesanta/mongoose/archive/7.7.tar.gz - URL_HASH SHA256=4e5733dae31c3a81156af63ca9aa3a6b9b736547f21f23c3ab2f8e3f1ecc16c0 # the hash for 7.7.tar.gz - USES_TERMINAL_DOWNLOAD TRUE # This is needed only for Ninja to show download progress - SOURCE_SUBDIR "?") # Nonexistent directory to prevent FetchContent_MakeAvailable from calling add_subdirectory and duplicating the mongoose target - if (NOT mongoose_POPULATED) + FetchContent_Declare(mongoose + URL https://github.com/cesanta/mongoose/archive/7.7.tar.gz + URL_HASH SHA256=4e5733dae31c3a81156af63ca9aa3a6b9b736547f21f23c3ab2f8e3f1ecc16c0 # the hash for 7.7.tar.gz + USES_TERMINAL_DOWNLOAD TRUE # This is needed only for Ninja to show download progress + SOURCE_SUBDIR "?") # Nonexistent directory to prevent FetchContent_MakeAvailable from calling add_subdirectory and duplicating the mongoose target + + if(NOT mongoose_POPULATED) FetchContent_MakeAvailable(mongoose) file(INSTALL cmake/mongoose.CMakeLists.txt DESTINATION ${mongoose_SOURCE_DIR}) file(RENAME ${mongoose_SOURCE_DIR}/mongoose.CMakeLists.txt ${mongoose_SOURCE_DIR}/CMakeLists.txt) add_subdirectory(${mongoose_SOURCE_DIR} ${mongoose_BINARY_DIR}) - endif() + # Group under the "external" project folder in IDEs such as Visual Studio. set_property(TARGET mongoose PROPERTY FOLDER "external") restore_variable(DESTINATION CMAKE_CXX_CLANG_TIDY BACKUP CMAKE_CXX_CLANG_TIDY_BKP) endif() -if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") +if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") else() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -Werror") - if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + + if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") # Disable C++98 compatibility support in clang: https://github.com/libcpr/cpr/issues/927 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-nonportable-system-include-path -Wno-exit-time-destructors -Wno-undef -Wno-global-constructors -Wno-switch-enum -Wno-old-style-cast -Wno-covered-switch-default -Wno-undefined-func-template") endif() @@ -417,6 +431,10 @@ endif() add_subdirectory(cpr) add_subdirectory(include) +if(CPR_BUILD_MODULES) + add_subdirectory(modules) +endif() + if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND CPR_BUILD_TESTS) # Disable linting for tests since they are currently not up to the standard clear_variable(DESTINATION CMAKE_CXX_CLANG_TIDY BACKUP CMAKE_CXX_CLANG_TIDY_BKP) diff --git a/cmake/cprver.h.in b/cmake/cprver.h.in index e35332497..52ab32fa8 100644 --- a/cmake/cprver.h.in +++ b/cmake/cprver.h.in @@ -1,17 +1,20 @@ #ifndef CPR_CPRVER_H #define CPR_CPRVER_H +#include "cpr/export.h" +#include + /** * CPR version as a string. **/ -#define CPR_VERSION "${cpr_VERSION}" +EXPORT_CPR constexpr std::string CPR_VERSION{"${cpr_VERSION}"}; /** * CPR version split up into parts. **/ -#define CPR_VERSION_MAJOR ${cpr_VERSION_MAJOR} -#define CPR_VERSION_MINOR ${cpr_VERSION_MINOR} -#define CPR_VERSION_PATCH ${cpr_VERSION_PATCH} +EXPORT_CPR constexpr uint8_t CPR_VERSION_MAJOR{${cpr_VERSION_MAJOR}}; +EXPORT_CPR constexpr uint8_t CPR_VERSION_MINOR{${cpr_VERSION_MINOR}}; +EXPORT_CPR constexpr uint8_t CPR_VERSION_PATCH{${cpr_VERSION_PATCH}}; /** * CPR version as a single hex digit. @@ -25,6 +28,6 @@ * '0x010702' -> 01.07.02 -> CPR_VERSION: 1.7.2 * '0xA13722' -> A1.37.22 -> CPR_VERSION: 161.55.34 **/ -#define CPR_VERSION_NUM ${cpr_VERSION_NUM} +EXPORT_CPR constexpr uint64_t CPR_VERSION_NUM{${cpr_VERSION_NUM}}; #endif diff --git a/cpr/CMakeLists.txt b/cpr/CMakeLists.txt index 9f1b303a4..c3a1d04db 100644 --- a/cpr/CMakeLists.txt +++ b/cpr/CMakeLists.txt @@ -69,13 +69,13 @@ if(CPR_USE_SYSTEM_CURL) COMPATIBILITY ExactVersion) if(SSL_BACKEND_USED STREQUAL "OpenSSL") - configure_package_config_file(${PROJECT_SOURCE_DIR}/cmake/cprConfig-ssl.cmake.in - "${PROJECT_BINARY_DIR}/cpr/cprConfig.cmake" - INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/cpr) + configure_package_config_file(${PROJECT_SOURCE_DIR}/cmake/cprConfig-ssl.cmake.in + "${PROJECT_BINARY_DIR}/cpr/cprConfig.cmake" + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/cpr) else() - configure_package_config_file(${PROJECT_SOURCE_DIR}/cmake/cprConfig.cmake.in - "${PROJECT_BINARY_DIR}/cpr/cprConfig.cmake" - INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/cpr) + configure_package_config_file(${PROJECT_SOURCE_DIR}/cmake/cprConfig.cmake.in + "${PROJECT_BINARY_DIR}/cpr/cprConfig.cmake" + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/cpr) endif() if (CPR_ENABLE_INSTALL) diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index 8bc83fba3..6bb38499c 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -23,6 +23,7 @@ target_sources(cpr PRIVATE cpr/curlholder.h cpr/curlholder.h cpr/error.h + cpr/export.h cpr/file.h cpr/limit_rate.h cpr/local_port.h diff --git a/include/cpr/accept_encoding.h b/include/cpr/accept_encoding.h index 549ed3ff4..c91276d99 100644 --- a/include/cpr/accept_encoding.h +++ b/include/cpr/accept_encoding.h @@ -1,6 +1,8 @@ #ifndef CPR_ACCEPT_ENCODING_H #define CPR_ACCEPT_ENCODING_H +#include "cpr/export.h" + #include #include #include @@ -11,7 +13,7 @@ namespace cpr { -enum class AcceptEncodingMethods : uint8_t { +EXPORT_CPR enum class AcceptEncodingMethods : uint8_t { identity, deflate, zlib, @@ -20,9 +22,9 @@ enum class AcceptEncodingMethods : uint8_t { }; // NOLINTNEXTLINE(cert-err58-cpp) -inline const std::map AcceptEncodingMethodsStringMap{{AcceptEncodingMethods::identity, "identity"}, {AcceptEncodingMethods::deflate, "deflate"}, {AcceptEncodingMethods::zlib, "zlib"}, {AcceptEncodingMethods::gzip, "gzip"}, {AcceptEncodingMethods::disabled, "disabled"}}; +EXPORT_CPR inline const std::map AcceptEncodingMethodsStringMap{{AcceptEncodingMethods::identity, "identity"}, {AcceptEncodingMethods::deflate, "deflate"}, {AcceptEncodingMethods::zlib, "zlib"}, {AcceptEncodingMethods::gzip, "gzip"}, {AcceptEncodingMethods::disabled, "disabled"}}; -class AcceptEncoding { +EXPORT_CPR class AcceptEncoding { public: AcceptEncoding() = default; AcceptEncoding(const std::initializer_list& methods); diff --git a/include/cpr/api.h b/include/cpr/api.h index fa700bed1..f9c49ac36 100644 --- a/include/cpr/api.h +++ b/include/cpr/api.h @@ -1,6 +1,8 @@ #ifndef CPR_API_H #define CPR_API_H +#include "cpr/export.h" + #include #include #include @@ -21,7 +23,7 @@ namespace cpr { -using AsyncResponse = AsyncWrapper; +EXPORT_CPR using AsyncResponse = AsyncWrapper; namespace priv { @@ -114,7 +116,7 @@ void setup_multiasync(std::vector>& responses, T&& } // namespace priv // Get methods -template +EXPORT_CPR template Response Get(Ts&&... ts) { Session session; priv::set_option(session, std::forward(ts)...); @@ -122,20 +124,20 @@ Response Get(Ts&&... ts) { } // Get async methods -template +EXPORT_CPR template AsyncResponse GetAsync(Ts... ts) { return cpr::async([](Ts... ts_inner) { return Get(std::move(ts_inner)...); }, std::move(ts)...); } // Get callback methods -template +EXPORT_CPR template // NOLINTNEXTLINE(fuchsia-trailing-return) auto GetCallback(Then then, Ts... ts) { return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Get(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...); } // Post methods -template +EXPORT_CPR template Response Post(Ts&&... ts) { Session session; priv::set_option(session, std::forward(ts)...); @@ -143,20 +145,20 @@ Response Post(Ts&&... ts) { } // Post async methods -template +EXPORT_CPR template AsyncResponse PostAsync(Ts... ts) { return cpr::async([](Ts... ts_inner) { return Post(std::move(ts_inner)...); }, std::move(ts)...); } // Post callback methods -template +EXPORT_CPR template // NOLINTNEXTLINE(fuchsia-trailing-return) auto PostCallback(Then then, Ts... ts) { return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Post(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...); } // Put methods -template +EXPORT_CPR template Response Put(Ts&&... ts) { Session session; priv::set_option(session, std::forward(ts)...); @@ -164,20 +166,20 @@ Response Put(Ts&&... ts) { } // Put async methods -template +EXPORT_CPR template AsyncResponse PutAsync(Ts... ts) { return cpr::async([](Ts... ts_inner) { return Put(std::move(ts_inner)...); }, std::move(ts)...); } // Put callback methods -template +EXPORT_CPR template // NOLINTNEXTLINE(fuchsia-trailing-return) auto PutCallback(Then then, Ts... ts) { return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Put(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...); } // Head methods -template +EXPORT_CPR template Response Head(Ts&&... ts) { Session session; priv::set_option(session, std::forward(ts)...); @@ -185,20 +187,20 @@ Response Head(Ts&&... ts) { } // Head async methods -template +EXPORT_CPR template AsyncResponse HeadAsync(Ts... ts) { return cpr::async([](Ts... ts_inner) { return Head(std::move(ts_inner)...); }, std::move(ts)...); } // Head callback methods -template +EXPORT_CPR template // NOLINTNEXTLINE(fuchsia-trailing-return) auto HeadCallback(Then then, Ts... ts) { return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Head(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...); } // Delete methods -template +EXPORT_CPR template Response Delete(Ts&&... ts) { Session session; priv::set_option(session, std::forward(ts)...); @@ -206,20 +208,20 @@ Response Delete(Ts&&... ts) { } // Delete async methods -template +EXPORT_CPR template AsyncResponse DeleteAsync(Ts... ts) { return cpr::async([](Ts... ts_inner) { return Delete(std::move(ts_inner)...); }, std::move(ts)...); } // Delete callback methods -template +EXPORT_CPR template // NOLINTNEXTLINE(fuchsia-trailing-return) auto DeleteCallback(Then then, Ts... ts) { return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Delete(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...); } // Options methods -template +EXPORT_CPR template Response Options(Ts&&... ts) { Session session; priv::set_option(session, std::forward(ts)...); @@ -227,20 +229,20 @@ Response Options(Ts&&... ts) { } // Options async methods -template +EXPORT_CPR template AsyncResponse OptionsAsync(Ts... ts) { return cpr::async([](Ts... ts_inner) { return Options(std::move(ts_inner)...); }, std::move(ts)...); } // Options callback methods -template +EXPORT_CPR template // NOLINTNEXTLINE(fuchsia-trailing-return) auto OptionsCallback(Then then, Ts... ts) { return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Options(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...); } // Patch methods -template +EXPORT_CPR template Response Patch(Ts&&... ts) { Session session; priv::set_option(session, std::forward(ts)...); @@ -248,20 +250,20 @@ Response Patch(Ts&&... ts) { } // Patch async methods -template +EXPORT_CPR template AsyncResponse PatchAsync(Ts... ts) { return cpr::async([](Ts... ts_inner) { return Patch(std::move(ts_inner)...); }, std::move(ts)...); } // Patch callback methods -template +EXPORT_CPR template // NOLINTNEXTLINE(fuchsia-trailing-return) auto PatchCallback(Then then, Ts... ts) { return cpr::async([](Then then_inner, Ts... ts_inner) { return then_inner(Patch(std::move(ts_inner)...)); }, std::move(then), std::move(ts)...); } // Download methods -template +EXPORT_CPR template Response Download(std::ofstream& file, Ts&&... ts) { Session session; priv::set_option(session, std::forward(ts)...); @@ -269,7 +271,7 @@ Response Download(std::ofstream& file, Ts&&... ts) { } // Download async method -template +EXPORT_CPR template AsyncResponse DownloadAsync(fs::path local_path, Ts... ts) { return AsyncWrapper{std::async( std::launch::async, @@ -281,7 +283,7 @@ AsyncResponse DownloadAsync(fs::path local_path, Ts... ts) { } // Download with user callback -template +EXPORT_CPR template Response Download(const WriteCallback& write, Ts&&... ts) { Session session; priv::set_option(session, std::forward(ts)...); @@ -289,97 +291,97 @@ Response Download(const WriteCallback& write, Ts&&... ts) { } // Multi requests -template +EXPORT_CPR template std::vector MultiGet(Ts&&... ts) { MultiPerform multiperform; priv::setup_multiperform(multiperform, std::forward(ts)...); return multiperform.Get(); } -template +EXPORT_CPR template std::vector MultiDelete(Ts&&... ts) { MultiPerform multiperform; priv::setup_multiperform(multiperform, std::forward(ts)...); return multiperform.Delete(); } -template +EXPORT_CPR template std::vector MultiPut(Ts&&... ts) { MultiPerform multiperform; priv::setup_multiperform(multiperform, std::forward(ts)...); return multiperform.Put(); } -template +EXPORT_CPR template std::vector MultiHead(Ts&&... ts) { MultiPerform multiperform; priv::setup_multiperform(multiperform, std::forward(ts)...); return multiperform.Head(); } -template +EXPORT_CPR template std::vector MultiOptions(Ts&&... ts) { MultiPerform multiperform; priv::setup_multiperform(multiperform, std::forward(ts)...); return multiperform.Options(); } -template +EXPORT_CPR template std::vector MultiPatch(Ts&&... ts) { MultiPerform multiperform; priv::setup_multiperform(multiperform, std::forward(ts)...); return multiperform.Patch(); } -template +EXPORT_CPR template std::vector MultiPost(Ts&&... ts) { MultiPerform multiperform; priv::setup_multiperform(multiperform, std::forward(ts)...); return multiperform.Post(); } -template +EXPORT_CPR template std::vector> MultiGetAsync(Ts&&... ts) { std::vector> ret{}; priv::setup_multiasync<&cpr::Session::Get>(ret, std::forward(ts)...); return ret; } -template +EXPORT_CPR template std::vector> MultiDeleteAsync(Ts&&... ts) { std::vector> ret{}; priv::setup_multiasync<&cpr::Session::Delete>(ret, std::forward(ts)...); return ret; } -template +EXPORT_CPR template std::vector> MultiHeadAsync(Ts&&... ts) { std::vector> ret{}; priv::setup_multiasync<&cpr::Session::Head>(ret, std::forward(ts)...); return ret; } -template +EXPORT_CPR template std::vector> MultiOptionsAsync(Ts&&... ts) { std::vector> ret{}; priv::setup_multiasync<&cpr::Session::Options>(ret, std::forward(ts)...); return ret; } -template +EXPORT_CPR template std::vector> MultiPatchAsync(Ts&&... ts) { std::vector> ret{}; priv::setup_multiasync<&cpr::Session::Patch>(ret, std::forward(ts)...); return ret; } -template +EXPORT_CPR template std::vector> MultiPostAsync(Ts&&... ts) { std::vector> ret{}; priv::setup_multiasync<&cpr::Session::Post>(ret, std::forward(ts)...); return ret; } -template +EXPORT_CPR template std::vector> MultiPutAsync(Ts&&... ts) { std::vector> ret{}; priv::setup_multiasync<&cpr::Session::Put>(ret, std::forward(ts)...); diff --git a/include/cpr/async.h b/include/cpr/async.h index 01c29454a..43b4844fa 100644 --- a/include/cpr/async.h +++ b/include/cpr/async.h @@ -1,13 +1,15 @@ #ifndef CPR_ASYNC_H #define CPR_ASYNC_H +#include "cpr/export.h" + #include "async_wrapper.h" #include "singleton.h" #include "threadpool.h" namespace cpr { -class GlobalThreadPool : public ThreadPool { +EXPORT_CPR class GlobalThreadPool : public ThreadPool { CPR_SINGLETON_DECL(GlobalThreadPool) protected: GlobalThreadPool() = default; @@ -22,7 +24,7 @@ class GlobalThreadPool : public ThreadPool { * async(std::bind(&Class::mem_fn, &obj)) * async(std::mem_fn(&Class::mem_fn, &obj)) **/ -template +EXPORT_CPR template auto async(Fn&& fn, Args&&... args) { std::future future = GlobalThreadPool::GetInstance()->Submit(std::forward(fn), std::forward(args)...); using async_wrapper_t = AsyncWrapper; @@ -33,7 +35,7 @@ auto async(Fn&& fn, Args&&... args) { } } -class async { +EXPORT_CPR class async { public: static void startup(size_t min_threads = CPR_DEFAULT_THREAD_POOL_MIN_THREAD_NUM, size_t max_threads = CPR_DEFAULT_THREAD_POOL_MAX_THREAD_NUM, std::chrono::milliseconds max_idle_ms = CPR_DEFAULT_THREAD_POOL_MAX_IDLE_TIME) { GlobalThreadPool* gtp = GlobalThreadPool::GetInstance(); diff --git a/include/cpr/async_wrapper.h b/include/cpr/async_wrapper.h index c90ea06c6..eb5e145aa 100644 --- a/include/cpr/async_wrapper.h +++ b/include/cpr/async_wrapper.h @@ -1,12 +1,14 @@ #ifndef CPR_ASYNC_WRAPPER_H #define CPR_ASYNC_WRAPPER_H +#include "cpr/export.h" + #include #include #include namespace cpr { -enum class [[nodiscard]] CancellationResult : uint8_t { failure, success, invalid_operation }; +EXPORT_CPR enum class [[nodiscard]] CancellationResult : uint8_t { failure, success, invalid_operation }; /** * A class template intended to wrap results of async operations (instances of std::future) @@ -14,7 +16,7 @@ enum class [[nodiscard]] CancellationResult : uint8_t { failure, success, invali * * The RAII semantics are the same as std::future - moveable, not copyable. */ -template +EXPORT_CPR template class AsyncWrapper; template @@ -149,10 +151,10 @@ class AsyncWrapper : public AsyncWrapper { }; // Deduction guides -template +EXPORT_CPR template AsyncWrapper(std::future&&) -> AsyncWrapper; -template +EXPORT_CPR template AsyncWrapper(std::future&&, std::shared_ptr&&) -> AsyncWrapper; } // namespace cpr diff --git a/include/cpr/auth.h b/include/cpr/auth.h index 166d1850e..03e782272 100644 --- a/include/cpr/auth.h +++ b/include/cpr/auth.h @@ -1,6 +1,8 @@ #ifndef CPR_AUTH_H #define CPR_AUTH_H +#include "cpr/export.h" + #include #include #include @@ -9,9 +11,9 @@ namespace cpr { -enum class AuthMode : uint8_t { BASIC, DIGEST, NTLM, NEGOTIATE, ANY, ANYSAFE }; +EXPORT_CPR enum class AuthMode : uint8_t { BASIC, DIGEST, NTLM, NEGOTIATE, ANY, ANYSAFE }; -class Authentication { +EXPORT_CPR class Authentication { public: Authentication(std::string_view username, std::string_view password, AuthMode auth_mode); diff --git a/include/cpr/bearer.h b/include/cpr/bearer.h index 1f448da0c..6d7211bd3 100644 --- a/include/cpr/bearer.h +++ b/include/cpr/bearer.h @@ -1,6 +1,8 @@ #ifndef CPR_BEARER_H #define CPR_BEARER_H +#include "cpr/export.h" + #include #include @@ -13,7 +15,7 @@ namespace cpr { // Only supported with libcurl >= 7.61.0. // As an alternative use SetHeader and add the token manually. #if LIBCURL_VERSION_NUM >= 0x073D00 -class Bearer { +EXPORT_CPR class Bearer { public: Bearer(std::string_view token) : token_string_{token} {} Bearer(const Bearer& other) = default; diff --git a/include/cpr/body.h b/include/cpr/body.h index 8febe3dcd..6fac5dea6 100644 --- a/include/cpr/body.h +++ b/include/cpr/body.h @@ -1,6 +1,8 @@ #ifndef CPR_BODY_H #define CPR_BODY_H +#include "cpr/export.h" + #include #include #include @@ -12,7 +14,7 @@ namespace cpr { -class Body : public StringHolder { +EXPORT_CPR class Body : public StringHolder { public: Body() = default; Body(std::string body) : StringHolder(std::move(body)) {} diff --git a/include/cpr/body_view.h b/include/cpr/body_view.h index 20bd6f366..18bf9f780 100644 --- a/include/cpr/body_view.h +++ b/include/cpr/body_view.h @@ -1,13 +1,15 @@ #ifndef CPR_BODY_VIEW_H #define CPR_BODY_VIEW_H +#include "cpr/export.h" + #include #include "cpr/buffer.h" namespace cpr { -class BodyView final { +EXPORT_CPR class BodyView final { public: BodyView() = default; BodyView(std::string_view body) : m_body(body) {} diff --git a/include/cpr/buffer.h b/include/cpr/buffer.h index 04a3e2bdc..354db1352 100644 --- a/include/cpr/buffer.h +++ b/include/cpr/buffer.h @@ -1,13 +1,15 @@ #ifndef CPR_BUFFER_H #define CPR_BUFFER_H +#include "cpr/export.h" + #include #include "cpr/filesystem.h" namespace cpr { -struct Buffer { +EXPORT_CPR struct Buffer { using data_t = const char*; template diff --git a/include/cpr/callback.h b/include/cpr/callback.h index 64775f0be..cade08722 100644 --- a/include/cpr/callback.h +++ b/include/cpr/callback.h @@ -1,6 +1,8 @@ #ifndef CPR_CALLBACK_H #define CPR_CALLBACK_H +#include "cpr/export.h" + #include "cprtypes.h" #include @@ -12,7 +14,7 @@ namespace cpr { -class ReadCallback { +EXPORT_CPR class ReadCallback { public: ReadCallback() = default; ReadCallback(std::function p_callback, intptr_t p_userdata = 0) : userdata(p_userdata), size{-1}, callback{std::move(p_callback)} {} @@ -29,7 +31,7 @@ class ReadCallback { std::function callback; }; -class HeaderCallback { +EXPORT_CPR class HeaderCallback { public: HeaderCallback() = default; HeaderCallback(std::function p_callback, intptr_t p_userdata = 0) : userdata(p_userdata), callback(std::move(p_callback)) {} @@ -44,7 +46,7 @@ class HeaderCallback { std::function callback; }; -class WriteCallback { +EXPORT_CPR class WriteCallback { public: WriteCallback() = default; WriteCallback(std::function p_callback, intptr_t p_userdata = 0) : userdata(p_userdata), callback(std::move(p_callback)) {} @@ -59,7 +61,7 @@ class WriteCallback { std::function callback; }; -class ProgressCallback { +EXPORT_CPR class ProgressCallback { public: ProgressCallback() = default; ProgressCallback(std::function p_callback, intptr_t p_userdata = 0) : userdata(p_userdata), callback(std::move(p_callback)) {} @@ -74,7 +76,7 @@ class ProgressCallback { std::function callback; }; -class DebugCallback { +EXPORT_CPR class DebugCallback { public: enum class InfoType : uint8_t { TEXT = 0, @@ -101,7 +103,7 @@ class DebugCallback { /** * Functor class for progress functions that will be used in cancellable requests. */ -class CancellationCallback { +EXPORT_CPR class CancellationCallback { public: CancellationCallback() = default; explicit CancellationCallback(std::shared_ptr&& cs) : cancellation_state{std::move(cs)} {} diff --git a/include/cpr/cert_info.h b/include/cpr/cert_info.h index 62182a5b0..dcfb1b960 100644 --- a/include/cpr/cert_info.h +++ b/include/cpr/cert_info.h @@ -1,13 +1,15 @@ #ifndef CPR_CERT_INFO_H #define CPR_CERT_INFO_H +#include "cpr/export.h" + #include #include #include namespace cpr { -class CertInfo { +EXPORT_CPR class CertInfo { private: std::vector cert_info_; diff --git a/include/cpr/connect_timeout.h b/include/cpr/connect_timeout.h index d608b98d0..a8008cc42 100644 --- a/include/cpr/connect_timeout.h +++ b/include/cpr/connect_timeout.h @@ -1,11 +1,13 @@ #ifndef CPR_CONNECT_TIMEOUT_H #define CPR_CONNECT_TIMEOUT_H +#include "cpr/export.h" + #include "cpr/timeout.h" namespace cpr { -class ConnectTimeout : public Timeout { +EXPORT_CPR class ConnectTimeout : public Timeout { public: ConnectTimeout(const std::chrono::milliseconds& duration) : Timeout{duration} {} ConnectTimeout(const std::int32_t& milliseconds) : Timeout{milliseconds} {} diff --git a/include/cpr/connection_pool.h b/include/cpr/connection_pool.h index fc75d2767..fc5f07592 100644 --- a/include/cpr/connection_pool.h +++ b/include/cpr/connection_pool.h @@ -1,6 +1,8 @@ #ifndef CPR_CONNECTION_POOL_H #define CPR_CONNECTION_POOL_H +#include "cpr/export.h" + #include #include #include @@ -28,7 +30,7 @@ namespace cpr { * auto future2 = cpr::GetAsync(cpr::Url{"http://example.com/api/more"}, pool); * ``` **/ -class ConnectionPool { +EXPORT_CPR class ConnectionPool { public: /** * Creates a new connection pool with shared connection state. diff --git a/include/cpr/cookies.h b/include/cpr/cookies.h index 6e6d09f0e..9c664f402 100644 --- a/include/cpr/cookies.h +++ b/include/cpr/cookies.h @@ -1,6 +1,8 @@ #ifndef CPR_COOKIES_H #define CPR_COOKIES_H +#include "cpr/export.h" + #include "cpr/curlholder.h" #include #include @@ -12,9 +14,9 @@ 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. **/ -inline const std::size_t EXPIRES_STRING_SIZE = 100; +EXPORT_CPR inline const std::size_t EXPIRES_STRING_SIZE = 100; -class Cookie { +EXPORT_CPR class Cookie { public: Cookie() = default; /** @@ -45,7 +47,7 @@ class Cookie { std::chrono::system_clock::time_point expires_; }; -class Cookies { +EXPORT_CPR class Cookies { public: /** * Should we URL-encode cookies when making a request. diff --git a/include/cpr/cpr.h b/include/cpr/cpr.h index d72aa62b5..a42058fbd 100644 --- a/include/cpr/cpr.h +++ b/include/cpr/cpr.h @@ -10,9 +10,7 @@ #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/cprtypes.h b/include/cpr/cprtypes.h index 20a86ded5..70f83ab47 100644 --- a/include/cpr/cprtypes.h +++ b/include/cpr/cprtypes.h @@ -1,6 +1,8 @@ #ifndef CPR_CPRTYPES_H #define CPR_CPRTYPES_H +#include "cpr/export.h" + #include #include #include @@ -14,18 +16,18 @@ namespace cpr { /** * Wrapper around "curl_off_t" to prevent applications from having to link against libcurl. **/ -using cpr_off_t = curl_off_t; +EXPORT_CPR using cpr_off_t = curl_off_t; /** * The argument type for progress functions, dependent on libcurl version **/ #if LIBCURL_VERSION_NUM < 0x072000 -using cpr_pf_arg_t = double; +EXPORT_CPR using cpr_pf_arg_t = double; #else -using cpr_pf_arg_t = cpr_off_t; +EXPORT_CPR using cpr_pf_arg_t = cpr_off_t; #endif -template +EXPORT_CPR template class StringHolder { public: private: @@ -139,13 +141,13 @@ class StringHolder { friend T; }; -template +EXPORT_CPR template std::ostream& operator<<(std::ostream& os, const StringHolder& s) { os << s.str(); return os; } -class Url : public StringHolder { +EXPORT_CPR class Url : public StringHolder { public: Url() = default; Url(std::string url) : StringHolder(std::move(url)) {} @@ -161,11 +163,11 @@ class Url : public StringHolder { Url& operator=(const Url& other) = default; }; -struct CaseInsensitiveCompare { +EXPORT_CPR struct CaseInsensitiveCompare { bool operator()(const std::string& a, const std::string& b) const noexcept; }; -using Header = std::map; +EXPORT_CPR using Header = std::map; } // namespace cpr diff --git a/include/cpr/curl_container.h b/include/cpr/curl_container.h index 1be9e62ae..e6b7a2755 100644 --- a/include/cpr/curl_container.h +++ b/include/cpr/curl_container.h @@ -1,6 +1,8 @@ #ifndef CPR_CURL_CONTAINER_H #define CPR_CURL_CONTAINER_H +#include "cpr/export.h" + #include #include #include @@ -11,14 +13,14 @@ namespace cpr { -struct Parameter { +EXPORT_CPR struct Parameter { Parameter(std::string p_key, std::string p_value) : key{std::move(p_key)}, value{std::move(p_value)} {} std::string key; std::string value; }; -struct Pair { +EXPORT_CPR struct Pair { Pair(std::string p_key, std::string p_value) : key(std::move(p_key)), value(std::move(p_value)) {} std::string key; @@ -26,7 +28,7 @@ struct Pair { }; -template +EXPORT_CPR template class CurlContainer { public: /** diff --git a/include/cpr/curlholder.h b/include/cpr/curlholder.h index 35a3a8490..e1f8635cc 100644 --- a/include/cpr/curlholder.h +++ b/include/cpr/curlholder.h @@ -1,6 +1,8 @@ #ifndef CPR_CURLHOLDER_H #define CPR_CURLHOLDER_H +#include "cpr/export.h" + #include #include #include @@ -9,7 +11,7 @@ namespace cpr { -struct CurlHolder { +EXPORT_CPR struct CurlHolder { private: /** * Mutex for curl_easy_init(). diff --git a/include/cpr/curlmultiholder.h b/include/cpr/curlmultiholder.h index 401df0eb6..7c3d21cce 100644 --- a/include/cpr/curlmultiholder.h +++ b/include/cpr/curlmultiholder.h @@ -1,11 +1,13 @@ #ifndef CPR_CURLMULTIHOLDER_H #define CPR_CURLMULTIHOLDER_H +#include "cpr/export.h" + #include namespace cpr { -class CurlMultiHolder { +EXPORT_CPR class CurlMultiHolder { public: CurlMultiHolder(); ~CurlMultiHolder(); diff --git a/include/cpr/error.h b/include/cpr/error.h index 5cf7e6b9e..826b8d537 100644 --- a/include/cpr/error.h +++ b/include/cpr/error.h @@ -1,6 +1,8 @@ #ifndef CPR_ERROR_H #define CPR_ERROR_H +#include "cpr/export.h" + #include #include #include @@ -14,7 +16,7 @@ namespace cpr { * cpr error codes that match the ones found inside 'curl.h'. * These error codes only include relevant error codes meaning no support for e.g. FTP errors since cpr does only support HTTP. **/ -enum class ErrorCode : uint16_t { +EXPORT_CPR enum class ErrorCode : uint16_t { /** * Everything is good and no error occurred. **/ @@ -90,7 +92,7 @@ enum class ErrorCode : uint16_t { UNKNOWN_ERROR = 1000, }; -inline const std::unordered_map& get_error_code_to_string_mapping() { +EXPORT_CPR inline const std::unordered_map& get_error_code_to_string_mapping() { // Use a function-local static rather than inline global objects to avoid the 'double-destructor' problem in MSVC when using /MT flags. static const std::unordered_map mapping = {{ErrorCode::OK, "OK"}, {ErrorCode::UNSUPPORTED_PROTOCOL, "UNSUPPORTED_PROTOCOL"}, @@ -159,7 +161,7 @@ inline const std::unordered_map& get_error_code_to_strin return mapping; } -class Error { +EXPORT_CPR class Error { public: ErrorCode code = ErrorCode::OK; std::string message; diff --git a/include/cpr/export.h b/include/cpr/export.h new file mode 100644 index 000000000..33694838d --- /dev/null +++ b/include/cpr/export.h @@ -0,0 +1,8 @@ +#ifndef CPR_EXPORT_H +#define CPR_EXPORT_H + +#ifndef EXPORT_CPR +#define EXPORT_CPR +#endif + +#endif diff --git a/include/cpr/file.h b/include/cpr/file.h index 7eefcfdc3..a8e808de2 100644 --- a/include/cpr/file.h +++ b/include/cpr/file.h @@ -1,6 +1,8 @@ #ifndef CPR_FILE_H #define CPR_FILE_H +#include "cpr/export.h" + #include #include #include @@ -9,7 +11,7 @@ namespace cpr { -struct File { +EXPORT_CPR struct File { explicit File(std::string p_filepath, const std::string& p_overriden_filename = {}) : filepath(std::move(p_filepath)), overriden_filename(p_overriden_filename) {} std::string filepath; @@ -20,7 +22,7 @@ struct File { } }; -class Files { +EXPORT_CPR class Files { public: Files() = default; Files(const File& p_file) : files{p_file} {} diff --git a/include/cpr/http_version.h b/include/cpr/http_version.h index 39b9512f4..ec10c985e 100644 --- a/include/cpr/http_version.h +++ b/include/cpr/http_version.h @@ -1,11 +1,13 @@ #ifndef CPR_HTTP_VERSION_H #define CPR_HTTP_VERSION_H +#include "cpr/export.h" + #include #include namespace cpr { -enum class HttpVersionCode : uint8_t { +EXPORT_CPR enum class HttpVersionCode : uint8_t { /** * Let libcurl decide which version is the best. **/ @@ -58,7 +60,7 @@ enum class HttpVersionCode : uint8_t { #endif }; -class HttpVersion { +EXPORT_CPR class HttpVersion { public: /** * The HTTP version that should be used by libcurl when initiating a HTTP(S) connection. diff --git a/include/cpr/interceptor.h b/include/cpr/interceptor.h index 4bef2f31f..700f6ff9d 100644 --- a/include/cpr/interceptor.h +++ b/include/cpr/interceptor.h @@ -1,13 +1,15 @@ #ifndef CPR_INTERCEPTOR_H #define CPR_INTERCEPTOR_H +#include "cpr/export.h" + #include "cpr/multiperform.h" #include "cpr/response.h" #include "cpr/session.h" #include namespace cpr { -class Interceptor { +EXPORT_CPR class Interceptor { public: enum class ProceedHttpMethod : uint8_t { GET_REQUEST = 0, @@ -38,7 +40,7 @@ class Interceptor { static Response proceed(Session& session, ProceedHttpMethod httpMethod, const WriteCallback& write); }; -class InterceptorMulti { +EXPORT_CPR class InterceptorMulti { public: enum class ProceedHttpMethod : uint8_t { GET_REQUEST = 0, diff --git a/include/cpr/interface.h b/include/cpr/interface.h index 115dc912b..615044ff9 100644 --- a/include/cpr/interface.h +++ b/include/cpr/interface.h @@ -1,6 +1,8 @@ #ifndef CPR_INTERFACE_H #define CPR_INTERFACE_H +#include "cpr/export.h" + #include #include @@ -8,7 +10,7 @@ namespace cpr { -class Interface : public StringHolder { +EXPORT_CPR class Interface : public StringHolder { public: Interface() = default; Interface(std::string iface) : StringHolder(std::move(iface)) {} diff --git a/include/cpr/limit_rate.h b/include/cpr/limit_rate.h index ac3c049e1..3da868ab6 100644 --- a/include/cpr/limit_rate.h +++ b/include/cpr/limit_rate.h @@ -1,11 +1,13 @@ #ifndef CPR_LIMIT_RATE_H #define CPR_LIMIT_RATE_H +#include "cpr/export.h" + #include namespace cpr { -class LimitRate { +EXPORT_CPR class LimitRate { public: LimitRate(const std::int64_t p_downrate, const std::int64_t p_uprate) : downrate(p_downrate), uprate(p_uprate) {} diff --git a/include/cpr/local_port.h b/include/cpr/local_port.h index 12cee9ec5..e8a6492bb 100644 --- a/include/cpr/local_port.h +++ b/include/cpr/local_port.h @@ -1,11 +1,13 @@ #ifndef CPR_LOCAL_PORT_H #define CPR_LOCAL_PORT_H +#include "cpr/export.h" + #include namespace cpr { -class LocalPort { +EXPORT_CPR class LocalPort { public: LocalPort(const std::uint16_t p_localport) : localport_(p_localport) {} diff --git a/include/cpr/local_port_range.h b/include/cpr/local_port_range.h index 6a7fa964d..372336787 100644 --- a/include/cpr/local_port_range.h +++ b/include/cpr/local_port_range.h @@ -1,11 +1,13 @@ #ifndef CPR_LOCAL_PORT_RANGE_H #define CPR_LOCAL_PORT_RANGE_H +#include "cpr/export.h" + #include namespace cpr { -class LocalPortRange { +EXPORT_CPR class LocalPortRange { public: LocalPortRange(const std::uint16_t p_localportrange) : localportrange_(p_localportrange) {} diff --git a/include/cpr/low_speed.h b/include/cpr/low_speed.h index c74ceceb5..5dac5f106 100644 --- a/include/cpr/low_speed.h +++ b/include/cpr/low_speed.h @@ -1,12 +1,14 @@ #ifndef CPR_LOW_SPEED_H #define CPR_LOW_SPEED_H +#include "cpr/export.h" + #include #include namespace cpr { -class LowSpeed { +EXPORT_CPR class LowSpeed { public: [[deprecated("Will be removed in CPR 2.x - Use the constructor with std::chrono::seconds instead of std::int32_t")]] LowSpeed(const std::int32_t p_limit, const std::int32_t p_time) diff --git a/include/cpr/multipart.h b/include/cpr/multipart.h index 991764243..f4189dfb5 100644 --- a/include/cpr/multipart.h +++ b/include/cpr/multipart.h @@ -1,6 +1,8 @@ #ifndef CPR_MULTIPART_H #define CPR_MULTIPART_H +#include "cpr/export.h" + #include #include #include @@ -12,7 +14,7 @@ namespace cpr { -struct Part { +EXPORT_CPR struct Part { Part(const std::string& p_name, const std::string& p_value, const std::string& p_content_type = {}) : name{p_name}, value{p_value}, content_type{p_content_type}, is_file{false}, is_buffer{false} {} Part(const std::string& p_name, const std::int32_t& p_value, const std::string& p_content_type = {}) : name{p_name}, value{std::to_string(p_value)}, content_type{p_content_type}, is_file{false}, is_buffer{false} {} Part(const std::string& p_name, const Files& p_files, const std::string& p_content_type = {}) : name{p_name}, content_type{p_content_type}, is_file{true}, is_buffer{false}, files{p_files} {} @@ -31,7 +33,7 @@ struct Part { Files files; }; -class Multipart { +EXPORT_CPR class Multipart { public: Multipart(const std::initializer_list& parts); explicit Multipart(const std::vector& parts); diff --git a/include/cpr/multiperform.h b/include/cpr/multiperform.h index e4ca75f92..c6c1729f9 100644 --- a/include/cpr/multiperform.h +++ b/include/cpr/multiperform.h @@ -1,6 +1,8 @@ #ifndef CPR_MULTIPERFORM_H #define CPR_MULTIPERFORM_H +#include "cpr/export.h" + #include "cpr/curlmultiholder.h" #include "cpr/response.h" #include "cpr/session.h" @@ -12,9 +14,9 @@ namespace cpr { -class InterceptorMulti; +EXPORT_CPR class InterceptorMulti; -class MultiPerform { +EXPORT_CPR class MultiPerform { public: enum class HttpMethod : uint8_t { UNDEFINED = 0, diff --git a/include/cpr/parameters.h b/include/cpr/parameters.h index 620962778..5f2ae1f95 100644 --- a/include/cpr/parameters.h +++ b/include/cpr/parameters.h @@ -1,13 +1,15 @@ #ifndef CPR_PARAMETERS_H #define CPR_PARAMETERS_H +#include "cpr/export.h" + #include #include "cpr/curl_container.h" namespace cpr { -class Parameters : public CurlContainer { +EXPORT_CPR class Parameters : public CurlContainer { public: Parameters() = default; Parameters(const std::initializer_list& parameters) : CurlContainer(parameters) {} diff --git a/include/cpr/payload.h b/include/cpr/payload.h index 0741a88fa..c657462c2 100644 --- a/include/cpr/payload.h +++ b/include/cpr/payload.h @@ -1,13 +1,15 @@ #ifndef CPR_PAYLOAD_H #define CPR_PAYLOAD_H +#include "cpr/export.h" + #include #include "cpr/curl_container.h" namespace cpr { -class Payload : public CurlContainer { +EXPORT_CPR class Payload : public CurlContainer { public: template Payload(const It begin, const It end) { diff --git a/include/cpr/proxies.h b/include/cpr/proxies.h index 60108af7f..80a57f917 100644 --- a/include/cpr/proxies.h +++ b/include/cpr/proxies.h @@ -1,12 +1,14 @@ #ifndef CPR_PROXIES_H #define CPR_PROXIES_H +#include "cpr/export.h" + #include #include #include namespace cpr { -class Proxies { +EXPORT_CPR class Proxies { public: Proxies() = default; Proxies(const std::initializer_list>& hosts); diff --git a/include/cpr/proxyauth.h b/include/cpr/proxyauth.h index 6a00c920e..295504f57 100644 --- a/include/cpr/proxyauth.h +++ b/include/cpr/proxyauth.h @@ -1,6 +1,8 @@ #ifndef CPR_PROXYAUTH_H #define CPR_PROXYAUTH_H +#include "cpr/export.h" + #include #include #include @@ -10,9 +12,9 @@ #include "cpr/util.h" namespace cpr { -class ProxyAuthentication; +EXPORT_CPR class ProxyAuthentication; -class EncodedAuthentication { +EXPORT_CPR class EncodedAuthentication { friend ProxyAuthentication; public: @@ -35,7 +37,7 @@ class EncodedAuthentication { util::SecureString password; }; -class ProxyAuthentication { +EXPORT_CPR class ProxyAuthentication { public: ProxyAuthentication() = default; ProxyAuthentication(const std::initializer_list>& auths) : proxyAuth_{auths} {} diff --git a/include/cpr/range.h b/include/cpr/range.h index c6ab6901a..721bcf42b 100644 --- a/include/cpr/range.h +++ b/include/cpr/range.h @@ -1,12 +1,16 @@ #ifndef CPR_RANGE_H #define CPR_RANGE_H +#include "cpr/export.h" + #include #include +#include +#include namespace cpr { -class Range { +EXPORT_CPR class Range { public: explicit Range(const std::optional p_resume_from = std::nullopt, const std::optional p_finish_at = std::nullopt) { resume_from = p_resume_from.value_or(0); @@ -23,7 +27,7 @@ class Range { } }; -class MultiRange { +EXPORT_CPR class MultiRange { public: MultiRange(std::initializer_list rs) : ranges{rs} {} diff --git a/include/cpr/redirect.h b/include/cpr/redirect.h index c3f24d3ad..16cdc30ff 100644 --- a/include/cpr/redirect.h +++ b/include/cpr/redirect.h @@ -1,10 +1,12 @@ #ifndef CPR_REDIRECT_H #define CPR_REDIRECT_H +#include "cpr/export.h" + #include namespace cpr { -enum class PostRedirectFlags : uint8_t { +EXPORT_CPR enum class PostRedirectFlags : uint8_t { /** * Respect RFC 7231 (section 6.4.2 to 6.4.4). * Same as CURL_REDIR_POST_301 (https://curl.se/libcurl/c/CURLOPT_POSTREDIR.html). @@ -32,16 +34,16 @@ enum class PostRedirectFlags : uint8_t { NONE = 0x0 }; -PostRedirectFlags operator|(PostRedirectFlags lhs, PostRedirectFlags rhs); -PostRedirectFlags operator&(PostRedirectFlags lhs, PostRedirectFlags rhs); -PostRedirectFlags operator^(PostRedirectFlags lhs, PostRedirectFlags rhs); -PostRedirectFlags operator~(PostRedirectFlags flag); -PostRedirectFlags& operator|=(PostRedirectFlags& lhs, PostRedirectFlags rhs); -PostRedirectFlags& operator&=(PostRedirectFlags& lhs, PostRedirectFlags rhs); -PostRedirectFlags& operator^=(PostRedirectFlags& lhs, PostRedirectFlags rhs); -bool any(PostRedirectFlags flag); +EXPORT_CPR PostRedirectFlags operator|(PostRedirectFlags lhs, PostRedirectFlags rhs); +EXPORT_CPR PostRedirectFlags operator&(PostRedirectFlags lhs, PostRedirectFlags rhs); +EXPORT_CPR PostRedirectFlags operator^(PostRedirectFlags lhs, PostRedirectFlags rhs); +EXPORT_CPR PostRedirectFlags operator~(PostRedirectFlags flag); +EXPORT_CPR PostRedirectFlags& operator|=(PostRedirectFlags& lhs, PostRedirectFlags rhs); +EXPORT_CPR PostRedirectFlags& operator&=(PostRedirectFlags& lhs, PostRedirectFlags rhs); +EXPORT_CPR PostRedirectFlags& operator^=(PostRedirectFlags& lhs, PostRedirectFlags rhs); +EXPORT_CPR bool any(PostRedirectFlags flag); -class Redirect { +EXPORT_CPR class Redirect { public: /** * The maximum number of redirects to follow. diff --git a/include/cpr/reserve_size.h b/include/cpr/reserve_size.h index 93bb31e86..1706d542f 100644 --- a/include/cpr/reserve_size.h +++ b/include/cpr/reserve_size.h @@ -1,11 +1,13 @@ #ifndef CPR_RESERVE_SIZE_H #define CPR_RESERVE_SIZE_H +#include "cpr/export.h" + #include namespace cpr { -class ReserveSize { +EXPORT_CPR class ReserveSize { public: ReserveSize(const std::size_t _size) : size(_size) {} diff --git a/include/cpr/resolve.h b/include/cpr/resolve.h index 6f0e52c16..6ba2c4ea2 100644 --- a/include/cpr/resolve.h +++ b/include/cpr/resolve.h @@ -1,11 +1,14 @@ #ifndef CPR_RESOLVE_H #define CPR_RESOLVE_H +#include "cpr/export.h" + +#include #include #include namespace cpr { -class Resolve { +EXPORT_CPR class Resolve { public: std::string host; std::string addr; diff --git a/include/cpr/response.h b/include/cpr/response.h index 1f85b3576..7d961d12e 100644 --- a/include/cpr/response.h +++ b/include/cpr/response.h @@ -1,6 +1,8 @@ #ifndef CPR_RESPONSE_H #define CPR_RESPONSE_H +#include "cpr/export.h" + #include #include #include @@ -17,9 +19,9 @@ namespace cpr { -class MultiPerform; +EXPORT_CPR class MultiPerform; -class Response { +EXPORT_CPR class Response { private: friend MultiPerform; std::shared_ptr curl_{nullptr}; diff --git a/include/cpr/secure_string.h b/include/cpr/secure_string.h index 35a6cbb4b..bc2013286 100644 --- a/include/cpr/secure_string.h +++ b/include/cpr/secure_string.h @@ -1,6 +1,8 @@ #ifndef CPR_SECURE_STRING_H #define CPR_SECURE_STRING_H +#include "cpr/export.h" + #include #include #include @@ -10,7 +12,7 @@ namespace cpr::util { // This is an allocator that overwrites memory with zero values before // deallocating the memory, so as to not leave secrets in unallocated memory // sections. -template +EXPORT_CPR template struct SecureAllocator : private std::allocator { template friend struct SecureAllocator; @@ -48,16 +50,16 @@ struct SecureAllocator : private std::allocator { return static_cast&>(*this) == static_cast&>(rhs); } }; -template +EXPORT_CPR template bool operator==(const SecureAllocator& lhs, const SecureAllocator& rhs) noexcept { return lhs.IsEqual(rhs); } -template +EXPORT_CPR template bool operator!=(const SecureAllocator& lhs, const SecureAllocator& rhs) noexcept { return !lhs.IsEqual(rhs); } -using SecureString = std::basic_string, SecureAllocator>; +EXPORT_CPR using SecureString = std::basic_string, SecureAllocator>; } // namespace cpr::util diff --git a/include/cpr/session.h b/include/cpr/session.h index 0781559f9..a50957eb1 100644 --- a/include/cpr/session.h +++ b/include/cpr/session.h @@ -1,6 +1,8 @@ #ifndef CPR_SESSION_H #define CPR_SESSION_H +#include "cpr/export.h" + #include #include #include @@ -48,13 +50,13 @@ namespace cpr { -using AsyncResponse = AsyncWrapper; -using Content = std::variant; +EXPORT_CPR using AsyncResponse = AsyncWrapper; +EXPORT_CPR using Content = std::variant; -class Interceptor; -class MultiPerform; +EXPORT_CPR class Interceptor; +EXPORT_CPR class MultiPerform; -class Session : public std::enable_shared_from_this { +EXPORT_CPR class Session : public std::enable_shared_from_this { public: Session(); Session(const Session& other) = delete; diff --git a/include/cpr/sse.h b/include/cpr/sse.h index 54746a341..ad6c8780e 100644 --- a/include/cpr/sse.h +++ b/include/cpr/sse.h @@ -1,6 +1,8 @@ #ifndef CPR_SSE_H #define CPR_SSE_H +#include "cpr/export.h" + #include #include #include @@ -14,7 +16,7 @@ namespace cpr { * Represents a Server-Sent Event (SSE) as defined in the HTML5 specification. * https://html.spec.whatwg.org/multipage/server-sent-events.html */ -struct ServerSentEvent { +EXPORT_CPR struct ServerSentEvent { /** * The event ID. Can be used to track the last received event and resume from there. */ @@ -42,7 +44,7 @@ struct ServerSentEvent { * Parser for Server-Sent Events (SSE) streams. * This parser handles incoming SSE data according to the HTML5 specification. */ -class ServerSentEventParser { +EXPORT_CPR class ServerSentEventParser { public: ServerSentEventParser() = default; @@ -71,7 +73,7 @@ class ServerSentEventParser { * Callback for handling Server-Sent Events. * The callback receives each parsed SSE event and can return false to abort the connection. */ -class ServerSentEventCallback { +EXPORT_CPR class ServerSentEventCallback { public: ServerSentEventCallback() = default; ServerSentEventCallback(std::function p_callback, intptr_t p_userdata = 0) : userdata(p_userdata), callback(std::move(p_callback)) {} diff --git a/include/cpr/ssl_ctx.h b/include/cpr/ssl_ctx.h index b6bc81190..4dfc7fb6d 100644 --- a/include/cpr/ssl_ctx.h +++ b/include/cpr/ssl_ctx.h @@ -1,6 +1,8 @@ #ifndef CPR_SSL_CTX_H #define CPR_SSL_CTX_H +#include "cpr/export.h" + #include "cpr/ssl_options.h" #include @@ -17,7 +19,7 @@ namespace cpr { * Sources: https://curl.se/libcurl/c/CURLOPT_SSL_CTX_FUNCTION.html * https://curl.se/libcurl/c/CURLOPT_SSL_CTX_DATA.html */ -CURLcode sslctx_function_load_ca_cert_from_buffer(CURL* curl, void* sslctx, void* raw_cert_buf); +EXPORT_CPR CURLcode sslctx_function_load_ca_cert_from_buffer(CURL* curl, void* sslctx, void* raw_cert_buf); } // Namespace cpr diff --git a/include/cpr/ssl_options.h b/include/cpr/ssl_options.h index 338744ea9..25efb68bf 100644 --- a/include/cpr/ssl_options.h +++ b/include/cpr/ssl_options.h @@ -1,6 +1,8 @@ #ifndef CPR_SSL_OPTIONS_H #define CPR_SSL_OPTIONS_H +#include "cpr/export.h" + #include #include #include @@ -76,7 +78,7 @@ namespace cpr { -class VerifySsl { +EXPORT_CPR class VerifySsl { public: VerifySsl() = default; VerifySsl(bool p_verify) : verify(p_verify) {} @@ -91,7 +93,7 @@ class VerifySsl { namespace ssl { // set SSL client certificate -class CertFile { +EXPORT_CPR class CertFile { public: CertFile(fs::path&& p_filename) : filename(std::move(p_filename)) {} @@ -104,9 +106,9 @@ class CertFile { } }; -using PemCert = CertFile; +EXPORT_CPR using PemCert = CertFile; -class DerCert : public CertFile { +EXPORT_CPR class DerCert : public CertFile { public: DerCert(fs::path&& p_filename) : CertFile(std::move(p_filename)) {} @@ -119,7 +121,7 @@ class DerCert : public CertFile { #if SUPPORT_CURLOPT_SSLCERT_BLOB -class CertBlob { +EXPORT_CPR class CertBlob { public: CertBlob(std::string&& p_blob) : blob(std::move(p_blob)) {} @@ -132,9 +134,9 @@ class CertBlob { } }; -using PemBlob = CertBlob; +EXPORT_CPR using PemBlob = CertBlob; -class DerBlob : public CertBlob { +EXPORT_CPR class DerBlob : public CertBlob { public: template // NOLINTNEXTLINE(bugprone-forwarding-reference-overload) @@ -149,7 +151,7 @@ class DerBlob : public CertBlob { #endif // specify private keyfile for TLS and SSL client cert -class KeyFile { +EXPORT_CPR class KeyFile { public: KeyFile(fs::path&& p_filename) : filename(std::move(p_filename)) {} @@ -167,7 +169,7 @@ class KeyFile { }; #if SUPPORT_CURLOPT_SSLKEY_BLOB -class KeyBlob { +EXPORT_CPR class KeyBlob { public: KeyBlob(std::string&& p_blob) : blob(std::move(p_blob)) {} @@ -185,9 +187,9 @@ class KeyBlob { }; #endif -using PemKey = KeyFile; +EXPORT_CPR using PemKey = KeyFile; -class DerKey : public KeyFile { +EXPORT_CPR class DerKey : public KeyFile { public: DerKey(fs::path&& p_filename) : KeyFile(std::move(p_filename)) {} @@ -201,7 +203,7 @@ class DerKey : public KeyFile { } }; -class PinnedPublicKey { +EXPORT_CPR class PinnedPublicKey { public: PinnedPublicKey(std::string&& p_pinned_public_key) : pinned_public_key(std::move(p_pinned_public_key)) {} @@ -211,7 +213,7 @@ class PinnedPublicKey { #if SUPPORT_ALPN // This option enables/disables ALPN in the SSL handshake (if the SSL backend libcurl is built to // use supports it), which can be used to negotiate http2. -class ALPN { +EXPORT_CPR class ALPN { public: ALPN() = default; ALPN(bool p_enabled) : enabled(p_enabled) {} @@ -227,7 +229,7 @@ class ALPN { #if SUPPORT_NPN // This option enables/disables NPN in the SSL handshake (if the SSL backend libcurl is built to // use supports it), which can be used to negotiate http2. -class NPN { +EXPORT_CPR class NPN { public: NPN() = default; NPN(bool p_enabled) : enabled(p_enabled) {} @@ -242,7 +244,7 @@ class NPN { // This option determines whether libcurl verifies that the server cert is for the server it is // known as. -class VerifyHost { +EXPORT_CPR class VerifyHost { public: VerifyHost() = default; VerifyHost(bool p_enabled) : enabled(p_enabled) {} @@ -255,7 +257,7 @@ class VerifyHost { }; // This option determines whether libcurl verifies the authenticity of the peer's certificate. -class VerifyPeer { +EXPORT_CPR class VerifyPeer { public: VerifyPeer() = default; VerifyPeer(bool p_enabled) : enabled(p_enabled) {} @@ -269,7 +271,7 @@ class VerifyPeer { // This option determines whether libcurl verifies the status of the server cert using the // "Certificate Status Request" TLS extension (aka. OCSP stapling). -class VerifyStatus { +EXPORT_CPR class VerifyStatus { public: VerifyStatus(bool p_enabled) : enabled(p_enabled) {} @@ -281,55 +283,55 @@ class VerifyStatus { }; // TLS v1.0 or later -struct TLSv1 {}; +EXPORT_CPR struct TLSv1 {}; #if SUPPORT_SSLv2 // SSL v2 (but not SSLv3) -struct SSLv2 {}; +EXPORT_CPR struct SSLv2 {}; #endif #if SUPPORT_SSLv3 // SSL v3 (but not SSLv2) -struct SSLv3 {}; +EXPORT_CPR struct SSLv3 {}; #endif #if SUPPORT_TLSv1_0 // TLS v1.0 or later (Added in 7.34.0) -struct TLSv1_0 {}; +EXPORT_CPR struct TLSv1_0 {}; #endif #if SUPPORT_TLSv1_1 // TLS v1.1 or later (Added in 7.34.0) -struct TLSv1_1 {}; +EXPORT_CPR struct TLSv1_1 {}; #endif #if SUPPORT_TLSv1_2 // TLS v1.2 or later (Added in 7.34.0) -struct TLSv1_2 {}; +EXPORT_CPR struct TLSv1_2 {}; #endif #if SUPPORT_TLSv1_3 // TLS v1.3 or later (Added in 7.52.0) -struct TLSv1_3 {}; +EXPORT_CPR struct TLSv1_3 {}; #endif #if SUPPORT_MAX_TLS_VERSION // The flag defines the maximum supported TLS version by libcurl, or the default value from the SSL // library is used. -struct MaxTLSVersion {}; +EXPORT_CPR struct MaxTLSVersion {}; #endif #if SUPPORT_MAX_TLSv1_0 // The flag defines maximum supported TLS version as TLSv1.0. (Added in 7.54.0) -struct MaxTLSv1_0 {}; +EXPORT_CPR struct MaxTLSv1_0 {}; #endif #if SUPPORT_MAX_TLSv1_1 // The flag defines maximum supported TLS version as TLSv1.1. (Added in 7.54.0) -struct MaxTLSv1_1 {}; +EXPORT_CPR struct MaxTLSv1_1 {}; #endif #if SUPPORT_MAX_TLSv1_2 // The flag defines maximum supported TLS version as TLSv1.2. (Added in 7.54.0) -struct MaxTLSv1_2 {}; +EXPORT_CPR struct MaxTLSv1_2 {}; #endif #if SUPPORT_MAX_TLSv1_3 // The flag defines maximum supported TLS version as TLSv1.3. (Added in 7.54.0) -struct MaxTLSv1_3 {}; +EXPORT_CPR struct MaxTLSv1_3 {}; #endif // path to Certificate Authority (CA) bundle -class CaInfo { +EXPORT_CPR class CaInfo { public: CaInfo(fs::path&& p_filename) : filename(std::move(p_filename)) {} @@ -338,7 +340,7 @@ class CaInfo { #if SUPPORT_CURLOPT_CAINFO_BLOB // Certificate Authority (CA) bundle as blob -class CaInfoBlob { +EXPORT_CPR class CaInfoBlob { public: CaInfoBlob(std::string&& p_blob) : blob(std::move(p_blob)) {} @@ -347,7 +349,7 @@ class CaInfoBlob { #endif // specify directory holding CA certificates -class CaPath { +EXPORT_CPR class CaPath { public: CaPath(fs::path&& p_filename) : filename(std::move(p_filename)) {} @@ -355,7 +357,7 @@ class CaPath { }; #if SUPPORT_CURLOPT_SSL_CTX_FUNCTION -class CaBuffer { +EXPORT_CPR class CaBuffer { public: CaBuffer(std::string&& p_buffer) : buffer(std::move(p_buffer)) {} @@ -364,7 +366,7 @@ class CaBuffer { #endif // specify a Certificate Revocation List file -class Crl { +EXPORT_CPR class Crl { public: Crl(fs::path&& p_filename) : filename(std::move(p_filename)) {} @@ -372,7 +374,7 @@ class Crl { }; // specify ciphers to use for TLS -class Ciphers { +EXPORT_CPR class Ciphers { public: Ciphers(std::string&& p_ciphers) : ciphers(std::move(p_ciphers)) {} @@ -381,7 +383,7 @@ class Ciphers { #if SUPPORT_TLSv13_CIPHERS // specify ciphers suites to use for TLS 1.3 -class TLS13_Ciphers { +EXPORT_CPR class TLS13_Ciphers { public: TLS13_Ciphers(std::string&& p_ciphers) : ciphers(std::move(p_ciphers)) {} @@ -391,7 +393,7 @@ class TLS13_Ciphers { #if SUPPORT_SESSIONID_CACHE // enable/disable use of the SSL session-ID cache -class SessionIdCache { +EXPORT_CPR class SessionIdCache { public: SessionIdCache() = default; SessionIdCache(bool p_enabled) : enabled(p_enabled) {} @@ -405,7 +407,7 @@ class SessionIdCache { #endif #if SUPPORT_SSL_FALSESTART -class SslFastStart { +EXPORT_CPR class SslFastStart { public: SslFastStart() = default; SslFastStart(bool p_enabled) : enabled(p_enabled) {} @@ -418,7 +420,7 @@ class SslFastStart { }; #endif -class NoRevoke { +EXPORT_CPR class NoRevoke { public: NoRevoke() = default; NoRevoke(bool p_enabled) : enabled(p_enabled) {} @@ -432,7 +434,7 @@ class NoRevoke { } // namespace ssl -struct SslOptions { +EXPORT_CPR struct SslOptions { // We don't use fs::path here, as this leads to problems using windows std::string cert_file; #if SUPPORT_CURLOPT_SSLCERT_BLOB @@ -640,7 +642,7 @@ void set_ssl_option(SslOptions& opts, T&& t, Ts&&... ts) { } // namespace priv -template +EXPORT_CPR template SslOptions Ssl(Ts&&... ts) { SslOptions opts; priv::set_ssl_option(opts, std::forward(ts)...); diff --git a/include/cpr/status_codes.h b/include/cpr/status_codes.h index 38dc0eb97..bd3d46d1d 100644 --- a/include/cpr/status_codes.h +++ b/include/cpr/status_codes.h @@ -1,95 +1,99 @@ #ifndef CPR_STATUS_CODES #define CPR_STATUS_CODES + +#include "cpr/export.h" + + namespace cpr::status { // Information responses -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; +EXPORT_CPR inline constexpr long HTTP_CONTINUE = 100; +EXPORT_CPR inline constexpr long HTTP_SWITCHING_PROTOCOL = 101; +EXPORT_CPR inline constexpr long HTTP_PROCESSING = 102; +EXPORT_CPR inline constexpr long HTTP_EARLY_HINTS = 103; // Successful responses -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; +EXPORT_CPR inline constexpr long HTTP_OK = 200; +EXPORT_CPR inline constexpr long HTTP_CREATED = 201; +EXPORT_CPR inline constexpr long HTTP_ACCEPTED = 202; +EXPORT_CPR inline constexpr long HTTP_NON_AUTHORITATIVE_INFORMATION = 203; +EXPORT_CPR inline constexpr long HTTP_NO_CONTENT = 204; +EXPORT_CPR inline constexpr long HTTP_RESET_CONTENT = 205; +EXPORT_CPR inline constexpr long HTTP_PARTIAL_CONTENT = 206; +EXPORT_CPR inline constexpr long HTTP_MULTI_STATUS = 207; +EXPORT_CPR inline constexpr long HTTP_ALREADY_REPORTED = 208; +EXPORT_CPR inline constexpr long HTTP_IM_USED = 226; // Redirection messages -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; +EXPORT_CPR inline constexpr long HTTP_MULTIPLE_CHOICE = 300; +EXPORT_CPR inline constexpr long HTTP_MOVED_PERMANENTLY = 301; +EXPORT_CPR inline constexpr long HTTP_FOUND = 302; +EXPORT_CPR inline constexpr long HTTP_SEE_OTHER = 303; +EXPORT_CPR inline constexpr long HTTP_NOT_MODIFIED = 304; +EXPORT_CPR inline constexpr long HTTP_USE_PROXY = 305; +EXPORT_CPR inline constexpr long HTTP_UNUSED = 306; +EXPORT_CPR inline constexpr long HTTP_TEMPORARY_REDIRECT = 307; +EXPORT_CPR inline constexpr long HTTP_PERMANENT_REDIRECT = 308; // Client error responses -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; +EXPORT_CPR inline constexpr long HTTP_BAD_REQUEST = 400; +EXPORT_CPR inline constexpr long HTTP_UNAUTHORIZED = 401; +EXPORT_CPR inline constexpr long HTTP_PAYMENT_REQUIRED = 402; +EXPORT_CPR inline constexpr long HTTP_FORBIDDEN = 403; +EXPORT_CPR inline constexpr long HTTP_NOT_FOUND = 404; +EXPORT_CPR inline constexpr long HTTP_METHOD_NOT_ALLOWED = 405; +EXPORT_CPR inline constexpr long HTTP_NOT_ACCEPTABLE = 406; +EXPORT_CPR inline constexpr long HTTP_PROXY_AUTHENTICATION_REQUIRED = 407; +EXPORT_CPR inline constexpr long HTTP_REQUEST_TIMEOUT = 408; +EXPORT_CPR inline constexpr long HTTP_CONFLICT = 409; +EXPORT_CPR inline constexpr long HTTP_GONE = 410; +EXPORT_CPR inline constexpr long HTTP_LENGTH_REQUIRED = 411; +EXPORT_CPR inline constexpr long HTTP_PRECONDITION_FAILED = 412; +EXPORT_CPR inline constexpr long HTTP_PAYLOAD_TOO_LARGE = 413; +EXPORT_CPR inline constexpr long HTTP_URI_TOO_LONG = 414; +EXPORT_CPR inline constexpr long HTTP_UNSUPPORTED_MEDIA_TYPE = 415; +EXPORT_CPR inline constexpr long HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416; +EXPORT_CPR inline constexpr long HTTP_EXPECTATION_FAILED = 417; +EXPORT_CPR inline constexpr long HTTP_IM_A_TEAPOT = 418; +EXPORT_CPR inline constexpr long HTTP_MISDIRECTED_REQUEST = 421; +EXPORT_CPR inline constexpr long HTTP_UNPROCESSABLE_ENTITY = 422; +EXPORT_CPR inline constexpr long HTTP_LOCKED = 423; +EXPORT_CPR inline constexpr long HTTP_FAILED_DEPENDENCY = 424; +EXPORT_CPR inline constexpr long HTTP_TOO_EARLY = 425; +EXPORT_CPR inline constexpr long HTTP_UPGRADE_REQUIRED = 426; +EXPORT_CPR inline constexpr long HTTP_PRECONDITION_REQUIRED = 428; +EXPORT_CPR inline constexpr long HTTP_TOO_MANY_REQUESTS = 429; +EXPORT_CPR inline constexpr long HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE = 431; +EXPORT_CPR inline constexpr long HTTP_UNAVAILABLE_FOR_LEGAL_REASONS = 451; // Server response errors -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; +EXPORT_CPR inline constexpr long HTTP_INTERNAL_SERVER_ERROR = 500; +EXPORT_CPR inline constexpr long HTTP_NOT_IMPLEMENTED = 501; +EXPORT_CPR inline constexpr long HTTP_BAD_GATEWAY = 502; +EXPORT_CPR inline constexpr long HTTP_SERVICE_UNAVAILABLE = 503; +EXPORT_CPR inline constexpr long HTTP_GATEWAY_TIMEOUT = 504; +EXPORT_CPR inline constexpr long HTTP_HTTP_VERSION_NOT_SUPPORTED = 505; +EXPORT_CPR inline constexpr long HTTP_VARIANT_ALSO_NEGOTIATES = 506; +EXPORT_CPR inline constexpr long HTTP_INSUFFICIENT_STORAGE = 507; +EXPORT_CPR inline constexpr long HTTP_LOOP_DETECTED = 508; +EXPORT_CPR inline constexpr long HTTP_NOT_EXTENDED = 510; +EXPORT_CPR inline constexpr long HTTP_NETWORK_AUTHENTICATION_REQUIRED = 511; -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; +EXPORT_CPR inline constexpr long INFO_CODE_OFFSET = 100; +EXPORT_CPR inline constexpr long SUCCESS_CODE_OFFSET = 200; +EXPORT_CPR inline constexpr long REDIRECT_CODE_OFFSET = 300; +EXPORT_CPR inline constexpr long CLIENT_ERROR_CODE_OFFSET = 400; +EXPORT_CPR inline constexpr long SERVER_ERROR_CODE_OFFSET = 500; +EXPORT_CPR inline constexpr long MISC_CODE_OFFSET = 600; -constexpr bool is_informational(const long code) { +EXPORT_CPR constexpr bool is_informational(const long code) { return (code >= INFO_CODE_OFFSET && code < SUCCESS_CODE_OFFSET); } -constexpr bool is_success(const long code) { +EXPORT_CPR constexpr bool is_success(const long code) { return (code >= SUCCESS_CODE_OFFSET && code < REDIRECT_CODE_OFFSET); } -constexpr bool is_redirect(const long code) { +EXPORT_CPR constexpr bool is_redirect(const long code) { return (code >= REDIRECT_CODE_OFFSET && code < CLIENT_ERROR_CODE_OFFSET); } -constexpr bool is_client_error(const long code) { +EXPORT_CPR constexpr bool is_client_error(const long code) { return (code >= CLIENT_ERROR_CODE_OFFSET && code < SERVER_ERROR_CODE_OFFSET); } -constexpr bool is_server_error(const long code) { +EXPORT_CPR constexpr bool is_server_error(const long code) { return (code >= SERVER_ERROR_CODE_OFFSET && code < MISC_CODE_OFFSET); } } // namespace cpr::status diff --git a/include/cpr/threadpool.h b/include/cpr/threadpool.h index a32c33fe7..27d8a2869 100644 --- a/include/cpr/threadpool.h +++ b/include/cpr/threadpool.h @@ -1,6 +1,8 @@ #ifndef CPR_THREADPOOL_H #define CPR_THREADPOOL_H +#include "cpr/export.h" + #include #include #include @@ -16,12 +18,12 @@ #define CPR_DEFAULT_THREAD_POOL_MAX_THREAD_NUM std::thread::hardware_concurrency() -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}; +EXPORT_CPR inline constexpr size_t CPR_DEFAULT_THREAD_POOL_MIN_THREAD_NUM = 1; +EXPORT_CPR inline constexpr std::chrono::milliseconds CPR_DEFAULT_THREAD_POOL_MAX_IDLE_TIME{250}; namespace cpr { -class ThreadPool { +EXPORT_CPR class ThreadPool { public: using Task = std::function; diff --git a/include/cpr/timeout.h b/include/cpr/timeout.h index 6f532d306..2255404d4 100644 --- a/include/cpr/timeout.h +++ b/include/cpr/timeout.h @@ -1,12 +1,14 @@ #ifndef CPR_TIMEOUT_H #define CPR_TIMEOUT_H +#include "cpr/export.h" + #include #include namespace cpr { -class Timeout { +EXPORT_CPR class Timeout { public: // Template constructor to accept any chrono duration type and convert it to milliseconds template diff --git a/include/cpr/unix_socket.h b/include/cpr/unix_socket.h index 5597ac921..3bc1ca1ac 100644 --- a/include/cpr/unix_socket.h +++ b/include/cpr/unix_socket.h @@ -1,11 +1,13 @@ #ifndef CPR_UNIX_SOCKET_H #define CPR_UNIX_SOCKET_H +#include "cpr/export.h" + #include namespace cpr { -class UnixSocket { +EXPORT_CPR class UnixSocket { public: UnixSocket(std::string unix_socket) : unix_socket_(std::move(unix_socket)) {} diff --git a/include/cpr/user_agent.h b/include/cpr/user_agent.h index 5cb04ea7c..09a2e4c3a 100644 --- a/include/cpr/user_agent.h +++ b/include/cpr/user_agent.h @@ -1,13 +1,15 @@ #ifndef CPR_USER_AGENT_H #define CPR_USER_AGENT_H +#include "cpr/export.h" + #include #include #include "cpr/cprtypes.h" namespace cpr { -class UserAgent : public StringHolder { +EXPORT_CPR class UserAgent : public StringHolder { public: UserAgent() = default; UserAgent(std::string useragent) : StringHolder(std::move(useragent)) {} diff --git a/include/cpr/util.h b/include/cpr/util.h index e210b19b7..99e0e9601 100644 --- a/include/cpr/util.h +++ b/include/cpr/util.h @@ -1,6 +1,8 @@ #ifndef CPR_UTIL_H #define CPR_UTIL_H +#include "cpr/export.h" + #include #include #include @@ -14,16 +16,16 @@ namespace cpr::util { -Header parseHeader(const std::string& headers, std::string* status_line = nullptr, std::string* reason = nullptr); -Cookies parseCookies(curl_slist* raw_cookies); -size_t readUserFunction(char* ptr, size_t size, size_t nitems, const ReadCallback* read); -size_t headerUserFunction(char* ptr, size_t size, size_t nmemb, const HeaderCallback* header); -size_t writeFunction(char* ptr, size_t size, size_t nmemb, void* data); -size_t writeFileFunction(char* ptr, size_t size, size_t nmemb, std::ofstream* file); -size_t writeUserFunction(char* ptr, size_t size, size_t nmemb, const WriteCallback* write); -size_t writeSSEFunction(char* ptr, size_t size, size_t nmemb, ServerSentEventCallback* sse); +EXPORT_CPR Header parseHeader(const std::string& headers, std::string* status_line = nullptr, std::string* reason = nullptr); +EXPORT_CPR Cookies parseCookies(curl_slist* raw_cookies); +EXPORT_CPR size_t readUserFunction(char* ptr, size_t size, size_t nitems, const ReadCallback* read); +EXPORT_CPR size_t headerUserFunction(char* ptr, size_t size, size_t nmemb, const HeaderCallback* header); +EXPORT_CPR size_t writeFunction(char* ptr, size_t size, size_t nmemb, void* data); +EXPORT_CPR size_t writeFileFunction(char* ptr, size_t size, size_t nmemb, std::ofstream* file); +EXPORT_CPR size_t writeUserFunction(char* ptr, size_t size, size_t nmemb, const WriteCallback* write); +EXPORT_CPR size_t writeSSEFunction(char* ptr, size_t size, size_t nmemb, ServerSentEventCallback* sse); -template +EXPORT_CPR template int progressUserFunction(const T* progress, cpr_pf_arg_t dltotal, cpr_pf_arg_t dlnow, cpr_pf_arg_t ultotal, cpr_pf_arg_t ulnow) { const int cancel_retval{1}; #ifdef CURL_PROGRESSFUNC_CONTINUE // Not always defined. Ref: https://github.com/libcpr/cpr/issues/932 @@ -31,18 +33,18 @@ int progressUserFunction(const T* progress, cpr_pf_arg_t dltotal, cpr_pf_arg_t d #endif // CURL_PROGRESSFUNC_CONTINUE return (*progress)(dltotal, dlnow, ultotal, ulnow) ? 0 : cancel_retval; } -int debugUserFunction(CURL* handle, curl_infotype type, char* data, size_t size, const DebugCallback* debug); -std::vector split(const std::string& to_split, char delimiter); -util::SecureString urlEncode(std::string_view s); -util::SecureString urlDecode(std::string_view s); +EXPORT_CPR int debugUserFunction(CURL* handle, curl_infotype type, char* data, size_t size, const DebugCallback* debug); +EXPORT_CPR std::vector split(const std::string& to_split, char delimiter); +EXPORT_CPR util::SecureString urlEncode(std::string_view s); +EXPORT_CPR util::SecureString urlDecode(std::string_view s); -bool isTrue(const std::string& s); +EXPORT_CPR bool isTrue(const std::string& s); /** * Parses the given std::string into time_t (unix ms). * This parsing happens time_t size agnostic since time_t does not use the same underlying type on all systems/compilers. **/ -time_t sTimestampToT(const std::string& /*st*/); +EXPORT_CPR time_t sTimestampToT(const std::string& /*st*/); } // namespace cpr::util diff --git a/include/cpr/verbose.h b/include/cpr/verbose.h index 46714200d..2de26d508 100644 --- a/include/cpr/verbose.h +++ b/include/cpr/verbose.h @@ -1,9 +1,11 @@ #ifndef CPR_VERBOSE_H_ #define CPR_VERBOSE_H_ +#include "cpr/export.h" + namespace cpr { -class Verbose { +EXPORT_CPR class Verbose { public: Verbose() = default; Verbose(const bool p_verbose) : verbose{p_verbose} {} diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt index a49dfa2db..90f8d8682 100644 --- a/modules/CMakeLists.txt +++ b/modules/CMakeLists.txt @@ -11,7 +11,7 @@ endif() # GCC gained module scanning support in version 14. if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND - CMAKE_CXX_COMPILER_VERSION VERSION_LESS "14") + CMAKE_CXX_COMPILER_VERSION VERSION_LESS "14") message(FATAL_ERROR "C++20 module scanning requires GCC 14 or later " "(found ${CMAKE_CXX_COMPILER_VERSION}).") @@ -20,11 +20,12 @@ endif() set(CMAKE_CXX_SCAN_FOR_MODULES ON) add_library(cpr_module) +add_library(cpr::module ALIAS cpr_module) target_sources(cpr_module PUBLIC - FILE_SET CXX_MODULES FILES - cpr.cxx + FILE_SET CXX_MODULES FILES + cpr.cxx ) target_compile_features(cpr_module PUBLIC cxx_std_20) @@ -34,13 +35,15 @@ target_include_directories(cpr_module PUBLIC $ ) -add_library(cpr::module ALIAS cpr_module) +target_link_libraries(cpr_module PUBLIC cpr::cpr) # 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 -) +if(CPR_ENABLE_INSTALL) + 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 + ) +endif() diff --git a/modules/cpr.cxx b/modules/cpr.cxx index 2e82643b0..4ece4adc0 100644 --- a/modules/cpr.cxx +++ b/modules/cpr.cxx @@ -1,334 +1,7 @@ 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; +#define EXPORT_CPR export - 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; -} +#include "cpr/cpr.h" From bfa74b0a39eaf9d775da57d81dbd098520e8ca06 Mon Sep 17 00:00:00 2001 From: Fabian Sauter Date: Thu, 14 May 2026 14:28:55 +0200 Subject: [PATCH 4/9] Use import std if possible [skip-ci] --- CMakeLists.txt | 19 ++++++++++++++++++- cmake/cprver.h.in | 11 ++++++----- modules/CMakeLists.txt | 2 +- modules/cpr.cxx | 3 +++ 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e400aa10..1c78ab12d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,21 @@ -cmake_minimum_required(VERSION 3.18) +cmake_minimum_required(VERSION 3.18...4.3) + +if(NOT CMAKE_EXPERIMENTAL_CXX_STD AND NOT CMAKE_CXX_MODULE_STD) + if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.30" AND CMAKE_VERSION VERSION_LESS_EQUAL "4.0") + set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "0e5b6991-d74f-4b3d-a41c-cf096e0b2508") + set(CMAKE_CXX_MODULE_STD 1) + elseif(CMAKE_VERSION VERSION_GREATER_EQUAL "4.0" AND CMAKE_VERSION VERSION_LESS "4.0.3") + set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "a9e1cf81-9932-4810-974b-6eccaf14e457") + set(CMAKE_CXX_MODULE_STD 1) + elseif(CMAKE_VERSION VERSION_GREATER_EQUAL "4.0.3" AND CMAKE_VERSION VERSION_LESS "4.3") + set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "d0edc3af-4c50-42ea-a356-e2862fe7a444") + set(CMAKE_CXX_MODULE_STD 1) + elseif(CMAKE_VERSION VERSION_GREATER_EQUAL "4.3") + set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "451f2fe2-a8a2-47c3-bc32-94786d8fc91b") + set(CMAKE_CXX_MODULE_STD 1) + endif() +endif() + project(cpr VERSION 1.15.0 LANGUAGES CXX) math(EXPR cpr_VERSION_NUM "${cpr_VERSION_MAJOR} * 0x10000 + ${cpr_VERSION_MINOR} * 0x100 + ${cpr_VERSION_PATCH}" OUTPUT_FORMAT HEXADECIMAL) diff --git a/cmake/cprver.h.in b/cmake/cprver.h.in index 52ab32fa8..254046d4f 100644 --- a/cmake/cprver.h.in +++ b/cmake/cprver.h.in @@ -3,18 +3,19 @@ #include "cpr/export.h" #include +#include /** * CPR version as a string. **/ -EXPORT_CPR constexpr std::string CPR_VERSION{"${cpr_VERSION}"}; +EXPORT_CPR inline constexpr std::string_view CPR_VERSION{"${cpr_VERSION}"}; /** * CPR version split up into parts. **/ -EXPORT_CPR constexpr uint8_t CPR_VERSION_MAJOR{${cpr_VERSION_MAJOR}}; -EXPORT_CPR constexpr uint8_t CPR_VERSION_MINOR{${cpr_VERSION_MINOR}}; -EXPORT_CPR constexpr uint8_t CPR_VERSION_PATCH{${cpr_VERSION_PATCH}}; +EXPORT_CPR inline constexpr uint8_t CPR_VERSION_MAJOR{${cpr_VERSION_MAJOR}}; +EXPORT_CPR inline constexpr uint8_t CPR_VERSION_MINOR{${cpr_VERSION_MINOR}}; +EXPORT_CPR inline constexpr uint8_t CPR_VERSION_PATCH{${cpr_VERSION_PATCH}}; /** * CPR version as a single hex digit. @@ -28,6 +29,6 @@ EXPORT_CPR constexpr uint8_t CPR_VERSION_PATCH{${cpr_VERSION_PATCH}}; * '0x010702' -> 01.07.02 -> CPR_VERSION: 1.7.2 * '0xA13722' -> A1.37.22 -> CPR_VERSION: 161.55.34 **/ -EXPORT_CPR constexpr uint64_t CPR_VERSION_NUM{${cpr_VERSION_NUM}}; +EXPORT_CPR inline constexpr uint64_t CPR_VERSION_NUM{${cpr_VERSION_NUM}}; #endif diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt index 90f8d8682..1dd9f0d9e 100644 --- a/modules/CMakeLists.txt +++ b/modules/CMakeLists.txt @@ -28,7 +28,7 @@ target_sources(cpr_module cpr.cxx ) -target_compile_features(cpr_module PUBLIC cxx_std_20) +target_compile_features(cpr_module PRIVATE cxx_std_23 INTERFACE cxx_std_20) target_include_directories(cpr_module PUBLIC $ diff --git a/modules/cpr.cxx b/modules/cpr.cxx index 4ece4adc0..4c906f69a 100644 --- a/modules/cpr.cxx +++ b/modules/cpr.cxx @@ -1,7 +1,10 @@ module; +import std; + export module cpr; +#define CPR_AS_MODULE 1 #define EXPORT_CPR export #include "cpr/cpr.h" From 71ade0cd01c904d6d6afe593276a4bb6c5f5c9ea Mon Sep 17 00:00:00 2001 From: Fabian Sauter Date: Sun, 17 May 2026 13:13:13 +0200 Subject: [PATCH 5/9] import std fixes --- CMakeLists.txt | 104 ++++++++++++++++++---------------- cmake/cprver.h.in | 7 +++ include/cpr/accept_encoding.h | 13 ++++- include/cpr/api.h | 12 ++-- include/cpr/async_wrapper.h | 6 ++ include/cpr/auth.h | 9 ++- include/cpr/bearer.h | 9 ++- include/cpr/body.h | 7 ++- include/cpr/body_view.h | 6 ++ include/cpr/buffer.h | 3 +- include/cpr/callback.h | 12 +++- include/cpr/cert_info.h | 6 ++ include/cpr/connection_pool.h | 9 ++- include/cpr/cookies.h | 9 ++- include/cpr/cprtypes.h | 11 +++- include/cpr/curl_container.h | 7 ++- include/cpr/curlholder.h | 8 ++- include/cpr/error.h | 10 +++- include/cpr/file.h | 6 ++ include/cpr/filesystem.h | 12 ++++ include/cpr/interceptor.h | 9 ++- include/cpr/interface.h | 6 ++ include/cpr/low_speed.h | 7 +++ include/cpr/multipart.h | 9 ++- include/cpr/multiperform.h | 14 +++-- include/cpr/parameters.h | 6 ++ include/cpr/payload.h | 6 ++ include/cpr/proxies.h | 6 ++ include/cpr/proxyauth.h | 6 ++ include/cpr/range.h | 9 ++- include/cpr/resolve.h | 9 ++- include/cpr/response.h | 10 +++- include/cpr/secure_string.h | 7 ++- include/cpr/session.h | 10 ++-- include/cpr/singleton.h | 1 - include/cpr/sse.h | 9 ++- include/cpr/ssl_options.h | 14 +++-- include/cpr/threadpool.h | 9 ++- include/cpr/timeout.h | 7 +++ include/cpr/unix_socket.h | 6 ++ include/cpr/user_agent.h | 6 ++ include/cpr/util.h | 7 ++- modules/CMakeLists.txt | 3 +- modules/cpr.cxx | 17 +++++- 44 files changed, 354 insertions(+), 105 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c78ab12d..142c7bf0b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,61 @@ cmake_minimum_required(VERSION 3.18...4.3) -if(NOT CMAKE_EXPERIMENTAL_CXX_STD AND NOT CMAKE_CXX_MODULE_STD) - if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.30" AND CMAKE_VERSION VERSION_LESS_EQUAL "4.0") +macro(cpr_option OPTION_NAME OPTION_TEXT OPTION_DEFAULT) + option(${OPTION_NAME} ${OPTION_TEXT} ${OPTION_DEFAULT}) + + if(DEFINED ENV{${OPTION_NAME}}) + # Allow overriding the option through an environment variable + set(${OPTION_NAME} $ENV{${OPTION_NAME}}) + endif() + + if(${OPTION_NAME}) + add_definitions(-D${OPTION_NAME}) + endif() + + message(STATUS " ${OPTION_NAME}: ${${OPTION_NAME}}") +endmacro() + +message(STATUS "C++ Requests CMake Options") +message(STATUS "=======================================================") +cpr_option(CPR_ENABLE_INSTALL "Set to ON to enable all cpr install targets." ON) +cpr_option(CPR_GENERATE_COVERAGE "Set to ON to generate coverage reports." OFF) +cpr_option(CPR_CURL_NOSIGNAL "Set to ON to disable use of signals in libcurl." OFF) +cpr_option(CURL_VERBOSE_LOGGING "Curl verbose logging during building curl" OFF) +cpr_option(CPR_USE_SYSTEM_GTEST "If ON, this project will look in the system paths for an installed gtest library. If none is found it will use the built-in one." OFF) +cpr_option(CPR_USE_SYSTEM_CURL "If enabled we will use the curl lib already installed on this system." OFF) +cpr_option(CPR_USE_EXISTING_CURL_TARGET "Use an existing libcurl cmake target instead of having the cpr project source the dependency itself." OFF) +cpr_option(CPR_CURL_USE_LIBPSL "Since curl 8.13 curl depends on libpsl (https://everything.curl.dev/build/deps.html#libpsl). By default cpr keeps this as a secure default enabled wich in turn requires meson as build dependency. If set to OFF, psl support inside curl will be disabled." ON) +cpr_option(CPR_USE_SYSTEM_LIB_PSL "If enabled we will use the psl lib already installed on this system. Else meson is required as build dependency. Only relevant in case 'CPR_CURL_USE_LIBPSL' is set to ON." ${CPR_USE_SYSTEM_CURL}) +cpr_option(CPR_ENABLE_CURL_HTTP_ONLY "If enabled we will only use the HTTP/HTTPS protocols from CURL. If disabled, all the CURL protocols are enabled. This is useful if your project uses libcurl and you need support for other CURL features e.g. sending emails." ON) +cpr_option(CPR_ENABLE_SSL "Enables or disables the SSL backend. Required to perform HTTPS requests." ON) +cpr_option(CPR_FORCE_OPENSSL_BACKEND "Force to use the OpenSSL 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_FORCE_WINSSL_BACKEND "Force to use the WinSSL 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_FORCE_DARWINSSL_BACKEND "Force to use the DarwinSSL 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_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) +cpr_option(CPR_BUILD_VERSION_OUTPUT_ONLY "Set to ON to only export the version into 'build/version.txt' and exit" OFF) +cpr_option(CPR_SKIP_CA_BUNDLE_SEARCH "Skip searching for Certificate Authority certs. Turn ON for systems like iOS where file access is restricted and prevents https from working." OFF) +cpr_option(CPR_USE_BOOST_FILESYSTEM "Set to ON to use the Boost.Filesystem library. This is useful, on, e.g., Apple platforms, where std::filesystem may not always be available when targeting older OS versions." OFF) +cpr_option(CPR_DEBUG_SANITIZER_FLAG_THREAD "Enables the ThreadSanitizer for debug builds." OFF) +cpr_option(CPR_DEBUG_SANITIZER_FLAG_ADDR "Enables the AddressSanitizer for debug builds." OFF) +cpr_option(CPR_DEBUG_SANITIZER_FLAG_LEAK "Enables the LeakSanitizer for debug builds." OFF) +cpr_option(CPR_DEBUG_SANITIZER_FLAG_UB "Enables the UndefinedBehaviorSanitizer for debug builds." OFF) +cpr_option(CPR_DEBUG_SANITIZER_FLAG_ALL "Enables all sanitizers for debug builds except the ThreadSanitizer since it is incompatible with the other sanitizers." OFF) +message(STATUS "=======================================================") + +# If we build cpr as C++20 module, we use `import std;`. This block enables it for different CMake versions. +if(CPR_BUILD_MODULES AND NOT CMAKE_EXPERIMENTAL_CXX_IMPORT_STD AND NOT CMAKE_CXX_MODULE_STD) + if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.30" AND CMAKE_VERSION VERSION_LESS "3.31") set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "0e5b6991-d74f-4b3d-a41c-cf096e0b2508") set(CMAKE_CXX_MODULE_STD 1) + elseif(CMAKE_VERSION VERSION_GREATER_EQUAL "3.31" AND CMAKE_VERSION VERSION_LESS "4.0") + set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "d0edc3af-4c50-42ea-a356-e2862fe7a444") + set(CMAKE_CXX_MODULE_STD 1) elseif(CMAKE_VERSION VERSION_GREATER_EQUAL "4.0" AND CMAKE_VERSION VERSION_LESS "4.0.3") set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "a9e1cf81-9932-4810-974b-6eccaf14e457") set(CMAKE_CXX_MODULE_STD 1) @@ -54,54 +106,6 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CPR_LIBRARIES cpr CACHE INTERNAL "") -macro(cpr_option OPTION_NAME OPTION_TEXT OPTION_DEFAULT) - option(${OPTION_NAME} ${OPTION_TEXT} ${OPTION_DEFAULT}) - - if(DEFINED ENV{${OPTION_NAME}}) - # Allow overriding the option through an environment variable - set(${OPTION_NAME} $ENV{${OPTION_NAME}}) - endif() - - if(${OPTION_NAME}) - add_definitions(-D${OPTION_NAME}) - endif() - - message(STATUS " ${OPTION_NAME}: ${${OPTION_NAME}}") -endmacro() - -message(STATUS "C++ Requests CMake Options") -message(STATUS "=======================================================") -cpr_option(CPR_ENABLE_INSTALL "Set to ON to enable all cpr install targets." ON) -cpr_option(CPR_GENERATE_COVERAGE "Set to ON to generate coverage reports." OFF) -cpr_option(CPR_CURL_NOSIGNAL "Set to ON to disable use of signals in libcurl." OFF) -cpr_option(CURL_VERBOSE_LOGGING "Curl verbose logging during building curl" OFF) -cpr_option(CPR_USE_SYSTEM_GTEST "If ON, this project will look in the system paths for an installed gtest library. If none is found it will use the built-in one." OFF) -cpr_option(CPR_USE_SYSTEM_CURL "If enabled we will use the curl lib already installed on this system." OFF) -cpr_option(CPR_USE_EXISTING_CURL_TARGET "Use an existing libcurl cmake target instead of having the cpr project source the dependency itself." OFF) -cpr_option(CPR_CURL_USE_LIBPSL "Since curl 8.13 curl depends on libpsl (https://everything.curl.dev/build/deps.html#libpsl). By default cpr keeps this as a secure default enabled wich in turn requires meson as build dependency. If set to OFF, psl support inside curl will be disabled." ON) -cpr_option(CPR_USE_SYSTEM_LIB_PSL "If enabled we will use the psl lib already installed on this system. Else meson is required as build dependency. Only relevant in case 'CPR_CURL_USE_LIBPSL' is set to ON." ${CPR_USE_SYSTEM_CURL}) -cpr_option(CPR_ENABLE_CURL_HTTP_ONLY "If enabled we will only use the HTTP/HTTPS protocols from CURL. If disabled, all the CURL protocols are enabled. This is useful if your project uses libcurl and you need support for other CURL features e.g. sending emails." ON) -cpr_option(CPR_ENABLE_SSL "Enables or disables the SSL backend. Required to perform HTTPS requests." ON) -cpr_option(CPR_FORCE_OPENSSL_BACKEND "Force to use the OpenSSL 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_FORCE_WINSSL_BACKEND "Force to use the WinSSL 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_FORCE_DARWINSSL_BACKEND "Force to use the DarwinSSL 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_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." ON) -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) -cpr_option(CPR_BUILD_VERSION_OUTPUT_ONLY "Set to ON to only export the version into 'build/version.txt' and exit" OFF) -cpr_option(CPR_SKIP_CA_BUNDLE_SEARCH "Skip searching for Certificate Authority certs. Turn ON for systems like iOS where file access is restricted and prevents https from working." OFF) -cpr_option(CPR_USE_BOOST_FILESYSTEM "Set to ON to use the Boost.Filesystem library. This is useful, on, e.g., Apple platforms, where std::filesystem may not always be available when targeting older OS versions." OFF) -cpr_option(CPR_DEBUG_SANITIZER_FLAG_THREAD "Enables the ThreadSanitizer for debug builds." OFF) -cpr_option(CPR_DEBUG_SANITIZER_FLAG_ADDR "Enables the AddressSanitizer for debug builds." OFF) -cpr_option(CPR_DEBUG_SANITIZER_FLAG_LEAK "Enables the LeakSanitizer for debug builds." OFF) -cpr_option(CPR_DEBUG_SANITIZER_FLAG_UB "Enables the UndefinedBehaviorSanitizer for debug builds." OFF) -cpr_option(CPR_DEBUG_SANITIZER_FLAG_ALL "Enables all sanitizers for debug builds except the ThreadSanitizer since it is incompatible with the other sanitizers." OFF) -message(STATUS "=======================================================") - if(MSVC) if(BUILD_SHARED_LIBS) message(STATUS "Build windows dynamic libs.") diff --git a/cmake/cprver.h.in b/cmake/cprver.h.in index 254046d4f..8ef539f90 100644 --- a/cmake/cprver.h.in +++ b/cmake/cprver.h.in @@ -2,8 +2,15 @@ #define CPR_CPRVER_H #include "cpr/export.h" + +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include #include +#endif /** * CPR version as a string. diff --git a/include/cpr/accept_encoding.h b/include/cpr/accept_encoding.h index c91276d99..fcd9059f8 100644 --- a/include/cpr/accept_encoding.h +++ b/include/cpr/accept_encoding.h @@ -3,13 +3,20 @@ #include "cpr/export.h" -#include -#include +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include #include #include -#include #include +#endif + +#include +#include +#include namespace cpr { diff --git a/include/cpr/api.h b/include/cpr/api.h index f9c49ac36..01b159dae 100644 --- a/include/cpr/api.h +++ b/include/cpr/api.h @@ -3,21 +3,21 @@ #include "cpr/export.h" +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include #include #include -#include #include +#endif #include "cpr/async.h" #include "cpr/async_wrapper.h" -#include "cpr/auth.h" -#include "cpr/bearer.h" #include "cpr/cprtypes.h" -#include "cpr/filesystem.h" -#include "cpr/multipart.h" #include "cpr/multiperform.h" -#include "cpr/payload.h" #include "cpr/response.h" #include "cpr/session.h" diff --git a/include/cpr/async_wrapper.h b/include/cpr/async_wrapper.h index eb5e145aa..14e364b5a 100644 --- a/include/cpr/async_wrapper.h +++ b/include/cpr/async_wrapper.h @@ -3,9 +3,15 @@ #include "cpr/export.h" +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include #include #include +#endif namespace cpr { EXPORT_CPR enum class [[nodiscard]] CancellationResult : uint8_t { failure, success, invalid_operation }; diff --git a/include/cpr/auth.h b/include/cpr/auth.h index 03e782272..fb6eb726f 100644 --- a/include/cpr/auth.h +++ b/include/cpr/auth.h @@ -3,11 +3,16 @@ #include "cpr/export.h" -#include -#include +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include +#endif #include "cpr/util.h" +#include namespace cpr { diff --git a/include/cpr/bearer.h b/include/cpr/bearer.h index 6d7211bd3..cf00db19c 100644 --- a/include/cpr/bearer.h +++ b/include/cpr/bearer.h @@ -3,12 +3,17 @@ #include "cpr/export.h" -#include +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include - #include +#endif #include "cpr/util.h" +#include namespace cpr { diff --git a/include/cpr/body.h b/include/cpr/body.h index 6fac5dea6..b88f56517 100644 --- a/include/cpr/body.h +++ b/include/cpr/body.h @@ -3,10 +3,15 @@ #include "cpr/export.h" -#include +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include #include #include +#endif #include "cpr/buffer.h" #include "cpr/cprtypes.h" diff --git a/include/cpr/body_view.h b/include/cpr/body_view.h index 18bf9f780..81562bdeb 100644 --- a/include/cpr/body_view.h +++ b/include/cpr/body_view.h @@ -3,7 +3,13 @@ #include "cpr/export.h" +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include +#endif #include "cpr/buffer.h" diff --git a/include/cpr/buffer.h b/include/cpr/buffer.h index 354db1352..4136346bb 100644 --- a/include/cpr/buffer.h +++ b/include/cpr/buffer.h @@ -3,9 +3,8 @@ #include "cpr/export.h" -#include - #include "cpr/filesystem.h" +#include namespace cpr { diff --git a/include/cpr/callback.h b/include/cpr/callback.h index cade08722..4f25980fc 100644 --- a/include/cpr/callback.h +++ b/include/cpr/callback.h @@ -3,14 +3,20 @@ #include "cpr/export.h" -#include "cprtypes.h" - +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include -#include #include #include #include #include +#endif + +#include "cprtypes.h" +#include namespace cpr { diff --git a/include/cpr/cert_info.h b/include/cpr/cert_info.h index dcfb1b960..7cf62a1ea 100644 --- a/include/cpr/cert_info.h +++ b/include/cpr/cert_info.h @@ -3,9 +3,15 @@ #include "cpr/export.h" +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include #include #include +#endif namespace cpr { diff --git a/include/cpr/connection_pool.h b/include/cpr/connection_pool.h index fc5f07592..0453147fd 100644 --- a/include/cpr/connection_pool.h +++ b/include/cpr/connection_pool.h @@ -3,9 +3,16 @@ #include "cpr/export.h" -#include +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include #include +#endif + +#include namespace cpr { /** diff --git a/include/cpr/cookies.h b/include/cpr/cookies.h index 9c664f402..3b6ebea2b 100644 --- a/include/cpr/cookies.h +++ b/include/cpr/cookies.h @@ -3,11 +3,18 @@ #include "cpr/export.h" -#include "cpr/curlholder.h" +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include #include #include #include +#endif + +#include "cpr/curlholder.h" namespace cpr { /** diff --git a/include/cpr/cprtypes.h b/include/cpr/cprtypes.h index 70f83ab47..0c5558224 100644 --- a/include/cpr/cprtypes.h +++ b/include/cpr/cprtypes.h @@ -3,13 +3,20 @@ #include "cpr/export.h" -#include -#include +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include #include #include #include #include +#endif + +#include +#include namespace cpr { diff --git a/include/cpr/curl_container.h b/include/cpr/curl_container.h index e6b7a2755..652133e01 100644 --- a/include/cpr/curl_container.h +++ b/include/cpr/curl_container.h @@ -3,10 +3,15 @@ #include "cpr/export.h" +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include -#include #include #include +#endif #include "cpr/curlholder.h" diff --git a/include/cpr/curlholder.h b/include/cpr/curlholder.h index e1f8635cc..fab4e12c9 100644 --- a/include/cpr/curlholder.h +++ b/include/cpr/curlholder.h @@ -3,11 +3,17 @@ #include "cpr/export.h" +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include -#include #include +#endif #include "cpr/secure_string.h" +#include namespace cpr { diff --git a/include/cpr/error.h b/include/cpr/error.h index 826b8d537..6c7f9196c 100644 --- a/include/cpr/error.h +++ b/include/cpr/error.h @@ -3,12 +3,18 @@ #include "cpr/export.h" -#include +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include #include +#include +#endif #include "cpr/cprtypes.h" -#include +#include namespace cpr { diff --git a/include/cpr/file.h b/include/cpr/file.h index a8e808de2..66dba9560 100644 --- a/include/cpr/file.h +++ b/include/cpr/file.h @@ -3,9 +3,15 @@ #include "cpr/export.h" +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include #include #include +#endif #include "cpr/filesystem.h" diff --git a/include/cpr/filesystem.h b/include/cpr/filesystem.h index 8a3bdafe0..10bfed0b6 100644 --- a/include/cpr/filesystem.h +++ b/include/cpr/filesystem.h @@ -8,14 +8,26 @@ namespace cpr { namespace fs = boost::filesystem; } +#elif defined(CPR_IMPORT_STD) +namespace cpr { +namespace fs = std::filesystem; +} // namespace cpr // cppcheck-suppress preprocessorErrorDirective #elif __has_include() +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include +#endif namespace cpr { namespace fs = std::filesystem; } // namespace cpr #elif __has_include("experimental/filesystem") +#ifndef CPR_IMPORT_STD #include +#endif namespace cpr { namespace fs = std::experimental::filesystem; } diff --git a/include/cpr/interceptor.h b/include/cpr/interceptor.h index 700f6ff9d..55db50859 100644 --- a/include/cpr/interceptor.h +++ b/include/cpr/interceptor.h @@ -3,10 +3,17 @@ #include "cpr/export.h" +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD +#include +#endif + #include "cpr/multiperform.h" #include "cpr/response.h" #include "cpr/session.h" -#include namespace cpr { EXPORT_CPR class Interceptor { diff --git a/include/cpr/interface.h b/include/cpr/interface.h index 615044ff9..cbf3b5750 100644 --- a/include/cpr/interface.h +++ b/include/cpr/interface.h @@ -3,8 +3,14 @@ #include "cpr/export.h" +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include #include +#endif #include "cpr/cprtypes.h" diff --git a/include/cpr/low_speed.h b/include/cpr/low_speed.h index 5dac5f106..643f5eea3 100644 --- a/include/cpr/low_speed.h +++ b/include/cpr/low_speed.h @@ -3,7 +3,14 @@ #include "cpr/export.h" +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include +#endif + #include namespace cpr { diff --git a/include/cpr/multipart.h b/include/cpr/multipart.h index f4189dfb5..4c72a1b37 100644 --- a/include/cpr/multipart.h +++ b/include/cpr/multipart.h @@ -3,14 +3,19 @@ #include "cpr/export.h" -#include +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include #include -#include #include +#endif #include "buffer.h" #include "file.h" +#include namespace cpr { diff --git a/include/cpr/multiperform.h b/include/cpr/multiperform.h index c6c1729f9..e989503bf 100644 --- a/include/cpr/multiperform.h +++ b/include/cpr/multiperform.h @@ -3,14 +3,20 @@ #include "cpr/export.h" -#include "cpr/curlmultiholder.h" -#include "cpr/response.h" -#include "cpr/session.h" +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include #include -#include #include #include +#endif + +#include "cpr/curlmultiholder.h" +#include "cpr/response.h" +#include "cpr/session.h" namespace cpr { diff --git a/include/cpr/parameters.h b/include/cpr/parameters.h index 5f2ae1f95..624dae22c 100644 --- a/include/cpr/parameters.h +++ b/include/cpr/parameters.h @@ -3,7 +3,13 @@ #include "cpr/export.h" +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include +#endif #include "cpr/curl_container.h" diff --git a/include/cpr/payload.h b/include/cpr/payload.h index c657462c2..023048f5a 100644 --- a/include/cpr/payload.h +++ b/include/cpr/payload.h @@ -3,7 +3,13 @@ #include "cpr/export.h" +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include +#endif #include "cpr/curl_container.h" diff --git a/include/cpr/proxies.h b/include/cpr/proxies.h index 80a57f917..9d83d1db2 100644 --- a/include/cpr/proxies.h +++ b/include/cpr/proxies.h @@ -3,9 +3,15 @@ #include "cpr/export.h" +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include #include #include +#endif namespace cpr { EXPORT_CPR class Proxies { diff --git a/include/cpr/proxyauth.h b/include/cpr/proxyauth.h index 295504f57..92d8d0e6e 100644 --- a/include/cpr/proxyauth.h +++ b/include/cpr/proxyauth.h @@ -3,10 +3,16 @@ #include "cpr/export.h" +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include #include #include #include +#endif #include "cpr/auth.h" #include "cpr/util.h" diff --git a/include/cpr/range.h b/include/cpr/range.h index 721bcf42b..8bea2e931 100644 --- a/include/cpr/range.h +++ b/include/cpr/range.h @@ -3,10 +3,17 @@ #include "cpr/export.h" -#include +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include #include #include +#endif + +#include namespace cpr { diff --git a/include/cpr/resolve.h b/include/cpr/resolve.h index 6ba2c4ea2..a30630a87 100644 --- a/include/cpr/resolve.h +++ b/include/cpr/resolve.h @@ -3,9 +3,16 @@ #include "cpr/export.h" -#include +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include #include +#endif + +#include namespace cpr { EXPORT_CPR class Resolve { diff --git a/include/cpr/response.h b/include/cpr/response.h index 7d961d12e..0ec1ecdda 100644 --- a/include/cpr/response.h +++ b/include/cpr/response.h @@ -3,12 +3,16 @@ #include "cpr/export.h" -#include -#include +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include #include #include #include +#endif #include "cpr/cert_info.h" #include "cpr/cookies.h" @@ -16,6 +20,8 @@ #include "cpr/error.h" #include "cpr/ssl_options.h" #include "cpr/util.h" +#include +#include namespace cpr { diff --git a/include/cpr/secure_string.h b/include/cpr/secure_string.h index bc2013286..681219c08 100644 --- a/include/cpr/secure_string.h +++ b/include/cpr/secure_string.h @@ -3,9 +3,14 @@ #include "cpr/export.h" +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include #include -#include +#endif namespace cpr::util { diff --git a/include/cpr/session.h b/include/cpr/session.h index a50957eb1..e099c7f41 100644 --- a/include/cpr/session.h +++ b/include/cpr/session.h @@ -3,14 +3,17 @@ #include "cpr/export.h" -#include +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include -#include -#include #include #include #include #include +#endif #include "cpr/accept_encoding.h" #include "cpr/async_wrapper.h" @@ -45,7 +48,6 @@ #include "cpr/timeout.h" #include "cpr/unix_socket.h" #include "cpr/user_agent.h" -#include "cpr/util.h" #include "cpr/verbose.h" namespace cpr { diff --git a/include/cpr/singleton.h b/include/cpr/singleton.h index ccff28483..17f39af63 100644 --- a/include/cpr/singleton.h +++ b/include/cpr/singleton.h @@ -2,7 +2,6 @@ #define CPR_SINGLETON_H #include -#include // NOLINTBEGIN(cppcoreguidelines-macro-usage, bugprone-macro-parentheses) diff --git a/include/cpr/sse.h b/include/cpr/sse.h index ad6c8780e..73ac32129 100644 --- a/include/cpr/sse.h +++ b/include/cpr/sse.h @@ -3,12 +3,19 @@ #include "cpr/export.h" -#include +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include #include #include #include #include +#endif + +#include namespace cpr { diff --git a/include/cpr/ssl_options.h b/include/cpr/ssl_options.h index 25efb68bf..085f68d7c 100644 --- a/include/cpr/ssl_options.h +++ b/include/cpr/ssl_options.h @@ -3,16 +3,18 @@ #include "cpr/export.h" -#include +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include -#include +#include +#endif #include "cpr/filesystem.h" -#include - #include "cpr/util.h" -#include "util.h" -#include +#include #ifndef SUPPORT_ALPN #define SUPPORT_ALPN LIBCURL_VERSION_NUM >= 0x072400 // 7.36.0 diff --git a/include/cpr/threadpool.h b/include/cpr/threadpool.h index 27d8a2869..ac0e18aad 100644 --- a/include/cpr/threadpool.h +++ b/include/cpr/threadpool.h @@ -3,10 +3,14 @@ #include "cpr/export.h" +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include #include #include -#include #include #include #include @@ -15,6 +19,9 @@ #include #include #include +#endif + +#include #define CPR_DEFAULT_THREAD_POOL_MAX_THREAD_NUM std::thread::hardware_concurrency() diff --git a/include/cpr/timeout.h b/include/cpr/timeout.h index 2255404d4..3e68193a0 100644 --- a/include/cpr/timeout.h +++ b/include/cpr/timeout.h @@ -3,7 +3,14 @@ #include "cpr/export.h" +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include +#endif + #include namespace cpr { diff --git a/include/cpr/unix_socket.h b/include/cpr/unix_socket.h index 3bc1ca1ac..29eed5b07 100644 --- a/include/cpr/unix_socket.h +++ b/include/cpr/unix_socket.h @@ -3,7 +3,13 @@ #include "cpr/export.h" +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include +#endif namespace cpr { diff --git a/include/cpr/user_agent.h b/include/cpr/user_agent.h index 09a2e4c3a..e6eaa9341 100644 --- a/include/cpr/user_agent.h +++ b/include/cpr/user_agent.h @@ -3,8 +3,14 @@ #include "cpr/export.h" +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include #include +#endif #include "cpr/cprtypes.h" diff --git a/include/cpr/util.h b/include/cpr/util.h index 99e0e9601..2ad9cd332 100644 --- a/include/cpr/util.h +++ b/include/cpr/util.h @@ -3,10 +3,15 @@ #include "cpr/export.h" +/** + * If we build cpr as C++20 module, we use 'import std;'. + * So skip all other imports and declare them in 'cpr.cxx'. + **/ +#ifndef CPR_IMPORT_STD #include -#include #include #include +#endif #include "cpr/callback.h" #include "cpr/cookies.h" diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt index 1dd9f0d9e..f05b3c6bb 100644 --- a/modules/CMakeLists.txt +++ b/modules/CMakeLists.txt @@ -28,7 +28,8 @@ target_sources(cpr_module cpr.cxx ) -target_compile_features(cpr_module PRIVATE cxx_std_23 INTERFACE cxx_std_20) +target_compile_features(cpr_module PUBLIC cxx_std_23) +set_target_properties(cpr_module PROPERTIES CXX_MODULE_STD ON) target_include_directories(cpr_module PUBLIC $ diff --git a/modules/cpr.cxx b/modules/cpr.cxx index 4c906f69a..ded60e92d 100644 --- a/modules/cpr.cxx +++ b/modules/cpr.cxx @@ -1,10 +1,25 @@ module; -import std; +#include +#include +#include +#include +#include +#include +#include +#ifdef CPR_USE_BOOST_FILESYSTEM +#define BOOST_FILESYSTEM_VERSION 4 +#include +#endif export module cpr; +import std; + #define CPR_AS_MODULE 1 +#define CPR_IMPORT_STD 1 #define EXPORT_CPR export +extern "C++" { #include "cpr/cpr.h" +} From 093df41dfebaa950c61f52181a96d98d4911b6fe Mon Sep 17 00:00:00 2001 From: Fabian Sauter Date: Sun, 17 May 2026 13:23:47 +0200 Subject: [PATCH 6/9] Fixed version check test compilation --- test/version_tests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/version_tests.cpp b/test/version_tests.cpp index 5bf7ed003..78965dacc 100644 --- a/test/version_tests.cpp +++ b/test/version_tests.cpp @@ -13,7 +13,7 @@ TEST(VersionTests, StringVersionExists) { TEST(VersionTests, StringVersionValid) { EXPECT_TRUE(CPR_VERSION != nullptr); - std::string version = CPR_VERSION; + std::string version{CPR_VERSION}; // Check if the version string is: '\d+\.\d+\.\d+' bool digit = true; From 0768e326b9ec66296e899540c8fe329aa27e2443 Mon Sep 17 00:00:00 2001 From: Fabian Sauter Date: Sun, 17 May 2026 13:27:16 +0200 Subject: [PATCH 7/9] Further cpr version test fixes --- test/version_tests.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/test/version_tests.cpp b/test/version_tests.cpp index 78965dacc..113e3aca9 100644 --- a/test/version_tests.cpp +++ b/test/version_tests.cpp @@ -12,7 +12,6 @@ TEST(VersionTests, StringVersionExists) { } TEST(VersionTests, StringVersionValid) { - EXPECT_TRUE(CPR_VERSION != nullptr); std::string version{CPR_VERSION}; // Check if the version string is: '\d+\.\d+\.\d+' From cfa8462bd2b5772de6c5af3c8034f190369f52eb Mon Sep 17 00:00:00 2001 From: Fabian Sauter Date: Sun, 17 May 2026 13:46:45 +0200 Subject: [PATCH 8/9] Removed old version tests --- CMakeLists.txt | 36 ++++++++++++++++++++++-------------- test/version_tests.cpp | 31 ------------------------------- 2 files changed, 22 insertions(+), 45 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 142c7bf0b..45752382f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,22 +50,18 @@ message(STATUS "=======================================================") # If we build cpr as C++20 module, we use `import std;`. This block enables it for different CMake versions. if(CPR_BUILD_MODULES AND NOT CMAKE_EXPERIMENTAL_CXX_IMPORT_STD AND NOT CMAKE_CXX_MODULE_STD) - if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.30" AND CMAKE_VERSION VERSION_LESS "3.31") + if(CMAKE_VERSION VERSION_LESS "3.30") + message(FATAL_ERROR "CPR_BUILD_MODULES requires CMake 3.30 or newer for `import std` support (found ${CMAKE_VERSION}).") + elseif(CMAKE_VERSION VERSION_LESS_EQUAL "3.31.7") set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "0e5b6991-d74f-4b3d-a41c-cf096e0b2508") - set(CMAKE_CXX_MODULE_STD 1) - elseif(CMAKE_VERSION VERSION_GREATER_EQUAL "3.31" AND CMAKE_VERSION VERSION_LESS "4.0") + elseif(CMAKE_VERSION VERSION_LESS_EQUAL "4.2.3") set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "d0edc3af-4c50-42ea-a356-e2862fe7a444") - set(CMAKE_CXX_MODULE_STD 1) - elseif(CMAKE_VERSION VERSION_GREATER_EQUAL "4.0" AND CMAKE_VERSION VERSION_LESS "4.0.3") - set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "a9e1cf81-9932-4810-974b-6eccaf14e457") - set(CMAKE_CXX_MODULE_STD 1) - elseif(CMAKE_VERSION VERSION_GREATER_EQUAL "4.0.3" AND CMAKE_VERSION VERSION_LESS "4.3") - set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "d0edc3af-4c50-42ea-a356-e2862fe7a444") - set(CMAKE_CXX_MODULE_STD 1) - elseif(CMAKE_VERSION VERSION_GREATER_EQUAL "4.3") + elseif(CMAKE_VERSION VERSION_LESS_EQUAL "4.3.4") set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "451f2fe2-a8a2-47c3-bc32-94786d8fc91b") - set(CMAKE_CXX_MODULE_STD 1) + else() + set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "f35a9ac6-8463-4d38-8eec-5d6008153e7d") endif() + set(CMAKE_CXX_MODULE_STD 1) endif() project(cpr VERSION 1.15.0 LANGUAGES CXX) @@ -96,9 +92,21 @@ if(PARENT_CXX_STANDARD) if(PARENT_CXX_STANDARD LESS 17) message(FATAL_ERROR "cpr ${cpr_VERSION} does not support ${PARENT_CXX_STANDARD}. Please use cpr <= 1.9.x") endif() + # `import std;` requires C++23, so we cannot honour a lower standard from the parent project here. + if(CPR_BUILD_MODULES AND PARENT_CXX_STANDARD LESS 23) + message(FATAL_ERROR "CPR_BUILD_MODULES requires C++23 or newer, but the parent project requests C++${PARENT_CXX_STANDARD}.") + endif() else() - # Set standard version if not already set by potential parent project - set(CMAKE_CXX_STANDARD 17) + # Set standard version if not already set by potential parent project. + # `import std;` requires C++23, so raise the default for module builds without + # downgrading an explicitly requested higher standard. + if(CPR_BUILD_MODULES) + if(NOT CMAKE_CXX_STANDARD OR CMAKE_CXX_STANDARD LESS 23) + set(CMAKE_CXX_STANDARD 23) + endif() + else() + set(CMAKE_CXX_STANDARD 17) + endif() endif() message(STATUS "CXX standard: ${CMAKE_CXX_STANDARD}") diff --git a/test/version_tests.cpp b/test/version_tests.cpp index 113e3aca9..3aff950e5 100644 --- a/test/version_tests.cpp +++ b/test/version_tests.cpp @@ -5,12 +5,6 @@ #include -TEST(VersionTests, StringVersionExists) { -#ifndef CPR_VERSION - EXPECT_TRUE(false); -#endif // CPR_VERSION -} - TEST(VersionTests, StringVersionValid) { std::string version{CPR_VERSION}; @@ -33,31 +27,6 @@ TEST(VersionTests, StringVersionValid) { EXPECT_EQ(dotCount, 2); } -TEST(VersionTests, VersionMajorExists) { -#ifndef CPR_VERSION_MAJOR - EXPECT_TRUE(false); -#endif // CPR_VERSION_MAJOR -} - -TEST(VersionTests, VersionMinorExists) { -#ifndef CPR_VERSION_MINOR - EXPECT_TRUE(false); -#endif // CPR_VERSION_MINOR -} - -TEST(VersionTests, VersionPatchExists) { -#ifndef CPR_VERSION_PATCH - EXPECT_TRUE(false); -#endif // CPR_VERSION_PATCH -} - -TEST(VersionTests, VersionNumExists) { -#ifndef CPR_VERSION_NUM - EXPECT_TRUE(false); -#endif // CPR_VERSION_NUM -} - - int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); From d333f251702bf0147657ac8fd160601356535cbc Mon Sep 17 00:00:00 2001 From: Toyosatomimi no Miko <110693261+mikomikotaishi@users.noreply.github.com> Date: Sun, 23 Aug 2026 14:25:26 -0400 Subject: [PATCH 9/9] Disable CMAKE_CXX_MODULE_STD to prevent passing onto dependencies --- .github/workflows/modules-ci.yml | 4 ++++ CMakeLists.txt | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/modules-ci.yml b/.github/workflows/modules-ci.yml index 6d98b9131..dd11346e5 100644 --- a/.github/workflows/modules-ci.yml +++ b/.github/workflows/modules-ci.yml @@ -140,6 +140,10 @@ jobs: macos-clang-modules: runs-on: macos-latest + # Homebrew's clang++ still uses the macOS system libc++, which ships no + # 'libc++.modules.json', so 'import std' cannot be resolved there yet. + # Keep the job visible without blocking the branch until that is sorted out. + continue-on-error: true steps: - name: Install Dependencies run: | diff --git a/CMakeLists.txt b/CMakeLists.txt index 45752382f..40f88bf53 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,7 +61,10 @@ if(CPR_BUILD_MODULES AND NOT CMAKE_EXPERIMENTAL_CXX_IMPORT_STD AND NOT CMAKE_CXX else() set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "f35a9ac6-8463-4d38-8eec-5d6008153e7d") endif() - set(CMAKE_CXX_MODULE_STD 1) + # Deliberately NOT setting CMAKE_CXX_MODULE_STD here: as a directory-scope variable it + # initialises the CXX_MODULE_STD property on *every* target created afterwards, including + # FetchContent dependencies (zlib, curl, googletest), which then demand C++ standard library + # module metadata they neither use nor ship. `cpr_module` opts in via its own target property. endif() project(cpr VERSION 1.15.0 LANGUAGES CXX)