enh(cmake): Add option POCO_ENABLE_CPP20 to enable C++20 when compiling Poco (#4956)

* enh(cmake): Add option POCO_CXX20 to enable standard C++20 and related changes.

* chore(cmake): do not allow C++20 setting for compilers that do not support it properly.

* fix(NetSSL_Win): indentation.
This commit is contained in:
Matej Kenda
2025-05-28 15:35:28 +02:00
committed by GitHub
parent 5e5e1a60f9
commit 15d987fbb0
12 changed files with 113 additions and 61 deletions

View File

@@ -36,18 +36,48 @@ list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
# Setup C/C++ compiler options # Setup C/C++ compiler options
################################################################################# #################################################################################
# C++17 compiler flags # Detect if compiler supports at least C++17 standard
include(CXX1x) include(CXX1x)
check_for_cxx17_compiler(CXX17_COMPILER) check_for_cxx17_compiler(CXX17_COMPILER)
# If a C++17 compiler is available, then set the appropriate flags if(NOT CXX17_COMPILER)
if(CXX17_COMPILER)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
else()
message(FATAL_ERROR "Compiler does not support C++17.") message(FATAL_ERROR "Compiler does not support C++17.")
endif() endif()
# If a C++17 compiler is available, then set the appropriate flags
option(POCO_ENABLE_CPP20 "Build Poco with C++20 standard" ON)
if (EMSCRIPTEN)
set(POCO_ENABLE_CPP20 OFF CACHE BOOL "Build Poco with C++20 standard" FORCE)
else()
# https://libcxx.llvm.org/Status/Cxx20.html
# https://en.wikipedia.org/wiki/Xcode#Toolchain_versions
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 18.0)
# Does not fully support C++20 yet
set(POCO_ENABLE_CPP20 OFF CACHE BOOL "Build Poco with C++20 standard" FORCE)
endif ()
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 17.0)
# Does not fully support C++20 yet
set(POCO_ENABLE_CPP20 OFF CACHE BOOL "Build Poco with C++20 standard" FORCE)
endif ()
endif()
endif()
if (POCO_ENABLE_CPP20)
set(CMAKE_CXX_STANDARD 20)
message(STATUS "Building Poco with C++20 standard")
else()
set(CMAKE_CXX_STANDARD 17)
message(STATUS "Building Poco with C++17 standard")
endif()
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(NOT CMAKE_BUILD_TYPE) if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "RelWithDebInfo") set(CMAKE_BUILD_TYPE "RelWithDebInfo")
endif() endif()

View File

@@ -128,17 +128,33 @@ target_include_directories(Foundation
target_compile_definitions(Foundation target_compile_definitions(Foundation
PUBLIC PUBLIC
$<$<CONFIG:Debug>:_DEBUG> $<$<CONFIG:Debug>:_DEBUG>
$<$<BOOL:${DISABLE_CPP14}>:POCO_DISABLE_CPP14> $<$<BOOL:${POCO_ENABLE_CPP20}>:POCO_ENABLE_CPP20>
$<$<NOT:$<BOOL:${DISABLE_CPP14}>>:POCO_ENABLE_CPP14>
$<$<BOOL:${DISABLE_CPP11}>:POCO_DISABLE_CPP11>
$<$<NOT:$<BOOL:${DISABLE_CPP11}>>:POCO_ENABLE_CPP11>
) )
target_compile_features(Foundation target_compile_features(Foundation
PUBLIC PUBLIC
$<$<NOT:$<BOOL:${DISABLE_CPP11}>>:cxx_defaulted_move_initializers> $<$<NOT:$<BOOL:${DISABLE_CPP11}>>:cxx_defaulted_move_initializers>
) )
if(NOT DISABLE_CPP14 AND CMAKE_VERSION VERSION_GREATER "3.8")
target_compile_features(Foundation PUBLIC cxx_std_14) #
# Set target C++ standard compile features for exported target.
#
target_compile_features(Foundation PUBLIC cxx_std_17)
if (POCO_ENABLE_CPP20)
target_compile_features(Foundation PUBLIC cxx_std_20)
endif()
if (POCO_ENABLE_CPP20 AND NOT EMSCRIPTEN)
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 20.0)
# Some C++20 features must be enabled explicitly in clang
target_compile_options(Foundation PUBLIC -fexperimental-library)
endif ()
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 18.0)
# Some C++20 features must be enabled explicitly in clang
target_compile_options(Foundation PUBLIC -fexperimental-library)
endif ()
endif()
endif() endif()
if(NOT BUILD_SHARED_LIBS) if(NOT BUILD_SHARED_LIBS)

