From a68bca371a917881045f83dc93b45b6f2eedb184 Mon Sep 17 00:00:00 2001 From: Stephen Webb Date: Mon, 8 Jun 2026 16:13:19 +1000 Subject: [PATCH 01/11] Fix compilation errors when using LOG4CXX_CHAR=unicode --- .github/workflows/log4cxx-ubuntu.yml | 5 +++-- src/main/cpp/asyncbuffer.cpp | 4 +++- src/main/cpp/smtpappender.cpp | 2 +- src/main/cpp/threadutility.cpp | 8 ++++---- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/.github/workflows/log4cxx-ubuntu.yml b/.github/workflows/log4cxx-ubuntu.yml index 71899d101..56faadac1 100644 --- a/.github/workflows/log4cxx-ubuntu.yml +++ b/.github/workflows/log4cxx-ubuntu.yml @@ -37,7 +37,7 @@ jobs: multithread: OFF exitevents: OFF fuzzers: OFF - logchar: utf-8 + logchar: unicode next_abi: OFF - name: ubuntu22-clang os: ubuntu-22.04 @@ -107,6 +107,7 @@ jobs: run: | ROOT=`pwd` set -x + [ ${{ matrix.logchar }} == unicode ] && OPTIONAL_API=-DLOG4CXX_UNICHAR=1 cmake \ -DCMAKE_CXX_COMPILER=${{ matrix.cxx }} \ -DLOG4CXX_TEST_ONLY_BUILD=1 \ @@ -116,7 +117,7 @@ jobs: -DLOG4CXX_MULTIPROCESS_ROLLING_FILE_APPENDER=${{ matrix.multiprocess }} \ -DLOG4CXX_EVENTS_AT_EXIT=${{ matrix.exitevents }} \ -DBUILD_FUZZERS=${{ matrix.fuzzers }} \ - -DLOG4CXX_CHAR=${{ matrix.logchar }} \ + -DLOG4CXX_CHAR=${{ matrix.logchar }} $OPTIONAL_API \ -DLOG4CXX_BUILD_NEXT_ABI=${{ matrix.next_abi }} \ -DCMAKE_INSTALL_PREFIX=$ROOT/lib \ -S $ROOT/main \ diff --git a/src/main/cpp/asyncbuffer.cpp b/src/main/cpp/asyncbuffer.cpp index 56c6d425c..54d727081 100644 --- a/src/main/cpp/asyncbuffer.cpp +++ b/src/main/cpp/asyncbuffer.cpp @@ -159,7 +159,7 @@ void AsyncBuffer::renderMessage(LogCharMessageBuffer& msg) const LOG4CXX_DECODE_WCHAR(lsMsg, wideBuf.extract_str(wideBuf)); msg << lsMsg; } -#else // !LOG4CXX_LOGCHAR_IS_UTF8 +#elif LOG4CXX_LOGCHAR_IS_WCHAR if (auto pRenderer = std::get_if(&renderer)) (*pRenderer)(msg); else @@ -169,6 +169,8 @@ void AsyncBuffer::renderMessage(LogCharMessageBuffer& msg) const LOG4CXX_DECODE_CHAR(lsMsg, narrowBuf.extract_str(narrowBuf)); msg << lsMsg; } +#else + msg << LOG4CXX_STR("Unichar is not supported"); #endif // !LOG4CXX_LOGCHAR_IS_UTF8 } #else // !LOG4CXX_CONCEPTS diff --git a/src/main/cpp/smtpappender.cpp b/src/main/cpp/smtpappender.cpp index 496c3d53d..079d85fab 100644 --- a/src/main/cpp/smtpappender.cpp +++ b/src/main/cpp/smtpappender.cpp @@ -54,7 +54,7 @@ namespace // owns SMTP wire-format sanitization (see SMTPSession::toAscii, which silently // rewrites non-ASCII to '?'); strip CR/LF in the public setters so the same // boundary is enforced regardless of how the value reaches the appender. -LogString stripSmtpControl(const LogString& value, const logchar* field) +LogString stripSmtpControl(const LogString& value, const LogString& field) { if (value.find_first_of(LOG4CXX_STR("\r\n")) == LogString::npos) { diff --git a/src/main/cpp/threadutility.cpp b/src/main/cpp/threadutility.cpp index 4ea4c0785..acdd57e43 100644 --- a/src/main/cpp/threadutility.cpp +++ b/src/main/cpp/threadutility.cpp @@ -189,7 +189,7 @@ void ThreadUtility::preThreadBlockSignals() if ( pthread_sigmask(SIG_SETMASK, &set, &old_mask) < 0 ) { - LOGLOG_ERROR( LOG4CXX_STR("Unable to set thread sigmask") ); + LogLog::error( LOG4CXX_STR("Unable to set thread sigmask") ); sigmask_valid = false; } else @@ -207,7 +207,7 @@ void ThreadUtility::threadStartedNameThread(LogString threadName, #if LOG4CXX_HAS_PTHREAD_SETNAME && !(defined(_WIN32) && defined(_LIBCPP_VERSION)) LOG4CXX_ENCODE_CHAR(sthreadName, threadName); if (pthread_setname_np(static_cast(nativeHandle), sthreadName.c_str()) < 0) { - LOGLOG_ERROR(LOG4CXX_STR("unable to set thread name")); + LogLog::error(LOG4CXX_STR("Unable to set thread name")); } #elif defined(_WIN32) typedef HRESULT (WINAPI *TSetThreadDescription)(HANDLE, PCWSTR); @@ -227,7 +227,7 @@ void ThreadUtility::threadStartedNameThread(LogString threadName, { LOG4CXX_ENCODE_WCHAR(wthreadName, threadName); if(FAILED(win32Func.SetThreadDescription(static_cast(nativeHandle), wthreadName.c_str()))) - LOGLOG_ERROR( LOG4CXX_STR("unable to set thread name") ); + LogLog::error( LOG4CXX_STR(Unable to set thread name") ); } #endif } @@ -241,7 +241,7 @@ void ThreadUtility::postThreadUnblockSignals() { if ( pthread_sigmask(SIG_SETMASK, &old_mask, nullptr) < 0 ) { - LOGLOG_ERROR( LOG4CXX_STR("Unable to set thread sigmask") ); + LogLog::error( LOG4CXX_STR("Unable to set thread sigmask") ); } } From 67c6bdf70fced248d79c3f9bf4cf0bcda5000d89 Mon Sep 17 00:00:00 2001 From: Stephen Webb Date: Mon, 8 Jun 2026 16:24:17 +1000 Subject: [PATCH 02/11] Fix typo --- .github/workflows/log4cxx-ubuntu.yml | 2 +- src/main/cpp/threadutility.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/log4cxx-ubuntu.yml b/.github/workflows/log4cxx-ubuntu.yml index 56faadac1..ca8df0fd4 100644 --- a/.github/workflows/log4cxx-ubuntu.yml +++ b/.github/workflows/log4cxx-ubuntu.yml @@ -107,7 +107,7 @@ jobs: run: | ROOT=`pwd` set -x - [ ${{ matrix.logchar }} == unicode ] && OPTIONAL_API=-DLOG4CXX_UNICHAR=1 + [ ${{ matrix.logchar }} == unicode ] && OPTIONAL_API=-DLOG4CXX_UNICHAR=ON cmake \ -DCMAKE_CXX_COMPILER=${{ matrix.cxx }} \ -DLOG4CXX_TEST_ONLY_BUILD=1 \ diff --git a/src/main/cpp/threadutility.cpp b/src/main/cpp/threadutility.cpp index acdd57e43..2d5e2dd75 100644 --- a/src/main/cpp/threadutility.cpp +++ b/src/main/cpp/threadutility.cpp @@ -227,7 +227,7 @@ void ThreadUtility::threadStartedNameThread(LogString threadName, { LOG4CXX_ENCODE_WCHAR(wthreadName, threadName); if(FAILED(win32Func.SetThreadDescription(static_cast(nativeHandle), wthreadName.c_str()))) - LogLog::error( LOG4CXX_STR(Unable to set thread name") ); + LogLog::error( LOG4CXX_STR("Unable to set thread name") ); } #endif } From e1b24935195216986a74883a0aa2894a4698c020 Mon Sep 17 00:00:00 2001 From: Stephen Webb Date: Mon, 8 Jun 2026 17:21:16 +1000 Subject: [PATCH 03/11] Prevent static_assert error when using LOG4CXX_CHAR=unicode --- src/main/include/log4cxx/helpers/asyncbuffer.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/include/log4cxx/helpers/asyncbuffer.h b/src/main/include/log4cxx/helpers/asyncbuffer.h index 023a3df5c..b1478d91b 100644 --- a/src/main/include/log4cxx/helpers/asyncbuffer.h +++ b/src/main/include/log4cxx/helpers/asyncbuffer.h @@ -95,7 +95,7 @@ class LOG4CXX_EXPORT AsyncBuffer #endif // LOG4CXX_WCHAR_T_API else static_assert(false, "operator<<(std::ostream&) overload must be provided"); -#else // !LOG4CXX_LOGCHAR_IS_UTF8 +#elif LOG4CXX_LOGCHAR_IS_WCHAR if constexpr (requires(std::wostream& buf, T v) { buf << v; }) { append([value](WideMessageBuffer& msgBuf) @@ -112,7 +112,12 @@ class LOG4CXX_EXPORT AsyncBuffer } else static_assert(false, "operator<<(std::wostream&) overload must be provided"); -#endif // !LOG4CXX_LOGCHAR_IS_UTF8 +#else // LOG4CXX_LOGCHAR_IS_WCHAR + append([value](LogCharMessageBuffer& msgBuf) + { + msgBuf << value; + }); +#endif // !LOG4CXX_LOGCHAR_IS_UTF8&& !LOG4CXX_LOGCHAR_IS_WCHAR #else // !LOG4CXX_CONCEPTS append([value](LogCharMessageBuffer& msgBuf) { From 9610d3fa1e30764fe6c68f73ce6c4ac576e8febc Mon Sep 17 00:00:00 2001 From: Stephen Webb Date: Mon, 8 Jun 2026 18:08:38 +1000 Subject: [PATCH 04/11] The actual option is LOG4CXX_CHAR=unichar --- .github/workflows/log4cxx-ubuntu.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/log4cxx-ubuntu.yml b/.github/workflows/log4cxx-ubuntu.yml index ca8df0fd4..91c260c13 100644 --- a/.github/workflows/log4cxx-ubuntu.yml +++ b/.github/workflows/log4cxx-ubuntu.yml @@ -37,7 +37,7 @@ jobs: multithread: OFF exitevents: OFF fuzzers: OFF - logchar: unicode + logchar: unichar next_abi: OFF - name: ubuntu22-clang os: ubuntu-22.04 @@ -107,7 +107,7 @@ jobs: run: | ROOT=`pwd` set -x - [ ${{ matrix.logchar }} == unicode ] && OPTIONAL_API=-DLOG4CXX_UNICHAR=ON + [ ${{ matrix.logchar }} == unichar ] && OPTIONAL_API=-DLOG4CXX_UNICHAR=ON cmake \ -DCMAKE_CXX_COMPILER=${{ matrix.cxx }} \ -DLOG4CXX_TEST_ONLY_BUILD=1 \ From 5c19ecfb49dff525e96b51537f818ef86cfba42a Mon Sep 17 00:00:00 2001 From: Stephen Webb Date: Mon, 8 Jun 2026 21:18:37 +1000 Subject: [PATCH 05/11] Fix LOG4CXX_CHAR=unichar and LOG4CXX_UNICHAR_API=On compilation error --- src/main/cpp/logger.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/main/cpp/logger.cpp b/src/main/cpp/logger.cpp index 1efcb34f4..68a8e92a1 100644 --- a/src/main/cpp/logger.cpp +++ b/src/main/cpp/logger.cpp @@ -1047,8 +1047,12 @@ void Logger::addEvent(const LevelPtr& level1, std::basic_string&& messa { if (!getHierarchy()) // Has removeHierarchy() been called? return; +#if LOG4CXX_LOGCHAR_IS_UNICHAR + auto event = std::make_shared(m_priv->name, level1, location, std::move(message)); +#else LOG4CXX_DECODE_UNICHAR(msg, message); auto event = std::make_shared(m_priv->name, level1, location, std::move(msg)); +#endif callAppenders(event); } @@ -1087,8 +1091,12 @@ void Logger::forcedLog(const LevelPtr& level1, const std::basic_string& { if (!getHierarchy()) // Has removeHierarchy() been called? return; +#if LOG4CXX_LOGCHAR_IS_UNICHAR + auto event = std::make_shared(m_priv->name, level1, message, location); +#else LOG4CXX_DECODE_UNICHAR(msg, message); auto event = std::make_shared(m_priv->name, level1, location, std::move(msg)); +#endif callAppenders(event); } @@ -1096,9 +1104,14 @@ void Logger::forcedLog(const LevelPtr& level1, const std::basic_string& { if (!getHierarchy()) // Has removeHierarchy() been called? return; +#if LOG4CXX_LOGCHAR_IS_UNICHAR + auto event = std::make_shared(m_priv->name, level1, message, + LocationInfo::getLocationUnavailable()); +#else LOG4CXX_DECODE_UNICHAR(msg, message); auto event = std::make_shared(m_priv->name, level1, msg, LocationInfo::getLocationUnavailable()); +#endif callAppenders(event); } From 14feb6e563cbc0952bd81b51ba3efb75c9c243ae Mon Sep 17 00:00:00 2001 From: Stephen Webb Date: Tue, 9 Jun 2026 14:14:44 +1000 Subject: [PATCH 06/11] Make string constants unichar compatible --- src/test/cpp/hexdumptestcase.cpp | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/test/cpp/hexdumptestcase.cpp b/src/test/cpp/hexdumptestcase.cpp index 66624c23d..781b6a95f 100644 --- a/src/test/cpp/hexdumptestcase.cpp +++ b/src/test/cpp/hexdumptestcase.cpp @@ -60,12 +60,11 @@ LOGUNIT_CLASS(HexdumpTestCase) 0x73, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x61, 0x7a, 0x79, 0x20, 0x64, 0x6f, 0x67 }; - LogString expectedOutput = - LOG4CXX_STR("00000000 54 68 65 20 71 75 69 63 6b 20 62 72 6f 77 6e 20 |The quick brown |") - LOG4CXX_EOL - LOG4CXX_STR("00000010 66 6f 78 20 6a 75 6d 70 73 20 6f 76 65 72 20 74 |fox jumps over t|") - LOG4CXX_EOL - LOG4CXX_STR("00000020 68 65 20 6c 61 7a 79 20 64 6f 67 |he lazy dog|"); + LogString expectedOutput = LOG4CXX_STR( + "00000000 54 68 65 20 71 75 69 63 6b 20 62 72 6f 77 6e 20 |The quick brown |\x0D\x0A" + "00000010 66 6f 78 20 6a 75 6d 70 73 20 6f 76 65 72 20 74 |fox jumps over t|\x0D\x0A" + "00000020 68 65 20 6c 61 7a 79 20 64 6f 67 |he lazy dog|" + ); // Hexdump up until the NULL char LogString dumped = log4cxx::hexdump(quick_brown_fox, sizeof(quick_brown_fox)); @@ -77,10 +76,8 @@ LOGUNIT_CLASS(HexdumpTestCase) unsigned char test1_str[] = { 0x74, 0x65, 0x73, 0x74, 0x31 }; - LogString expectedOutput = - LOG4CXX_EOL - LOG4CXX_STR("00000000 74 65 73 74 31 |test1|") - LOG4CXX_EOL; + LogString expectedOutput = LOG4CXX_STR("\x0D\x0A0"); + expectedOutput += LOG4CXX_STR("00000000 74 65 73 74 31 |test1|\x0D\x0A"); LogString dumped = log4cxx::hexdump(test1_str, sizeof(test1_str), HexdumpFlags::AddNewline); LOGUNIT_ASSERT_EQUAL(expectedOutput, dumped); @@ -91,10 +88,8 @@ LOGUNIT_CLASS(HexdumpTestCase) unsigned char test1_str[] = { 0x74, 0x65, 0x73, 0x74, 0x31 }; - LogString expectedOutput = - LOG4CXX_EOL - LOG4CXX_STR("00000000 74 65 73 74 31 |test1|") - LOG4CXX_EOL; + LogString expectedOutput = LOG4CXX_STR("\x0D\x0A0"); + expectedOutput += LOG4CXX_STR("00000000 74 65 73 74 31 |test1|\x0D\x0A"); LogString dumped = log4cxx::hexdump(test1_str, sizeof(test1_str), HexdumpFlags::AddStartingNewline | HexdumpFlags::AddEndingNewline); LOGUNIT_ASSERT_EQUAL(expectedOutput, dumped); From 60f9a1968ccf42c472995f2d022eb45f882401e2 Mon Sep 17 00:00:00 2001 From: Stephen Webb Date: Tue, 9 Jun 2026 16:36:35 +1000 Subject: [PATCH 07/11] Make string constants unichar compatible --- src/test/cpp/hexdumptestcase.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/test/cpp/hexdumptestcase.cpp b/src/test/cpp/hexdumptestcase.cpp index 781b6a95f..ace761943 100644 --- a/src/test/cpp/hexdumptestcase.cpp +++ b/src/test/cpp/hexdumptestcase.cpp @@ -76,8 +76,9 @@ LOGUNIT_CLASS(HexdumpTestCase) unsigned char test1_str[] = { 0x74, 0x65, 0x73, 0x74, 0x31 }; - LogString expectedOutput = LOG4CXX_STR("\x0D\x0A0"); - expectedOutput += LOG4CXX_STR("00000000 74 65 73 74 31 |test1|\x0D\x0A"); + LogString expectedOutput = LOG4CXX_EOL; + expectedOutput += LOG4CXX_STR("00000000 74 65 73 74 31 |test1|"); + expectedOutput += LOG4CXX_EOL; LogString dumped = log4cxx::hexdump(test1_str, sizeof(test1_str), HexdumpFlags::AddNewline); LOGUNIT_ASSERT_EQUAL(expectedOutput, dumped); @@ -88,8 +89,9 @@ LOGUNIT_CLASS(HexdumpTestCase) unsigned char test1_str[] = { 0x74, 0x65, 0x73, 0x74, 0x31 }; - LogString expectedOutput = LOG4CXX_STR("\x0D\x0A0"); - expectedOutput += LOG4CXX_STR("00000000 74 65 73 74 31 |test1|\x0D\x0A"); + LogString expectedOutput = LOG4CXX_EOL; + expectedOutput += LOG4CXX_STR("00000000 74 65 73 74 31 |test1|"); + expectedOutput += LOG4CXX_EOL; LogString dumped = log4cxx::hexdump(test1_str, sizeof(test1_str), HexdumpFlags::AddStartingNewline | HexdumpFlags::AddEndingNewline); LOGUNIT_ASSERT_EQUAL(expectedOutput, dumped); From d36f4eddc617ff736f7f5324492d97b3ea241eee Mon Sep 17 00:00:00 2001 From: Stephen Webb Date: Tue, 9 Jun 2026 17:20:37 +1000 Subject: [PATCH 08/11] Make string constants unichar compatible --- src/test/cpp/hexdumptestcase.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/test/cpp/hexdumptestcase.cpp b/src/test/cpp/hexdumptestcase.cpp index ace761943..9fae5f695 100644 --- a/src/test/cpp/hexdumptestcase.cpp +++ b/src/test/cpp/hexdumptestcase.cpp @@ -60,11 +60,12 @@ LOGUNIT_CLASS(HexdumpTestCase) 0x73, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x61, 0x7a, 0x79, 0x20, 0x64, 0x6f, 0x67 }; - LogString expectedOutput = LOG4CXX_STR( - "00000000 54 68 65 20 71 75 69 63 6b 20 62 72 6f 77 6e 20 |The quick brown |\x0D\x0A" - "00000010 66 6f 78 20 6a 75 6d 70 73 20 6f 76 65 72 20 74 |fox jumps over t|\x0D\x0A" - "00000020 68 65 20 6c 61 7a 79 20 64 6f 67 |he lazy dog|" - ); + LogString expectedOutput = + LOG4CXX_STR("00000000 54 68 65 20 71 75 69 63 6b 20 62 72 6f 77 6e 20 |The quick brown |"); + expectedOutput += LOG4CXX_EOL; + expectedOutput += LOG4CXX_STR("00000010 66 6f 78 20 6a 75 6d 70 73 20 6f 76 65 72 20 74 |fox jumps over t|"); + expectedOutput += LOG4CXX_EOL; + expectedOutput += LOG4CXX_STR("00000020 68 65 20 6c 61 7a 79 20 64 6f 67 |he lazy dog|"); // Hexdump up until the NULL char LogString dumped = log4cxx::hexdump(quick_brown_fox, sizeof(quick_brown_fox)); From de7ddb04603269462bc0eb18807f42dd5cbf73d5 Mon Sep 17 00:00:00 2001 From: Stephen Webb Date: Tue, 9 Jun 2026 17:30:29 +1000 Subject: [PATCH 09/11] Make string constants unichar compatible --- src/test/cpp/helpers/simpledateformattestcase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/cpp/helpers/simpledateformattestcase.cpp b/src/test/cpp/helpers/simpledateformattestcase.cpp index d435381a1..68e64a887 100644 --- a/src/test/cpp/helpers/simpledateformattestcase.cpp +++ b/src/test/cpp/helpers/simpledateformattestcase.cpp @@ -110,7 +110,7 @@ LOGUNIT_CLASS(SimpleDateFormatTestCase) , (apr_time_t) APR_INT64_C(-9000000000000000000) }; - const logchar* patterns[] = + const LogString patterns[] = { LOG4CXX_STR("EEE") , LOG4CXX_STR("EEEE") , LOG4CXX_STR("MMM") From 094c39fd2443601b2766244cfbb5cfff11bb09e2 Mon Sep 17 00:00:00 2001 From: Stephen Webb Date: Tue, 9 Jun 2026 18:14:41 +1000 Subject: [PATCH 10/11] AsyncBuffer fmt support does not include unichar --- src/main/include/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/include/CMakeLists.txt b/src/main/include/CMakeLists.txt index c5d52f331..57d0b46fe 100644 --- a/src/main/include/CMakeLists.txt +++ b/src/main/include/CMakeLists.txt @@ -25,6 +25,7 @@ if(${LOG4CXX_CHAR} STREQUAL "unichar") set(LOGCHAR_IS_UNICHAR 1) set(LOGCHAR_IS_WCHAR 0) set(LOGCHAR_IS_UTF8 0) + set(ENABLE_FMT_ASYNC 0) elseif(${LOG4CXX_CHAR} STREQUAL "wchar_t") set(LOGCHAR_IS_WCHAR 1) set(LOGCHAR_IS_UNICHAR 0) From a5baf2ebb05db58a917ae723dbad66e45bef60e5 Mon Sep 17 00:00:00 2001 From: Stephen Webb Date: Tue, 9 Jun 2026 18:16:01 +1000 Subject: [PATCH 11/11] LOG4CXX_CHAR=unichar may compile on Ubuntu, but it does not work --- .github/workflows/log4cxx-ubuntu.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/log4cxx-ubuntu.yml b/.github/workflows/log4cxx-ubuntu.yml index 91c260c13..50f548064 100644 --- a/.github/workflows/log4cxx-ubuntu.yml +++ b/.github/workflows/log4cxx-ubuntu.yml @@ -37,7 +37,7 @@ jobs: multithread: OFF exitevents: OFF fuzzers: OFF - logchar: unichar + logchar: utf-8 next_abi: OFF - name: ubuntu22-clang os: ubuntu-22.04