From cf378c36721c255afb41ac73abb667bb24ac68e0 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Sun, 2 Nov 2025 14:43:12 +0200 Subject: [PATCH] Migrate codebase to C++20 - VCMI can now be compiled in C++20 mode - Replaced all references to C++17 with C++20 - Boost 1.74 is now set as minimal version (older version might work but untested) - Updated documentation to reflect required versions of compilers / libraries - Removed excessive fail-fast / continue-on-error from CI --- .github/workflows/github.yml | 6 +----- CMakeLists.txt | 23 +++++++---------------- client/mapView/MapRendererContext.h | 5 +---- client/renderSDL/FontChain.cpp | 4 ++-- client/windows/CQuestLog.h | 5 ++++- docs/developers/Building_Linux.md | 8 ++++---- docs/developers/Coding_Guidelines.md | 17 +++++++++++++++-- lib/filesystem/CZipLoader.cpp | 4 ++-- lib/rmg/modificators/WaterProxy.cpp | 1 + lib/rmg/modificators/WaterProxy.h | 8 +------- lib/rmg/modificators/WaterRoutes.h | 8 +++++++- lib/spells/Problem.h | 2 ++ lib/spells/adventure/SummonBoatEffect.cpp | 2 +- 13 files changed, 48 insertions(+), 45 deletions(-) diff --git a/.github/workflows/github.yml b/.github/workflows/github.yml index c72c6e206..741e4901a 100644 --- a/.github/workflows/github.yml +++ b/.github/workflows/github.yml @@ -13,7 +13,6 @@ jobs: build: name: Build (${{ matrix.platform }}) strategy: - fail-fast: false # Do not cancel whole matrix when one build fails matrix: include: - platform: mac-intel @@ -126,10 +125,7 @@ jobs: artifact_platform: x64 runs-on: ${{ matrix.os }} - # Allow non-MSVC builds to fail without failing whole job - # This keeps pipeline moving so Windows Installer job can still run - # MSVC builds must success to continue to Windows Installer job - continue-on-error: ${{ !startsWith(matrix.platform, 'msvc') }} + defaults: run: shell: bash diff --git a/CMakeLists.txt b/CMakeLists.txt index 71cf571d6..9eb611d9b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -223,8 +223,9 @@ include(UseDoxygen OPTIONAL) # Compile and linking options # ############################################ -#Enable C++17 Globally -set (CMAKE_CXX_STANDARD 17) +set (CMAKE_CXX_STANDARD 20) +set (CMAKE_CXX_STANDARD_REQUIRED ON) + #General visibility options set(CMAKE_CXX_VISIBILITY_PRESET hidden) set(CMAKE_VISIBILITY_INLINES_HIDDEN 1) @@ -423,18 +424,8 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR NOT WIN32) endif() # Check if some platform-specific libraries are needed for linking -if(NOT WIN32 AND NOT IOS) - include(CheckLibraryExists) - - # Shared memory functions used by Boost.Interprocess - # FindBoost handle linking with pthreads, but doesn't handle this - CHECK_LIBRARY_EXISTS(rt shm_open "" HAVE_RT_LIB) - if(HAVE_RT_LIB) - set(SYSTEM_LIBS ${SYSTEM_LIBS} rt) - endif() - if(HAIKU) - set(SYSTEM_LIBS ${SYSTEM_LIBS} network) - endif() +if(HAIKU) + set(SYSTEM_LIBS ${SYSTEM_LIBS} network) endif() if(ENABLE_LUA) @@ -449,10 +440,10 @@ set(BOOST_COMPONENTS date_time filesystem locale program_options) if(ENABLE_INNOEXTRACT) list(APPEND BOOST_COMPONENTS iostreams) endif() -find_package(Boost 1.48.0 REQUIRED COMPONENTS ${BOOST_COMPONENTS}) +find_package(Boost 1.74.0 REQUIRED COMPONENTS ${BOOST_COMPONENTS}) if(Boost_MAJOR_VERSION EQUAL 1 AND Boost_MINOR_VERSION LESS 69) list(APPEND BOOST_COMPONENTS system) - find_package(Boost 1.48.0 REQUIRED COMPONENTS ${BOOST_COMPONENTS}) + find_package(Boost 1.74.0 REQUIRED COMPONENTS ${BOOST_COMPONENTS}) endif() find_package(ZLIB REQUIRED) diff --git a/client/mapView/MapRendererContext.h b/client/mapView/MapRendererContext.h index f9054ad42..21c344355 100644 --- a/client/mapView/MapRendererContext.h +++ b/client/mapView/MapRendererContext.h @@ -13,10 +13,7 @@ #include "../lib/GameConstants.h" #include "../lib/int3.h" - -VCMI_LIB_NAMESPACE_BEGIN -struct ObjectPosInfo; -VCMI_LIB_NAMESPACE_END +#include "../lib/spells/ViewSpellInt.h" struct MapRendererContextState; diff --git a/client/renderSDL/FontChain.cpp b/client/renderSDL/FontChain.cpp index 98f343d2f..4f35a7426 100644 --- a/client/renderSDL/FontChain.cpp +++ b/client/renderSDL/FontChain.cpp @@ -115,8 +115,8 @@ size_t FontChain::getGlyphWidthScaled(const char * data) const std::vector FontChain::splitTextToChunks(const std::string & data) const { - // U+FFFD - replacement character (question mark in rhombus) - static const std::string replacementCharacter = u8"�"; + // U+FFFD - replacement character (question mark in rhombus, '�') + static const std::string replacementCharacter = reinterpret_cast(u8"\ufffd"); std::vector chunks; diff --git a/client/windows/CQuestLog.h b/client/windows/CQuestLog.h index c9c4d7983..9ee450a86 100644 --- a/client/windows/CQuestLog.h +++ b/client/windows/CQuestLog.h @@ -9,11 +9,14 @@ */ #pragma once +#include "CWindowObject.h" + #include "../widgets/TextControls.h" #include "../widgets/MiscWidgets.h" #include "../widgets/Images.h" #include "../adventureMap/CMinimap.h" -#include "CWindowObject.h" + +#include "../../lib/gameState/QuestInfo.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/docs/developers/Building_Linux.md b/docs/developers/Building_Linux.md index d16622e0f..febd873d5 100644 --- a/docs/developers/Building_Linux.md +++ b/docs/developers/Building_Linux.md @@ -1,7 +1,7 @@ # Building VCMI for Linux -- Current baseline requirement for building is Ubuntu 20.04 -- Supported C++ compilers for UNIX-like systems are GCC 9+ and Clang 13+ +- Current baseline requirement for building is Ubuntu 22.04 or later +- Supported C++ compilers for UNIX-like systems are GCC 10+ and Clang 13+ Older distributions and compilers might work, but they aren't tested by Github CI (Actions) @@ -15,8 +15,8 @@ To compile, the following packages (and their development counterparts) are need - SDL2 with devel packages: mixer, image, ttf - minizip or minizip-ng - zlib and zlib-devel -- Boost C++ libraries v1.48+: program-options, filesystem, system, thread, locale -- Recommended, if you want to build launcher or map editor: Qt 5, widget and network modules +- Boost C++ libraries: program-options, filesystem, system, thread, locale +- Recommended, if you want to build launcher or map editor: Qt (widget and network modules) - Recommended, FFmpeg libraries, if you want to watch in-game videos: libavformat and libswscale. Their name could be libavformat-devel and libswscale-devel, or ffmpeg-libs-devel or similar names. - Optional: - if you want to build scripting modules: LuaJIT diff --git a/docs/developers/Coding_Guidelines.md b/docs/developers/Coding_Guidelines.md index 5c1706cc3..1de098e26 100644 --- a/docs/developers/Coding_Guidelines.md +++ b/docs/developers/Coding_Guidelines.md @@ -2,9 +2,22 @@ ## C++ Standard -VCMI implementation bases on C++17 standard. Any feature is acceptable as long as it's will pass build on our CI, but there is list below on what is already being used. +VCMI implementation bases on C++20 standard. Any feature is acceptable as long as it's will pass build on our CI. At the time of writing, following compilers are supported, and any C++20 feature available across all these compilers can be used: -Any compiler supporting C++17 should work, but this has not been thoroughly tested. You can find information about extensions and compiler support at +- GCC 10 or newer +- Clang 13 or newer +- Visual Studio 2022 (MSVC 19.44) +- XCode 16.2 (Apple Clang 16.0.0) + +You can find information about compiler support at . + +Additionally, features that require macOS 10.15 or newer are not available: + +- (C++17) Filesystem library +- (C++17) Elementary string conversions std::to_chars, std::from_chars +- (C++20) Synchronization library (, , and notification functions on std::atomic) +- (C++20) Add max() to latch and barrier +- (C++20) memory_resource ## Style Guidelines diff --git a/lib/filesystem/CZipLoader.cpp b/lib/filesystem/CZipLoader.cpp index 2e9555a5a..5e07f6eda 100644 --- a/lib/filesystem/CZipLoader.cpp +++ b/lib/filesystem/CZipLoader.cpp @@ -241,9 +241,9 @@ bool ZipArchive::extract(const boost::filesystem::path & where, const std::strin { #ifdef VCMI_WINDOWS if (fullName.size() < 260) - logGlobal->error("Failed to open file '%s'", fullName.c_str()); + logGlobal->error("Failed to open file '%s'", fullName.string()); else - logGlobal->error("Failed to open file with long path '%s' (%d characters)", fullName.c_str(), fullName.size()); + logGlobal->error("Failed to open file with long path '%s' (%d characters)", fullName.string(), fullName.size()); #else logGlobal->error("Failed to open file '%s'", fullName.c_str()); #endif diff --git a/lib/rmg/modificators/WaterProxy.cpp b/lib/rmg/modificators/WaterProxy.cpp index dd8e08caa..6d8f527fa 100644 --- a/lib/rmg/modificators/WaterProxy.cpp +++ b/lib/rmg/modificators/WaterProxy.cpp @@ -28,6 +28,7 @@ #include "ConnectionsPlacer.h" #include "../TileInfo.h" #include "WaterAdopter.h" +#include "WaterRoutes.h" #include "../RmgArea.h" #include diff --git a/lib/rmg/modificators/WaterProxy.h b/lib/rmg/modificators/WaterProxy.h index a370ec74a..df60ffdee 100644 --- a/lib/rmg/modificators/WaterProxy.h +++ b/lib/rmg/modificators/WaterProxy.h @@ -13,13 +13,7 @@ VCMI_LIB_NAMESPACE_BEGIN -struct RouteInfo -{ - rmg::Area blocked; - int3 visitable; - int3 boarding; - rmg::Area water; -}; +struct RouteInfo; class WaterProxy: public Modificator { diff --git a/lib/rmg/modificators/WaterRoutes.h b/lib/rmg/modificators/WaterRoutes.h index 2a12dfd96..c0a70246b 100644 --- a/lib/rmg/modificators/WaterRoutes.h +++ b/lib/rmg/modificators/WaterRoutes.h @@ -13,7 +13,13 @@ VCMI_LIB_NAMESPACE_BEGIN -struct RouteInfo; +struct RouteInfo +{ + rmg::Area blocked; + int3 visitable; + int3 boarding; + rmg::Area water; +}; class WaterRoutes: public Modificator { diff --git a/lib/spells/Problem.h b/lib/spells/Problem.h index c3d850cb3..33f106dca 100644 --- a/lib/spells/Problem.h +++ b/lib/spells/Problem.h @@ -12,6 +12,8 @@ #include +#include "../texts/MetaString.h" + VCMI_LIB_NAMESPACE_BEGIN namespace spells diff --git a/lib/spells/adventure/SummonBoatEffect.cpp b/lib/spells/adventure/SummonBoatEffect.cpp index 6216ece26..3c8207983 100644 --- a/lib/spells/adventure/SummonBoatEffect.cpp +++ b/lib/spells/adventure/SummonBoatEffect.cpp @@ -28,7 +28,7 @@ SummonBoatEffect::SummonBoatEffect(const CSpell * s, const JsonNode & config) { if (!config["createdBoat"].isNull()) { - LIBRARY->identifiers()->requestIdentifier("core:boat", config["createdBoat"], [=](int32_t boatTypeID) + LIBRARY->identifiers()->requestIdentifier("core:boat", config["createdBoat"], [this](int32_t boatTypeID) { createdBoat = BoatId(boatTypeID); });