View File

@@ -186,6 +186,8 @@
#endif #endif
#define POCO_HAVE_CPP17_COMPILER (__cplusplus >= 201703L) #define POCO_HAVE_CPP17_COMPILER (__cplusplus >= 201703L)
#define POCO_HAVE_CPP20_COMPILER (__cplusplus >= 202002L)
#define POCO_HAVE_CPP23_COMPILER (__cplusplus >= 202302L)
// Option to silence deprecation warnings. // Option to silence deprecation warnings.
#ifndef POCO_SILENCE_DEPRECATED #ifndef POCO_SILENCE_DEPRECATED

View File

@@ -260,12 +260,6 @@ struct UTF32CharTraits
}; };
//#if defined(POCO_ENABLE_CPP11) //TODO
// using char16_t UTF16Char;
// using std::u16string UTF16String;
// using char32_t UTF32Char;
// using std::u32string UTF32String;
//#else
#ifdef POCO_NO_WSTRING #ifdef POCO_NO_WSTRING
using UTF16Char = Poco::UInt16; using UTF16Char = Poco::UInt16;
using UTF16String = std::basic_string<UTF16Char, UTF16CharTraits>; using UTF16String = std::basic_string<UTF16Char, UTF16CharTraits>;
@@ -301,7 +295,6 @@ struct UTF32CharTraits
#define POCO_USE_STRING16 #define POCO_USE_STRING16
#endif //POCO_OS_FAMILY_WINDOWS #endif //POCO_OS_FAMILY_WINDOWS
#endif //POCO_NO_WSTRING #endif //POCO_NO_WSTRING
//#endif // POCO_ENABLE_CPP11
} // namespace Poco } // namespace Poco

View File

