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
#################################################################################
# C++17 compiler flags
# Detect if compiler supports at least C++17 standard
include(CXX1x)
check_for_cxx17_compiler(CXX17_COMPILER)
# If a C++17 compiler is available, then set the appropriate flags
if(CXX17_COMPILER)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
else()
if(NOT CXX17_COMPILER)
message(FATAL_ERROR "Compiler does not support C++17.")
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)
set(CMAKE_BUILD_TYPE "RelWithDebInfo")
endif()

View File

@@ -128,17 +128,33 @@ target_include_directories(Foundation
target_compile_definitions(Foundation
PUBLIC
$<$<CONFIG:Debug>:_DEBUG>
$<$<BOOL:${DISABLE_CPP14}>:POCO_DISABLE_CPP14>
$<$<NOT:$<BOOL:${DISABLE_CPP14}>>:POCO_ENABLE_CPP14>
$<$<BOOL:${DISABLE_CPP11}>:POCO_DISABLE_CPP11>
$<$<NOT:$<BOOL:${DISABLE_CPP11}>>:POCO_ENABLE_CPP11>
$<$<BOOL:${POCO_ENABLE_CPP20}>:POCO_ENABLE_CPP20>
)
target_compile_features(Foundation
PUBLIC
$<$<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()
if(NOT BUILD_SHARED_LIBS)

View File

@@ -186,6 +186,8 @@
#endif
#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.
#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
using UTF16Char = Poco::UInt16;
using UTF16String = std::basic_string<UTF16Char, UTF16CharTraits>;
@@ -301,7 +295,6 @@ struct UTF32CharTraits
#define POCO_USE_STRING16
#endif //POCO_OS_FAMILY_WINDOWS
#endif //POCO_NO_WSTRING
//#endif // POCO_ENABLE_CPP11
} // namespace Poco

View File

@@ -252,23 +252,23 @@ namespace
std::string format(const std::string& fmt, const Any& value)
{
std::string result;
format(result, fmt, value);
Poco::format(result, fmt, value);
return result;
}
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)
{
std::string::const_iterator itFmt = fmt.begin();
std::string::const_iterator endFmt = fmt.end();
std::vector<Any>::const_iterator itVal = values.begin();
std::vector<Any>::const_iterator endVal = values.end();
auto itFmt = fmt.begin();
const auto endFmt = fmt.end();
auto itVal = values.begin();
const auto endVal = values.end();
while (itFmt != endFmt)
{
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);
if (index < values.size())
{
std::vector<Any>::const_iterator it = values.begin() + index;
auto it = values.begin() + index;
formatOne(result, itFmt, endFmt, it);
}
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 nine = 9;
bool operator==(const BigObject& other)
bool operator==(const BigObject& other) const
{
return one == other.one &&
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()
@@ -256,7 +254,7 @@ void FormatTest::testBool()
bv.push_back(true);
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");
}
@@ -571,7 +569,7 @@ void FormatTest::testAny()
s.clear();
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);
}

View File

@@ -69,7 +69,8 @@ public:
bool available()
{
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)
{
_pSecFunTable->FreeContextBuffer(pSecPkgInfo);
@@ -81,7 +82,8 @@ public:
Poco::SharedPtr<NTLMContext> createNTLMContext(const std::string& host, const std::string& service)
{
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);
std::size_t maxTokenSize = pSecPkgInfo->cbMaxToken;
@@ -93,7 +95,7 @@ public:
TimeStamp expiry;
status = _pSecFunTable->AcquireCredentialsHandleW(
NULL,
L"NTLM",
package,
SECPKG_CRED_OUTBOUND,
NULL,
NULL,

View File

@@ -174,8 +174,10 @@ void Context::loadCertificate()
}
if (!_hCertStore) throw CertificateException("Failed to open certificate store", _certStoreName, GetLastError());
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.Value.cbData = (DWORD) _certNameOrPath.size();
cert_rdn_attr.Value.pbData = (BYTE *) _certNameOrPath.c_str();
@@ -270,7 +272,7 @@ void Context::acquireSchannelCredentials(CredHandle& credHandle) const
if (_pCert)
{
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();
@@ -312,9 +314,10 @@ void Context::acquireSchannelCredentials(CredHandle& credHandle) const
TimeStamp tsExpiry;
tsExpiry.LowPart = tsExpiry.HighPart = 0;
::SEC_WCHAR name[] = UNISP_NAME_W;
SECURITY_STATUS status = _securityFunctions.AcquireCredentialsHandleW(
NULL,
UNISP_NAME_W,
name,
isForServerUse() ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND,
NULL,
&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());
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.Value.cbData = static_cast<DWORD>(certName.size());
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()
{
SERVICE_TABLE_ENTRYW svcDispatchTable[2];
svcDispatchTable[0].lpServiceName = L"";
wchar_t name[] = L"";
svcDispatchTable[0].lpServiceName = name;
svcDispatchTable[0].lpServiceProc = ServiceMain;
svcDispatchTable[1].lpServiceName = NULL;
svcDispatchTable[1].lpServiceProc = NULL;

View File

@@ -20,25 +20,31 @@
# Determines whether the compiler supports C++17
macro(check_for_cxx17_compiler _VAR)
message(STATUS "Checking for C++17 compiler")
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)
if(NOT _COMPILER_TEST_RESULT AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
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)
if(_COMPILER_TEST_RESULT)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
else()
message(STATUS "To enable C++17 install libc++ standard library from https://libcxx.llvm.org/")
endif()
endif()
if(_COMPILER_TEST_RESULT AND ((MSVC AND (MSVC14)) OR
(CMAKE_COMPILER_IS_GNUCXX AND NOT ${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 4.9.2) OR
(CMAKE_CXX_COMPILER_ID STREQUAL "QCC" AND NOT ${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 4.9.2) OR
(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()
message(STATUS "Checking for C++17 compiler")
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
)
if(NOT _COMPILER_TEST_RESULT AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
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
)
if(_COMPILER_TEST_RESULT)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
else()
message(STATUS "To enable C++17 install libc++ standard library from https://libcxx.llvm.org/")
endif()
endif()
if(_COMPILER_TEST_RESULT AND ((MSVC AND (MSVC14)) OR
(CMAKE_COMPILER_IS_GNUCXX AND NOT ${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 4.9.2) OR
(CMAKE_CXX_COMPILER_ID STREQUAL "QCC" AND NOT ${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 4.9.2) OR
(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()