From 3ff5ee9b6035db14d8509e2400e4a5b83841ac64 Mon Sep 17 00:00:00 2001 From: Ansh-Karnwal <78387773+Ansh-Karnwal@users.noreply.github.com> Date: Wed, 15 Jul 2026 01:23:38 -0700 Subject: [PATCH 1/3] fix(server): build cpprestsdk against libc++ >= 16 via overlay port The vendored cpprestsdk (archived by Microsoft, frozen at 2.10.19) uses std::basic_string in Value2StringFormatter (cpprest/streams.h), which requires std::char_traits. libc++ 16 removed that non-standard specialization, so the engine link fails on any modern-libc++ host (Fedora 40+, Ubuntu 24.04, clang/libc++ 16-22) with: error: implicit instantiation of undefined template 'std::char_traits' Add a vcpkg overlay port for cpprestsdk (a copy of the stock vcpkg 2026.04.27 port and its patch set) with one extra patch that reintroduces a minimal, standard-conforming std::char_traits in astreambuf.h. It is guarded by _LIBCPP_VERSION >= 160000 so it stays a no-op on libstdc++ and on libc++ < 16, which still ship the extension, and cannot cause a redefinition there. Fixes #1438. --- .../server/cmake/ports/cpprestsdk/README.md | 22 ++ .../ports/cpprestsdk/fix-asio-error.patch | 367 ++++++++++++++++++ .../cpprestsdk/fix-clang-dllimport.patch | 52 +++ .../ports/cpprestsdk/fix-find-openssl.patch | 18 + .../cpprestsdk/fix-libcxx16-char-traits.patch | 70 ++++ .../cmake/ports/cpprestsdk/fix-uwp.patch | 28 ++ .../ports/cpprestsdk/fix_narrowing.patch | 50 +++ .../cmake/ports/cpprestsdk/portfile.cmake | 55 +++ ...dext-checked-array-iterators-warning.patch | 12 + .../server/cmake/ports/cpprestsdk/vcpkg.json | 85 ++++ 10 files changed, 759 insertions(+) create mode 100644 packages/server/cmake/ports/cpprestsdk/README.md create mode 100644 packages/server/cmake/ports/cpprestsdk/fix-asio-error.patch create mode 100644 packages/server/cmake/ports/cpprestsdk/fix-clang-dllimport.patch create mode 100644 packages/server/cmake/ports/cpprestsdk/fix-find-openssl.patch create mode 100644 packages/server/cmake/ports/cpprestsdk/fix-libcxx16-char-traits.patch create mode 100644 packages/server/cmake/ports/cpprestsdk/fix-uwp.patch create mode 100644 packages/server/cmake/ports/cpprestsdk/fix_narrowing.patch create mode 100644 packages/server/cmake/ports/cpprestsdk/portfile.cmake create mode 100644 packages/server/cmake/ports/cpprestsdk/silence-stdext-checked-array-iterators-warning.patch create mode 100644 packages/server/cmake/ports/cpprestsdk/vcpkg.json diff --git a/packages/server/cmake/ports/cpprestsdk/README.md b/packages/server/cmake/ports/cpprestsdk/README.md new file mode 100644 index 000000000..e49e9e5b2 --- /dev/null +++ b/packages/server/cmake/ports/cpprestsdk/README.md @@ -0,0 +1,22 @@ +This is a vcpkg overlay port for `cpprestsdk`. + +It is a copy of the upstream vcpkg port (vcpkg `2026.04.27`, cpprestsdk `2.10.19`, +commit `411a109`) with one extra patch, `fix-libcxx16-char-traits.patch`, layered +on top of the stock patch set. + +Why it exists: `cpprestsdk` was archived by Microsoft in 2022 and its +`Value2StringFormatter` (`Release/include/cpprest/streams.h`) uses +`std::basic_string`, which needs `std::char_traits`. +libc++ 16 removed that non-standard specialization, so the engine fails to link +against any modern libc++ (Fedora 40+, Ubuntu 24.04, clang/libc++ 16-22). See +issue RR-1438. + +The patch reintroduces a minimal, standard-conforming `std::char_traits` +in `astreambuf.h`, guarded by `_LIBCPP_VERSION >= 160000` so it is a no-op on +libstdc++ and on libc++ < 16 (which still ship the extension) and does not cause +a redefinition there. + +When bumping the pinned vcpkg version, re-sync `portfile.cmake`, `vcpkg.json`, and +the stock `.patch` files from upstream and re-verify this patch still applies. +Longer term this port can be dropped once the engine migrates off `cpprestsdk` +(see RR-1468). diff --git a/packages/server/cmake/ports/cpprestsdk/fix-asio-error.patch b/packages/server/cmake/ports/cpprestsdk/fix-asio-error.patch new file mode 100644 index 000000000..dcc5052ef --- /dev/null +++ b/packages/server/cmake/ports/cpprestsdk/fix-asio-error.patch @@ -0,0 +1,367 @@ +diff --git a/Release/include/pplx/threadpool.h b/Release/include/pplx/threadpool.h +index b297ff6..56ea475 100644 +--- a/Release/include/pplx/threadpool.h ++++ b/Release/include/pplx/threadpool.h +@@ -69,15 +69,15 @@ public: + CASABLANCA_DEPRECATED("Use `.service().post(task)` directly.") + void schedule(T task) + { +- service().post(task); ++ boost::asio::post(service(), task); + } + +- boost::asio::io_service& service() { return m_service; } ++ boost::asio::io_context& service() { return m_service; } + + protected: + threadpool(size_t num_threads) : m_service(static_cast(num_threads)) {} + +- boost::asio::io_service m_service; ++ boost::asio::io_context m_service; + }; + + } // namespace crossplat +diff --git a/Release/src/http/client/http_client_asio.cpp b/Release/src/http/client/http_client_asio.cpp +index 07bb488..f9c7c51 100644 +--- a/Release/src/http/client/http_client_asio.cpp ++++ b/Release/src/http/client/http_client_asio.cpp +@@ -146,9 +146,9 @@ class asio_connection + friend class asio_client; + + public: +- asio_connection(boost::asio::io_service& io_service) ++ asio_connection(boost::asio::io_context& io_context) + : m_socket_lock() +- , m_socket(io_service) ++ , m_socket(io_context) + , m_ssl_stream() + , m_cn_hostname() + , m_is_reused(false) +@@ -429,7 +429,7 @@ private: + auto& self = *pool; + std::weak_ptr weak_pool = pool; + +- self.m_pool_epoch_timer.expires_from_now(boost::posix_time::seconds(30)); ++ self.m_pool_epoch_timer.expires_after(std::chrono::seconds(30)); + self.m_pool_epoch_timer.async_wait([weak_pool](const boost::system::error_code& ec) { + if (ec) + { +@@ -467,7 +467,7 @@ private: + std::mutex m_lock; + std::map> m_connections; + bool m_is_timer_running; +- boost::asio::deadline_timer m_pool_epoch_timer; ++ boost::asio::system_timer m_pool_epoch_timer; + }; + + class asio_client final : public _http_client_communicator +@@ -581,18 +581,16 @@ public: + + m_context->m_timer.start(); + +- tcp::resolver::query query(utility::conversions::to_utf8string(proxy_host), to_string(proxy_port)); +- + auto client = std::static_pointer_cast(m_context->m_http_client); +- m_context->m_resolver.async_resolve(query, +- boost::bind(&ssl_proxy_tunnel::handle_resolve, +- shared_from_this(), +- boost::asio::placeholders::error, +- boost::asio::placeholders::iterator)); ++ m_context->m_resolver.async_resolve(utility::conversions::to_utf8string(proxy_host), to_string(proxy_port), ++ [self = shared_from_this()](const boost::system::error_code& error, tcp::resolver::results_type results){ ++ self->handle_resolve(error, results.begin()); ++ } ++ ); + } + + private: +- void handle_resolve(const boost::system::error_code& ec, tcp::resolver::iterator endpoints) ++ void handle_resolve(const boost::system::error_code& ec, tcp::resolver::results_type::iterator endpoints) + { + if (ec) + { +@@ -610,7 +608,7 @@ public: + } + } + +- void handle_tcp_connect(const boost::system::error_code& ec, tcp::resolver::iterator endpoints) ++ void handle_tcp_connect(const boost::system::error_code& ec, tcp::resolver::results_type::iterator endpoints) + { + if (!ec) + { +@@ -621,7 +619,7 @@ public: + shared_from_this(), + boost::asio::placeholders::error)); + } +- else if (endpoints == tcp::resolver::iterator()) ++ else if (endpoints == tcp::resolver::results_type::iterator()) + { + m_context->report_error( + "Failed to connect to any resolved proxy endpoint", ec, httpclient_errorcode_context::connect); +@@ -885,12 +883,11 @@ public: + auto tcp_host = proxy_type == http_proxy_type::http ? proxy_host : host; + auto tcp_port = proxy_type == http_proxy_type::http ? proxy_port : port; + +- tcp::resolver::query query(tcp_host, to_string(tcp_port)); +- ctx->m_resolver.async_resolve(query, +- boost::bind(&asio_context::handle_resolve, +- ctx, +- boost::asio::placeholders::error, +- boost::asio::placeholders::iterator)); ++ ctx->m_resolver.async_resolve(tcp_host, to_string(tcp_port), ++ [ctx](const boost::system::error_code& error, tcp::resolver::results_type results){ ++ ctx->handle_resolve(error, results.begin()); ++ } ++ ); + } + + // Register for notification on cancellation to abort this request. +@@ -1006,7 +1003,7 @@ private: + request_context::report_error(errorcodeValue, message); + } + +- void handle_connect(const boost::system::error_code& ec, tcp::resolver::iterator endpoints) ++ void handle_connect(const boost::system::error_code& ec, tcp::resolver::results_type::iterator endpoints) + { + m_timer.reset(); + if (!ec) +@@ -1019,7 +1016,7 @@ private: + { + report_error("Request canceled by user.", ec, httpclient_errorcode_context::connect); + } +- else if (endpoints == tcp::resolver::iterator()) ++ else if (endpoints == tcp::resolver::results_type::iterator()) + { + report_error("Failed to connect to any resolved endpoint", ec, httpclient_errorcode_context::connect); + } +@@ -1045,13 +1042,13 @@ private: + } + } + +- void handle_resolve(const boost::system::error_code& ec, tcp::resolver::iterator endpoints) ++ void handle_resolve(const boost::system::error_code& ec, tcp::resolver::results_type::iterator endpoints) + { + if (ec) + { + report_error("Error resolving address", ec, httpclient_errorcode_context::connect); + } +- else if (endpoints == tcp::resolver::iterator()) ++ else if (endpoints == tcp::resolver::results_type::iterator()) + { + report_error("Failed to resolve address", ec, httpclient_errorcode_context::connect); + } +@@ -1134,7 +1131,7 @@ private: + } + #endif // CPPREST_PLATFORM_ASIO_CERT_VERIFICATION_AVAILABLE + +- boost::asio::ssl::rfc2818_verification rfc2818(m_connection->cn_hostname()); ++ boost::asio::ssl::host_name_verification rfc2818(m_connection->cn_hostname()); + return rfc2818(preverified, verifyCtx); + } + +@@ -1182,8 +1179,8 @@ private: + + const auto& chunkSize = m_http_client->client_config().chunksize(); + auto readbuf = _get_readbuffer(); +- uint8_t* buf = boost::asio::buffer_cast( +- m_body_buf.prepare(chunkSize + http::details::chunked_encoding::additional_encoding_space)); ++ uint8_t* buf = static_cast( ++ m_body_buf.prepare(chunkSize + http::details::chunked_encoding::additional_encoding_space).data()); + const auto this_request = shared_from_this(); + readbuf.getn(buf + http::details::chunked_encoding::data_offset, chunkSize) + .then([this_request, buf, chunkSize AND_CAPTURE_MEMBER_FUNCTION_POINTERS](pplx::task op) { +@@ -1247,7 +1244,7 @@ private: + const auto readSize = static_cast((std::min)( + static_cast(m_http_client->client_config().chunksize()), m_content_length - m_uploaded)); + auto readbuf = _get_readbuffer(); +- readbuf.getn(boost::asio::buffer_cast(m_body_buf.prepare(readSize)), readSize) ++ readbuf.getn(static_cast(m_body_buf.prepare(readSize).data()), readSize) + .then([this_request AND_CAPTURE_MEMBER_FUNCTION_POINTERS](pplx::task op) { + try + { +@@ -1639,7 +1636,7 @@ private: + std::vector decompressed; + + bool boo = +- decompress(boost::asio::buffer_cast(m_body_buf.data()), to_read, decompressed); ++ decompress(static_cast(m_body_buf.data().data()), to_read, decompressed); + if (!boo) + { + report_exception(std::runtime_error("Failed to decompress the response body")); +@@ -1687,7 +1684,7 @@ private: + } + else + { +- writeBuffer.putn_nocopy(boost::asio::buffer_cast(m_body_buf.data()), to_read) ++ writeBuffer.putn_nocopy(static_cast(m_body_buf.data().data()), to_read) + .then([this_request, to_read AND_CAPTURE_MEMBER_FUNCTION_POINTERS](pplx::task op) { + try + { +@@ -1759,7 +1756,7 @@ private: + std::vector decompressed; + + bool boo = +- decompress(boost::asio::buffer_cast(m_body_buf.data()), read_size, decompressed); ++ decompress(static_cast(m_body_buf.data().data()), read_size, decompressed); + if (!boo) + { + this_request->report_exception(std::runtime_error("Failed to decompress the response body")); +@@ -1821,7 +1818,7 @@ private: + } + else + { +- writeBuffer.putn_nocopy(boost::asio::buffer_cast(m_body_buf.data()), read_size) ++ writeBuffer.putn_nocopy(static_cast(m_body_buf.data().data()), read_size) + .then([this_request AND_CAPTURE_MEMBER_FUNCTION_POINTERS](pplx::task op) { + size_t writtenSize = 0; + try +@@ -1870,7 +1867,7 @@ private: + assert(!m_ctx.expired()); + m_state = started; + +- m_timer.expires_from_now(m_duration); ++ m_timer.expires_after(m_duration); + auto ctx = m_ctx; + m_timer.async_wait([ctx AND_CAPTURE_MEMBER_FUNCTION_POINTERS](const boost::system::error_code& ec) { + handle_timeout(ec, ctx); +@@ -1881,7 +1878,7 @@ private: + { + assert(m_state == started || m_state == timedout); + assert(!m_ctx.expired()); +- if (m_timer.expires_from_now(m_duration) > 0) ++ if (m_timer.expires_after(m_duration) > 0) + { + // The existing handler was canceled so schedule a new one. + assert(m_state == started); +diff --git a/Release/src/http/client/x509_cert_utilities.cpp b/Release/src/http/client/x509_cert_utilities.cpp +index 67fc5ac..7239f97 100644 +--- a/Release/src/http/client/x509_cert_utilities.cpp ++++ b/Release/src/http/client/x509_cert_utilities.cpp +@@ -95,7 +95,7 @@ bool verify_cert_chain_platform_specific(boost::asio::ssl::verify_context& verif + #if defined(_WIN32) + if (verify_result) + { +- boost::asio::ssl::rfc2818_verification rfc2818(hostName); ++ boost::asio::ssl::host_name_verification rfc2818(hostName); + verify_result = rfc2818(verify_result, verifyCtx); + } + #endif +diff --git a/Release/src/http/listener/http_server_asio.cpp b/Release/src/http/listener/http_server_asio.cpp +index e83b9ff..14aadfb 100644 +--- a/Release/src/http/listener/http_server_asio.cpp ++++ b/Release/src/http/listener/http_server_asio.cpp +@@ -520,17 +520,14 @@ void hostport_listener::start() + auto& service = crossplat::threadpool::shared_instance().service(); + tcp::resolver resolver(service); + // #446: boost resolver does not recognize "+" as a host wildchar +- tcp::resolver::query query = +- ("+" == m_host) ? tcp::resolver::query(m_port, boost::asio::ip::resolver_query_base::flags()) +- : tcp::resolver::query(m_host, m_port, boost::asio::ip::resolver_query_base::flags()); +- +- tcp::endpoint endpoint = *resolver.resolve(query); +- ++ auto host = ("+" == m_host) ? "" : m_host; ++ auto results = resolver.resolve(host, m_port, boost::asio::ip::resolver_query_base::flags()); ++ tcp::endpoint endpoint = *results.begin(); + m_acceptor.reset(new tcp::acceptor(service)); + m_acceptor->open(endpoint.protocol()); + m_acceptor->set_option(socket_base::reuse_address(true)); + m_acceptor->bind(endpoint); +- m_acceptor->listen(0 != m_backlog ? m_backlog : socket_base::max_connections); ++ m_acceptor->listen(0 != m_backlog ? m_backlog : socket_base::max_listen_connections); + + auto socket = new ip::tcp::socket(service); + std::unique_ptr usocket(socket); +@@ -881,7 +878,7 @@ will_deref_t asio_server_connection::handle_chunked_body(const boost::system::er + else + { + auto writebuf = requestImpl->outstream().streambuf(); +- writebuf.putn_nocopy(buffer_cast(m_request_buf.data()), toWrite) ++ writebuf.putn_nocopy(static_cast(m_request_buf.data().data()), toWrite) + .then([=](pplx::task writeChunkTask) -> will_deref_t { + try + { +@@ -913,7 +910,7 @@ will_deref_t asio_server_connection::handle_body(const boost::system::error_code + { + auto writebuf = requestImpl->outstream().streambuf(); + writebuf +- .putn_nocopy(boost::asio::buffer_cast(m_request_buf.data()), ++ .putn_nocopy(static_cast(m_request_buf.data().data()), + (std::min)(m_request_buf.size(), m_read_size - m_read)) + .then([this](pplx::task writtenSizeTask) -> will_deref_t { + size_t writtenSize = 0; +@@ -1134,7 +1131,7 @@ will_deref_and_erase_t asio_server_connection::handle_write_chunked_response(con + } + auto membuf = m_response_buf.prepare(ChunkSize + chunked_encoding::additional_encoding_space); + +- readbuf.getn(buffer_cast(membuf) + chunked_encoding::data_offset, ChunkSize) ++ readbuf.getn(static_cast(membuf.data()) + chunked_encoding::data_offset, ChunkSize) + .then([=](pplx::task actualSizeTask) -> will_deref_and_erase_t { + size_t actualSize = 0; + try +@@ -1146,7 +1143,7 @@ will_deref_and_erase_t asio_server_connection::handle_write_chunked_response(con + return cancel_sending_response_with_error(response, std::current_exception()); + } + size_t offset = chunked_encoding::add_chunked_delimiters( +- buffer_cast(membuf), ChunkSize + chunked_encoding::additional_encoding_space, actualSize); ++ static_cast(membuf.data()), ChunkSize + chunked_encoding::additional_encoding_space, actualSize); + m_response_buf.commit(actualSize + chunked_encoding::additional_encoding_space); + m_response_buf.consume(offset); + if (actualSize == 0) +@@ -1167,7 +1164,7 @@ will_deref_and_erase_t asio_server_connection::handle_write_large_response(const + return cancel_sending_response_with_error( + response, std::make_exception_ptr(http_exception("Response stream close early!"))); + size_t readBytes = (std::min)(ChunkSize, m_write_size - m_write); +- readbuf.getn(buffer_cast(m_response_buf.prepare(readBytes)), readBytes) ++ readbuf.getn(static_cast(m_response_buf.prepare(readBytes).data()), readBytes) + .then([=](pplx::task actualSizeTask) -> will_deref_and_erase_t { + size_t actualSize = 0; + try +diff --git a/Release/src/pplx/pplxlinux.cpp b/Release/src/pplx/pplxlinux.cpp +index 630a9e4..65625b6 100644 +--- a/Release/src/pplx/pplxlinux.cpp ++++ b/Release/src/pplx/pplxlinux.cpp +@@ -35,7 +35,7 @@ _PPLXIMP void YieldExecution() { std::this_thread::yield(); } + + _PPLXIMP void linux_scheduler::schedule(TaskProc_t proc, void* param) + { +- crossplat::threadpool::shared_instance().service().post(boost::bind(proc, param)); ++ boost::asio::post(crossplat::threadpool::shared_instance().service(), boost::bind(proc, param)); + } + + } // namespace details +diff --git a/Release/src/pplx/threadpool.cpp b/Release/src/pplx/threadpool.cpp +index ba38a1a..e12e48d 100644 +--- a/Release/src/pplx/threadpool.cpp ++++ b/Release/src/pplx/threadpool.cpp +@@ -37,7 +37,7 @@ static void abort_if_no_jvm() + + struct threadpool_impl final : crossplat::threadpool + { +- threadpool_impl(size_t n) : crossplat::threadpool(n), m_work(m_service) ++ threadpool_impl(size_t n) : crossplat::threadpool(n), m_work(m_service.get_executor()) + { + for (size_t i = 0; i < n; i++) + add_thread(); +@@ -84,7 +84,7 @@ private: + } + + std::vector> m_threads; +- boost::asio::io_service::work m_work; ++ boost::asio::executor_work_guard m_work; + }; + + #if defined(_WIN32) +diff --git a/Release/src/websockets/client/ws_client_wspp.cpp b/Release/src/websockets/client/ws_client_wspp.cpp +index d7c31c4..8dfa815 100644 +--- a/Release/src/websockets/client/ws_client_wspp.cpp ++++ b/Release/src/websockets/client/ws_client_wspp.cpp +@@ -225,7 +225,7 @@ public: + verifyCtx, utility::conversions::to_utf8string(m_uri.host())); + } + #endif +- boost::asio::ssl::rfc2818_verification rfc2818(utility::conversions::to_utf8string(m_uri.host())); ++ boost::asio::ssl::host_name_verification rfc2818(utility::conversions::to_utf8string(m_uri.host())); + return rfc2818(preverified, verifyCtx); + }); + diff --git a/packages/server/cmake/ports/cpprestsdk/fix-clang-dllimport.patch b/packages/server/cmake/ports/cpprestsdk/fix-clang-dllimport.patch new file mode 100644 index 000000000..52552a576 --- /dev/null +++ b/packages/server/cmake/ports/cpprestsdk/fix-clang-dllimport.patch @@ -0,0 +1,52 @@ +diff --git a/Release/include/cpprest/details/cpprest_compat.h b/Release/include/cpprest/details/cpprest_compat.h +index bf107479..00581371 100644 +--- a/Release/include/cpprest/details/cpprest_compat.h ++++ b/Release/include/cpprest/details/cpprest_compat.h +@@ -29,7 +29,6 @@ + #else // ^^^ _WIN32 ^^^ // vvv !_WIN32 vvv + + #define __declspec(x) __attribute__((x)) +-#define dllimport + #define novtable /* no novtable equivalent */ + #define __assume(x) \ + do \ +@@ -74,9 +73,17 @@ + #define _ASYNCRTIMP_TYPEINFO + #else // ^^^ _NO_ASYNCRTIMP ^^^ // vvv !_NO_ASYNCRTIMP vvv + #ifdef _ASYNCRT_EXPORT ++#ifdef _WIN32 + #define _ASYNCRTIMP __declspec(dllexport) ++#else ++#define _ASYNCRTIMP __attribute__((visibility("default"))) ++#endif + #else // ^^^ _ASYNCRT_EXPORT ^^^ // vvv !_ASYNCRT_EXPORT vvv ++#ifdef _WIN32 + #define _ASYNCRTIMP __declspec(dllimport) ++#else ++#define _ASYNCRTIMP ++#endif + #endif // _ASYNCRT_EXPORT + + #if defined(_WIN32) +diff --git a/Release/include/pplx/pplx.h b/Release/include/pplx/pplx.h +index d9ba9c61..8d36252c 100644 +--- a/Release/include/pplx/pplx.h ++++ b/Release/include/pplx/pplx.h +@@ -30,9 +30,17 @@ + #define _PPLXIMP + #else + #ifdef _PPLX_EXPORT ++#ifdef _WIN32 + #define _PPLXIMP __declspec(dllexport) + #else ++#define _PPLXIMP __attribute__((visibility("default"))) ++#endif ++#else ++#ifdef _WIN32 + #define _PPLXIMP __declspec(dllimport) ++#else ++#define _PPLXIMP ++#endif + #endif + #endif + diff --git a/packages/server/cmake/ports/cpprestsdk/fix-find-openssl.patch b/packages/server/cmake/ports/cpprestsdk/fix-find-openssl.patch new file mode 100644 index 000000000..ec420e677 --- /dev/null +++ b/packages/server/cmake/ports/cpprestsdk/fix-find-openssl.patch @@ -0,0 +1,18 @@ +diff --git a/Release/cmake/cpprest_find_openssl.cmake b/Release/cmake/cpprest_find_openssl.cmake +index 9333663..c1df089 100644 +--- a/Release/cmake/cpprest_find_openssl.cmake ++++ b/Release/cmake/cpprest_find_openssl.cmake +@@ -36,8 +36,11 @@ function(cpprest_find_openssl) + # Prefer a homebrew version of OpenSSL over the one in /usr/lib + file(GLOB OPENSSL_ROOT_DIR /usr/local/Cellar/openssl*/*) + # Prefer the latest (make the latest one first) +- list(REVERSE OPENSSL_ROOT_DIR) +- list(GET OPENSSL_ROOT_DIR 0 OPENSSL_ROOT_DIR) ++ if(OPENSSL_ROOT_DIR) ++ # Prefer the latest (make the latest one first) ++ list(REVERSE OPENSSL_ROOT_DIR) ++ list(GET OPENSSL_ROOT_DIR 0 OPENSSL_ROOT_DIR) ++ endif() + endif() + # This should prevent linking against the system provided 0.9.8y + message(STATUS "OPENSSL_ROOT_DIR = ${OPENSSL_ROOT_DIR}") diff --git a/packages/server/cmake/ports/cpprestsdk/fix-libcxx16-char-traits.patch b/packages/server/cmake/ports/cpprestsdk/fix-libcxx16-char-traits.patch new file mode 100644 index 000000000..895ce39ac --- /dev/null +++ b/packages/server/cmake/ports/cpprestsdk/fix-libcxx16-char-traits.patch @@ -0,0 +1,70 @@ +diff --git a/Release/include/cpprest/astreambuf.h b/Release/include/cpprest/astreambuf.h +index 1dcb285..010fd32 100644 +--- a/Release/include/cpprest/astreambuf.h ++++ b/Release/include/cpprest/astreambuf.h +@@ -22,6 +22,65 @@ + #include + #include + ++// libc++ >= 16 removed the non-standard std::char_traits ++// specialization (see https://reviews.llvm.org/D157058). cpprestsdk's ++// Value2StringFormatter in streams.h uses std::basic_string ++// (uint8_t == unsigned char), which requires it, so the engine link fails on ++// any modern-libc++ host. Reintroduce a minimal, standard-conforming ++// specialization, but only on affected libc++: libstdc++ and libc++ < 16 still ++// provide the extension, so the guard avoids a redefinition there. The ++// include precedes the guard so _LIBCPP_VERSION is defined when it is evaluated. ++#include ++#include ++#include ++#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION >= 160000 ++namespace std ++{ ++template<> ++struct char_traits ++{ ++ using char_type = unsigned char; ++ using int_type = int; ++ using off_type = streamoff; ++ using pos_type = streampos; ++ using state_type = mbstate_t; ++ ++ static constexpr void assign(char_type& a, const char_type& b) noexcept { a = b; } ++ static constexpr bool eq(char_type a, char_type b) noexcept { return a == b; } ++ static constexpr bool lt(char_type a, char_type b) noexcept { return a < b; } ++ static int compare(const char_type* a, const char_type* b, size_t n) { return n == 0 ? 0 : memcmp(a, b, n); } ++ static size_t length(const char_type* s) ++ { ++ size_t i = 0; ++ while (s[i]) ++ ++i; ++ return i; ++ } ++ static const char_type* find(const char_type* s, size_t n, const char_type& c) ++ { ++ return static_cast(memchr(s, c, n)); ++ } ++ static char_type* move(char_type* d, const char_type* s, size_t n) ++ { ++ return n == 0 ? d : static_cast(memmove(d, s, n)); ++ } ++ static char_type* copy(char_type* d, const char_type* s, size_t n) ++ { ++ return n == 0 ? d : static_cast(memcpy(d, s, n)); ++ } ++ static char_type* assign(char_type* s, size_t n, char_type c) ++ { ++ return n == 0 ? s : static_cast(memset(s, c, n)); ++ } ++ static constexpr int_type not_eof(int_type c) noexcept { return eq_int_type(c, eof()) ? ~eof() : c; } ++ static constexpr char_type to_char_type(int_type c) noexcept { return char_type(c); } ++ static constexpr int_type to_int_type(char_type c) noexcept { return int_type(c); } ++ static constexpr bool eq_int_type(int_type a, int_type b) noexcept { return a == b; } ++ static constexpr int_type eof() noexcept { return int_type(EOF); } ++}; ++} // namespace std ++#endif ++ + #if (defined(_MSC_VER) && (_MSC_VER >= 1800)) && !CPPREST_FORCE_PPLX + namespace Concurrency // since namespace pplx = Concurrency + #else diff --git a/packages/server/cmake/ports/cpprestsdk/fix-uwp.patch b/packages/server/cmake/ports/cpprestsdk/fix-uwp.patch new file mode 100644 index 000000000..c7e77ebf6 --- /dev/null +++ b/packages/server/cmake/ports/cpprestsdk/fix-uwp.patch @@ -0,0 +1,28 @@ +diff --git a/Release/CMakeLists.txt b/Release/CMakeLists.txt +index b8f3809..3857cfc 100644 +--- a/Release/CMakeLists.txt ++++ b/Release/CMakeLists.txt +@@ -187,7 +187,7 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /profile /OPT:REF /OPT:ICF") + + if (WINDOWS_STORE OR WINDOWS_PHONE) +- add_compile_options(/ZW) ++ # add_compile_options(/ZW) + else() + if (NOT (MSVC_VERSION LESS 1920)) + add_compile_options(/permissive-) +diff --git a/Release/src/CMakeLists.txt b/Release/src/CMakeLists.txt +index 128f6d6..098d33f 100644 +--- a/Release/src/CMakeLists.txt ++++ b/Release/src/CMakeLists.txt +@@ -47,6 +47,10 @@ target_include_directories(cpprest + pch + ) + ++if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC" AND (WINDOWS_STORE OR WINDOWS_PHONE)) ++ target_compile_options(cpprest PUBLIC /ZW) ++endif() ++ + ## Sub-components + # Websockets component + if(CPPREST_WEBSOCKETS_IMPL STREQUAL "none") diff --git a/packages/server/cmake/ports/cpprestsdk/fix_narrowing.patch b/packages/server/cmake/ports/cpprestsdk/fix_narrowing.patch new file mode 100644 index 000000000..975a759ca --- /dev/null +++ b/packages/server/cmake/ports/cpprestsdk/fix_narrowing.patch @@ -0,0 +1,50 @@ +diff --git a/Release/src/CMakeLists.txt b/Release/src/CMakeLists.txt +index e15aeb7fc..128f6d6af 100644 +--- a/Release/src/CMakeLists.txt ++++ b/Release/src/CMakeLists.txt +@@ -185,12 +185,12 @@ endif() + + configure_pch(cpprest stdafx.h pch/stdafx.cpp /Zm120) + +-if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU") ++if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND NOT MSVC) + if(WERROR) + target_compile_options(cpprest PRIVATE -Werror) + endif() + target_compile_options(cpprest PRIVATE -pedantic ${WARNINGS}) +-elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") ++elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC" OR CMAKE_CXX_COMPILER_FRONTEND_VARIANT MATCHES "MSVC") + if(WERROR) + target_compile_options(cpprest PRIVATE /WX ${WARNINGS}) + endif() +diff --git a/Release/src/streams/fileio_win32.cpp b/Release/src/streams/fileio_win32.cpp +index 057dd9b67..a65439cb7 100644 +--- a/Release/src/streams/fileio_win32.cpp ++++ b/Release/src/streams/fileio_win32.cpp +@@ -616,7 +616,7 @@ size_t _fill_buffer_fsb(_In_ _file_info_impl* fInfo, + // pending + return read; + +- case (-1): ++ case ((size_t)(-1)): + // error + delete cb; + return read; +@@ -668,7 +668,7 @@ size_t _fill_buffer_fsb(_In_ _file_info_impl* fInfo, + // pending + return read; + +- case (-1): ++ case ((size_t)(-1)): + // error + delete cb; + return read; +@@ -719,7 +719,7 @@ size_t _fill_buffer_fsb(_In_ _file_info_impl* fInfo, + // pending + return read; + +- case (-1): ++ case ((size_t)(-1)): + // error + delete cb; + return read; diff --git a/packages/server/cmake/ports/cpprestsdk/portfile.cmake b/packages/server/cmake/ports/cpprestsdk/portfile.cmake new file mode 100644 index 000000000..e6bc09e90 --- /dev/null +++ b/packages/server/cmake/ports/cpprestsdk/portfile.cmake @@ -0,0 +1,55 @@ +vcpkg_from_github( + OUT_SOURCE_PATH SOURCE_PATH + REPO Microsoft/cpprestsdk + REF 411a109150b270f23c8c97fa4ec9a0a4a98cdecf + SHA512 4f604763f05d53e50dec5deaba283fa4f82d5e7a94c7c8142bf422f4c0bc24bcef00666ddbdd820f64c14e552997d6657b6aca79a29e69db43799961b44b2a1a + HEAD_REF master + PATCHES + fix-find-openssl.patch + fix_narrowing.patch + fix-uwp.patch + fix-clang-dllimport.patch # workaround for https://github.com/microsoft/cpprestsdk/issues/1710 + silence-stdext-checked-array-iterators-warning.patch + fix-asio-error.patch + fix-libcxx16-char-traits.patch # RocketRide: build against libc++ >= 16 (RR-1438) +) + +vcpkg_check_features( + OUT_FEATURE_OPTIONS FEATURE_OPTIONS + INVERTED_FEATURES + brotli CPPREST_EXCLUDE_BROTLI + compression CPPREST_EXCLUDE_COMPRESSION + websockets CPPREST_EXCLUDE_WEBSOCKETS +) + +if(VCPKG_TARGET_IS_UWP) + set(configure_opts WINDOWS_USE_MSBUILD) +endif() + +vcpkg_cmake_configure( + SOURCE_PATH "${SOURCE_PATH}/Release" + ${configure_opts} + OPTIONS + ${FEATURE_OPTIONS} + -DBUILD_TESTS=OFF + -DBUILD_SAMPLES=OFF + -DCPPREST_EXPORT_DIR=share/cpprestsdk + -DWERROR=OFF + -DPKG_CONFIG_EXECUTABLE=FALSE + OPTIONS_DEBUG + -DCPPREST_INSTALL_HEADERS=OFF +) + +vcpkg_cmake_install() + +vcpkg_copy_pdbs() + +vcpkg_cmake_config_fixup(CONFIG_PATH "lib/share/${PORT}") +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/lib/share" "${CURRENT_PACKAGES_DIR}/lib/share") + +if (VCPKG_LIBRARY_LINKAGE STREQUAL static) + vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/include/cpprest/details/cpprest_compat.h" + "#ifdef _NO_ASYNCRTIMP" "#if 1") +endif() + +file(INSTALL "${SOURCE_PATH}/license.txt" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}" RENAME copyright) diff --git a/packages/server/cmake/ports/cpprestsdk/silence-stdext-checked-array-iterators-warning.patch b/packages/server/cmake/ports/cpprestsdk/silence-stdext-checked-array-iterators-warning.patch new file mode 100644 index 000000000..aa6336784 --- /dev/null +++ b/packages/server/cmake/ports/cpprestsdk/silence-stdext-checked-array-iterators-warning.patch @@ -0,0 +1,12 @@ +diff --git a/Release/CMakeLists.txt b/Release/CMakeLists.txt +index 3d6df65..9ff6d66 100644 +--- a/Release/CMakeLists.txt ++++ b/Release/CMakeLists.txt +@@ -178,6 +178,7 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + set(WARNINGS) + set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /ignore:4264") + add_compile_options(/bigobj) ++ add_compile_options(/D_SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING) + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MP") + set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} /MP") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MP") diff --git a/packages/server/cmake/ports/cpprestsdk/vcpkg.json b/packages/server/cmake/ports/cpprestsdk/vcpkg.json new file mode 100644 index 000000000..8d26279f4 --- /dev/null +++ b/packages/server/cmake/ports/cpprestsdk/vcpkg.json @@ -0,0 +1,85 @@ +{ + "name": "cpprestsdk", + "version": "2.10.19", + "port-version": 3, + "description": [ + "C++11 JSON, REST, and OAuth library", + "The C++ REST SDK is a Microsoft project for cloud-based client-server communication in native code using a modern asynchronous C++ API design. This project aims to help C++ developers connect to and interact with services." + ], + "homepage": "https://github.com/Microsoft/cpprestsdk", + "license": "MIT", + "dependencies": [ + { + "name": "boost-asio", + "platform": "!uwp & !windows" + }, + { + "name": "boost-chrono", + "platform": "!uwp & !windows" + }, + { + "name": "boost-date-time", + "platform": "!uwp & !windows" + }, + { + "name": "boost-filesystem", + "platform": "!uwp & !windows" + }, + { + "name": "boost-random", + "platform": "!uwp & !windows" + }, + { + "name": "boost-regex", + "platform": "!uwp & !windows" + }, + { + "name": "boost-system", + "platform": "!uwp & !windows" + }, + { + "name": "boost-thread", + "platform": "!uwp & !windows" + }, + { + "name": "openssl", + "platform": "!uwp & !windows" + }, + { + "name": "vcpkg-cmake", + "host": true + }, + { + "name": "vcpkg-cmake-config", + "host": true + } + ], + "default-features": [ + { + "name": "brotli", + "platform": "windows" + }, + "compression" + ], + "features": { + "brotli": { + "description": "Brotli compression support", + "dependencies": [ + "brotli", + { + "name": "cpprestsdk", + "default-features": false, + "features": [ + "compression" + ] + } + ] + }, + "compression": { + "description": "HTTP Compression support", + "dependencies": [ + "zlib" + ] + } + } +} From be8e0d7023029a32007e1b4d140f4884718f4e2a Mon Sep 17 00:00:00 2001 From: Ansh-Karnwal <78387773+Ansh-Karnwal@users.noreply.github.com> Date: Wed, 15 Jul 2026 01:34:18 -0700 Subject: [PATCH 2/3] fix(server): include explicitly for EOF in cpprestsdk char_traits patch libc++ prunes transitive includes aggressively, so do not rely on pulling in for the EOF used by char_traits::eof(). --- .../cmake/ports/cpprestsdk/fix-libcxx16-char-traits.patch | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/server/cmake/ports/cpprestsdk/fix-libcxx16-char-traits.patch b/packages/server/cmake/ports/cpprestsdk/fix-libcxx16-char-traits.patch index 895ce39ac..d76ef2cc0 100644 --- a/packages/server/cmake/ports/cpprestsdk/fix-libcxx16-char-traits.patch +++ b/packages/server/cmake/ports/cpprestsdk/fix-libcxx16-char-traits.patch @@ -1,8 +1,8 @@ diff --git a/Release/include/cpprest/astreambuf.h b/Release/include/cpprest/astreambuf.h -index 1dcb285..010fd32 100644 +index 1dcb285..c5e126b 100644 --- a/Release/include/cpprest/astreambuf.h +++ b/Release/include/cpprest/astreambuf.h -@@ -22,6 +22,65 @@ +@@ -22,6 +22,66 @@ #include #include @@ -15,6 +15,7 @@ index 1dcb285..010fd32 100644 +// provide the extension, so the guard avoids a redefinition there. The +// include precedes the guard so _LIBCPP_VERSION is defined when it is evaluated. +#include ++#include +#include +#include +#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION >= 160000 From 0fe143d87578fc9e8c5257fd80ab8afe685ddeff Mon Sep 17 00:00:00 2001 From: Ansh-Karnwal <78387773+Ansh-Karnwal@users.noreply.github.com> Date: Thu, 16 Jul 2026 12:46:03 -0700 Subject: [PATCH 3/3] fix(server): drop constexpr from char_traits assign for C++11 builds macOS compiles cpprestsdk with -std=gnu++11, where a constexpr function returning void is ill-formed (void is not a literal type before C++14), so Apple clang hard-errored on the injected char_traits::assign. That in turn removed the two-argument assign from the overload set, and libc++'s then failed to find it (too few arguments, expected 3). CharTraits does not require assign to be constexpr; libc++ itself only marks it constexpr since C++17. Dropping constexpr keeps the specialization valid on C++11 (macOS) while remaining correct on the C++14+ Linux/libc++>=16 build. --- .../cmake/ports/cpprestsdk/fix-libcxx16-char-traits.patch | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/server/cmake/ports/cpprestsdk/fix-libcxx16-char-traits.patch b/packages/server/cmake/ports/cpprestsdk/fix-libcxx16-char-traits.patch index d76ef2cc0..60620e251 100644 --- a/packages/server/cmake/ports/cpprestsdk/fix-libcxx16-char-traits.patch +++ b/packages/server/cmake/ports/cpprestsdk/fix-libcxx16-char-traits.patch @@ -2,7 +2,7 @@ diff --git a/Release/include/cpprest/astreambuf.h b/Release/include/cpprest/astr index 1dcb285..c5e126b 100644 --- a/Release/include/cpprest/astreambuf.h +++ b/Release/include/cpprest/astreambuf.h -@@ -22,6 +22,66 @@ +@@ -22,6 +22,69 @@ #include #include @@ -30,7 +30,10 @@ index 1dcb285..c5e126b 100644 + using pos_type = streampos; + using state_type = mbstate_t; + -+ static constexpr void assign(char_type& a, const char_type& b) noexcept { a = b; } ++ // Not constexpr: a constexpr function returning void is ill-formed pre-C++14, ++ // and macOS builds cpprestsdk as -std=gnu++11. CharTraits does not require ++ // assign to be constexpr (libc++ only makes it so since C++17), so we omit it. ++ static void assign(char_type& a, const char_type& b) noexcept { a = b; } + static constexpr bool eq(char_type a, char_type b) noexcept { return a == b; } + static constexpr bool lt(char_type a, char_type b) noexcept { return a < b; } + static int compare(const char_type* a, const char_type* b, size_t n) { return n == 0 ? 0 : memcmp(a, b, n); }