@@ -252,23 +252,23 @@ namespace
std::string format(const std::string& fmt, const Any& value) std::string format(const std::string& fmt, const Any& value)
{ {
std::string result; std::string result;
format(result, fmt, value); Poco::format(result, fmt, value);
return result; return result;
} }
void format(std::string& result, const char *fmt, const std::vector<Any>& values) void format(std::string& result, const char *fmt, const std::vector<Any>& values)
{ {
format(result, std::string(fmt), values); Poco::format(result, std::string(fmt), values);
} }
void format(std::string& result, const std::string& fmt, const std::vector<Any>& values) void format(std::string& result, const std::string& fmt, const std::vector<Any>& values)
{ {
std::string::const_iterator itFmt = fmt.begin(); auto itFmt = fmt.begin();
std::string::const_iterator endFmt = fmt.end(); const auto endFmt = fmt.end();
std::vector<Any>::const_iterator itVal = values.begin(); auto itVal = values.begin();
std::vector<Any>::const_iterator endVal = values.end(); const auto endVal = values.end();
while (itFmt != endFmt) while (itFmt != endFmt)
{ {
switch (*itFmt) switch (*itFmt)
@@ -283,7 +283,7 @@ void format(std::string& result, const std::string& fmt, const std::vector<Any>&
std::size_t index = parseIndex(itFmt, endFmt); std::size_t index = parseIndex(itFmt, endFmt);
if (index < values.size()) if (index < values.size())
{ {
std::vector<Any>::const_iterator it = values.begin() + index; auto it = values.begin() + index;
formatOne(result, itFmt, endFmt, it); formatOne(result, itFmt, endFmt, it);
} }
else throw InvalidArgumentException("format argument index out of range", fmt); else throw InvalidArgumentException("format argument index out of range", fmt);

View File

@@ -233,7 +233,7 @@ void AnyTest::testAnySwap()
Poco::UInt64 eight = 8; Poco::UInt64 eight = 8;
Poco::UInt64 nine = 9; Poco::UInt64 nine = 9;
bool operator==(const BigObject& other) bool operator==(const BigObject& other) const
{ {
return one == other.one && return one == other.one &&
two == other.two && two == other.two &&

View File

@@ -29,9 +29,7 @@ FormatTest::FormatTest(const std::string& name): CppUnit::TestCase(name)
} }
FormatTest::~FormatTest() FormatTest::~FormatTest() = default;
{
}
void FormatTest::testChar() void FormatTest::testChar()
@@ -256,7 +254,7 @@ void FormatTest::testBool()
bv.push_back(true); bv.push_back(true);
s.clear(); s.clear();
format(s, "%b%b%b%b%b%b%b%b%b%b", bv); Poco::format(s, "%b%b%b%b%b%b%b%b%b%b", bv);
assertTrue (s == "0101010101"); assertTrue (s == "0101010101");
} }
@@ -571,7 +569,7 @@ void FormatTest::testAny()
s.clear(); s.clear();
std::vector<Any> av{ 42, std::string("42"), 42. }; std::vector<Any> av{ 42, std::string("42"), 42. };
format(s, "%d '%s' %f", av); Poco::format(s, "%d '%s' %f", av);
assertTrue (s.find("42 '42' 42.0") == 0); assertTrue (s.find("42 '42' 42.0") == 0);
} }

View File

@@ -69,7 +69,8 @@ public:
bool available() bool available()
{ {
PSecPkgInfoW pSecPkgInfo; PSecPkgInfoW pSecPkgInfo;
SECURITY_STATUS status = _pSecFunTable->QuerySecurityPackageInfoW(L"NTLM", &pSecPkgInfo); ::SEC_WCHAR package[] = L"NTLM";
SECURITY_STATUS status = _pSecFunTable->QuerySecurityPackageInfoW(package, &pSecPkgInfo);
if (status == SEC_E_OK) if (status == SEC_E_OK)
{ {
_pSecFunTable->FreeContextBuffer(pSecPkgInfo); _pSecFunTable->FreeContextBuffer(pSecPkgInfo);
@@ -81,7 +82,8 @@ public:
Poco::SharedPtr<NTLMContext> createNTLMContext(const std::string& host, const std::string& service) Poco::SharedPtr<NTLMContext> createNTLMContext(const std::string& host, const std::string& service)
{ {
PSecPkgInfoW pSecPkgInfo; PSecPkgInfoW pSecPkgInfo;
SECURITY_STATUS status = _pSecFunTable->QuerySecurityPackageInfoW(L"NTLM", &pSecPkgInfo); ::SEC_WCHAR package[] = L"NTLM";
SECURITY_STATUS status = _pSecFunTable->QuerySecurityPackageInfoW(package, &pSecPkgInfo);
if (status != SEC_E_OK) throw Poco::SystemException("NTLM SSPI not available", status); if (status != SEC_E_OK) throw Poco::SystemException("NTLM SSPI not available", status);
std::size_t maxTokenSize = pSecPkgInfo->cbMaxToken; std::size_t maxTokenSize = pSecPkgInfo->cbMaxToken;
@@ -93,7 +95,7 @@ public:
TimeStamp expiry; TimeStamp expiry;
status = _pSecFunTable->AcquireCredentialsHandleW( status = _pSecFunTable->AcquireCredentialsHandleW(
NULL, NULL,
L"NTLM", package,
SECPKG_CRED_OUTBOUND, SECPKG_CRED_OUTBOUND,
NULL, NULL,
NULL, NULL,

View File

@@ -174,8 +174,10 @@ void Context::loadCertificate()
} }
if (!_hCertStore) throw CertificateException("Failed to open certificate store", _certStoreName, GetLastError()); if (!_hCertStore) throw CertificateException("Failed to open certificate store", _certStoreName, GetLastError());
CERT_RDN_ATTR cert_rdn_attr; CERT_RDN_ATTR cert_rdn_attr;
cert_rdn_attr.pszObjId = szOID_COMMON_NAME; char cmnName[] = szOID_COMMON_NAME;
cert_rdn_attr.pszObjId = cmnName;
cert_rdn_attr.dwValueType = CERT_RDN_ANY_TYPE; cert_rdn_attr.dwValueType = CERT_RDN_ANY_TYPE;
cert_rdn_attr.Value.cbData = (DWORD) _certNameOrPath.size(); cert_rdn_attr.Value.cbData = (DWORD) _certNameOrPath.size();
cert_rdn_attr.Value.pbData = (BYTE *) _certNameOrPath.c_str(); cert_rdn_attr.Value.pbData = (BYTE *) _certNameOrPath.c_str();
@@ -270,7 +272,7 @@ void Context::acquireSchannelCredentials(CredHandle& credHandle) const
if (_pCert) if (_pCert)
{ {
schannelCred.cCreds = 1; // how many cred are stored in &pCertContext schannelCred.cCreds = 1; // how many cred are stored in &pCertContext
schannelCred.paCred = &const_cast<PCCERT_CONTEXT>(_pCert); schannelCred.paCred = const_cast<PCCERT_CONTEXT*>(&_pCert);
} }
schannelCred.grbitEnabledProtocols = proto(); schannelCred.grbitEnabledProtocols = proto();
@@ -312,9 +314,10 @@ void Context::acquireSchannelCredentials(CredHandle& credHandle) const
TimeStamp tsExpiry; TimeStamp tsExpiry;
tsExpiry.LowPart = tsExpiry.HighPart = 0; tsExpiry.LowPart = tsExpiry.HighPart = 0;
::SEC_WCHAR name[] = UNISP_NAME_W;
SECURITY_STATUS status = _securityFunctions.AcquireCredentialsHandleW( SECURITY_STATUS status = _securityFunctions.AcquireCredentialsHandleW(
NULL, NULL,
UNISP_NAME_W, name,
isForServerUse() ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND, isForServerUse() ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND,
NULL, NULL,
&schannelCred, &schannelCred,

View File

@@ -396,7 +396,8 @@ void X509Certificate::loadCertificate(const std::string& certName, const std::st
if (!hCertStore) throw CertificateException("Failed to open certificate store", certStoreName, GetLastError()); if (!hCertStore) throw CertificateException("Failed to open certificate store", certStoreName, GetLastError());
CERT_RDN_ATTR cert_rdn_attr; CERT_RDN_ATTR cert_rdn_attr;
cert_rdn_attr.pszObjId = szOID_COMMON_NAME; char cmnName[] = szOID_COMMON_NAME;
cert_rdn_attr.pszObjId = cmnName;
cert_rdn_attr.dwValueType = CERT_RDN_ANY_TYPE; cert_rdn_attr.dwValueType = CERT_RDN_ANY_TYPE;
cert_rdn_attr.Value.cbData = static_cast<DWORD>(certName.size()); cert_rdn_attr.Value.cbData = static_cast<DWORD>(certName.size());
cert_rdn_attr.Value.pbData = reinterpret_cast<BYTE*>(const_cast<char*>(certName.c_str())); cert_rdn_attr.Value.pbData = reinterpret_cast<BYTE*>(const_cast<char*>(certName.c_str()));

View File

@@ -333,7 +333,8 @@ int ServerApplication::run(int argc, wchar_t** argv)
bool ServerApplication::isService() bool ServerApplication::isService()
{ {
SERVICE_TABLE_ENTRYW svcDispatchTable[2]; SERVICE_TABLE_ENTRYW svcDispatchTable[2];
svcDispatchTable[0].lpServiceName = L""; wchar_t name[] = L"";
svcDispatchTable[0].lpServiceName = name;
svcDispatchTable[0].lpServiceProc = ServiceMain; svcDispatchTable[0].lpServiceProc = ServiceMain;
svcDispatchTable[1].lpServiceName = NULL; svcDispatchTable[1].lpServiceName = NULL;
svcDispatchTable[1].lpServiceProc = NULL; svcDispatchTable[1].lpServiceProc = NULL;

View File

@@ -20,25 +20,31 @@
# Determines whether the compiler supports C++17 # Determines whether the compiler supports C++17
macro(check_for_cxx17_compiler _VAR) macro(check_for_cxx17_compiler _VAR)
message(STATUS "Checking for C++17 compiler") message(STATUS "Checking for C++17 compiler")
set(${_VAR}) set(${_VAR})
try_compile(_COMPILER_TEST_RESULT ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/cmake/test_compiler.cpp CMAKE_FLAGS -DCMAKE_CXX_STANDARD=17 -DCMAKE_CXX_STANDARD_REQUIRED=ON) try_compile(
if(NOT _COMPILER_TEST_RESULT AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang") _COMPILER_TEST_RESULT ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/cmake/test_compiler.cpp
try_compile(_COMPILER_TEST_RESULT ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/cmake/test_compiler.cpp CMAKE_FLAGS -DCMAKE_CXX_FLAGS="-stdlib=libc++" -DCMAKE_CXX_STANDARD=17 -DCMAKE_CXX_STANDARD_REQUIRED=ON) CMAKE_FLAGS -DCMAKE_CXX_STANDARD=17 -DCMAKE_CXX_STANDARD_REQUIRED=ON
if(_COMPILER_TEST_RESULT) )
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") if(NOT _COMPILER_TEST_RESULT AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
else() try_compile(
message(STATUS "To enable C++17 install libc++ standard library from https://libcxx.llvm.org/") _COMPILER_TEST_RESULT ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/cmake/test_compiler.cpp
endif() CMAKE_FLAGS -DCMAKE_CXX_FLAGS="-stdlib=libc++" -DCMAKE_CXX_STANDARD=17 -DCMAKE_CXX_STANDARD_REQUIRED=ON
endif() )
if(_COMPILER_TEST_RESULT AND ((MSVC AND (MSVC14)) OR if(_COMPILER_TEST_RESULT)
(CMAKE_COMPILER_IS_GNUCXX AND NOT ${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 4.9.2) OR set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
(CMAKE_CXX_COMPILER_ID STREQUAL "QCC" AND NOT ${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 4.9.2) OR else()
(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND NOT ${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 3.4) OR message(STATUS "To enable C++17 install libc++ standard library from https://libcxx.llvm.org/")
(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang"))) endif()
set(${_VAR} 1) endif()
message(STATUS "Checking for C++17 compiler - available") if(_COMPILER_TEST_RESULT AND ((MSVC AND (MSVC14)) OR
else() (CMAKE_COMPILER_IS_GNUCXX AND NOT ${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 4.9.2) OR
message(STATUS "Checking for C++17 compiler - unavailable") (CMAKE_CXX_COMPILER_ID STREQUAL "QCC" AND NOT ${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 4.9.2) OR
endif() (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND NOT ${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 3.4) OR
(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")))
set(${_VAR} 1)
message(STATUS "Checking for C++17 compiler - available")
else()
message(STATUS "Checking for C++17 compiler - unavailable")
endif()
endmacro() endmacro()