From 3170852c8782556a35d0f72f3881ec7cabe48dbc Mon Sep 17 00:00:00 2001 From: Sandu Liviu Catalin Date: Fri, 2 Jan 2026 17:41:37 +0200 Subject: [PATCH 1/3] Implement CMake build scripts and github actions. Only Windows and Linux for now. Builds dependencies and links statically against them. Minimally intrusive approach. Only adds a few files and submodules. --- .github/workflows/linux.yml | 48 +++ .github/workflows/mingw.yml | 50 +++ .github/workflows/windows.yml | 45 +++ .gitignore | 2 + .gitmodules | 18 + CMakeLists.txt | 675 ++++++++++++++++++++++++++++++++++ CTestConfig.cmake | 17 + appveyor.yml | 53 +++ cmake/CI.CTestScript.cmake | 38 ++ cmake/CTestCustom.cmake.in | 10 + cmake/CopyDllsForDebug.cmake | 35 ++ cmake/Coverage.cmake | 110 ++++++ cmake/LTO.cmake | 253 +++++++++++++ cmake/VALHALLAConfig.cmake.in | 17 + cmake/Warnings.cmake | 156 ++++++++ external/CMakeLists.txt | 85 +++++ external/SDL2 | 1 + external/SDL_image | 1 + external/SDL_mixer | 1 + external/doctest | 1 + external/libmaxminddb | 1 + source/shared/cube.h | 5 +- tests/CMakeLists.txt | 28 ++ tests/failtest.cpp | 21 ++ tests/successtest.cpp | 31 ++ 25 files changed, 1701 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/linux.yml create mode 100644 .github/workflows/mingw.yml create mode 100644 .github/workflows/windows.yml create mode 100644 CMakeLists.txt create mode 100644 CTestConfig.cmake create mode 100644 appveyor.yml create mode 100644 cmake/CI.CTestScript.cmake create mode 100644 cmake/CTestCustom.cmake.in create mode 100644 cmake/CopyDllsForDebug.cmake create mode 100644 cmake/Coverage.cmake create mode 100644 cmake/LTO.cmake create mode 100644 cmake/VALHALLAConfig.cmake.in create mode 100644 cmake/Warnings.cmake create mode 100644 external/CMakeLists.txt create mode 160000 external/SDL2 create mode 160000 external/SDL_image create mode 160000 external/SDL_mixer create mode 160000 external/doctest create mode 160000 external/libmaxminddb create mode 100644 tests/CMakeLists.txt create mode 100644 tests/failtest.cpp create mode 100644 tests/successtest.cpp diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml new file mode 100644 index 000000000..f7c75588b --- /dev/null +++ b/.github/workflows/linux.yml @@ -0,0 +1,48 @@ +name: Linux +permissions: + contents: read + +on: + push: + # Always trigger CI on push + pull_request: + branches: [ $default-branch ] + + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) + buildtype: [Debug, Release] + env: + BUILD_TYPE: ${{ matrix.buildtype }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + # So we can skip the `data` submodule. + #with: + #submodules: 'recursive' + # Same as above, but skip the `data` submodule. + - name: Checkout submodules + run: git -c submodule."data".update=none submodule update --init --recursive + + - name: Install libraries + run: sudo apt update && sudo apt install -y build-essential freeglut3-dev + + - name: Configure CMake + # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. + # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type + run: cmake -B ${{runner.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DENABLE_LTO=FALSE + + - name: Build + # Build your program with the given configuration + run: cmake --build ${{runner.workspace}}/build --config ${{env.BUILD_TYPE}} + + - name: Test + working-directory: ${{runner.workspace}}/build + # Execute tests defined by the CMake configuration. + # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail + run: ctest -C ${{env.BUILD_TYPE}} + diff --git a/.github/workflows/mingw.yml b/.github/workflows/mingw.yml new file mode 100644 index 000000000..238f0ed94 --- /dev/null +++ b/.github/workflows/mingw.yml @@ -0,0 +1,50 @@ +name: MinGW +permissions: + contents: read + +on: + push: + # Always trigger CI on push + pull_request: + branches: [ $default-branch ] + + +jobs: + build: + runs-on: windows-latest + strategy: + matrix: + # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) + buildtype: [Debug, Release] + env: + BUILD_TYPE: ${{ matrix.buildtype }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + # So we can skip the `data` submodule. + #with: + #submodules: 'recursive' + # Same as above, but skip the `data` submodule. + - name: Checkout submodules + run: git -c submodule."data".update=none submodule update --init --recursive + + - name: Set up MinGW + uses: egor-tensin/setup-mingw@v3 + with: + platform: x64 + + - name: Configure CMake + # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. + # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type + run: cmake -B ${{runner.workspace}}/build -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DENABLE_LTO=FALSE + + - name: Build + # Build your program with the given configuration + run: cmake --build ${{runner.workspace}}/build --config ${{env.BUILD_TYPE}} + + - name: Test + working-directory: ${{runner.workspace}}/build + # Execute tests defined by the CMake configuration. + # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail + run: ctest -C ${{env.BUILD_TYPE}} + diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml new file mode 100644 index 000000000..1a7953376 --- /dev/null +++ b/.github/workflows/windows.yml @@ -0,0 +1,45 @@ +name: Windows +permissions: + contents: read + +on: + push: + # Always trigger CI on push + pull_request: + branches: [ $default-branch ] + + +jobs: + build: + runs-on: windows-latest + strategy: + matrix: + # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) + buildtype: [Debug, Release] + env: + BUILD_TYPE: ${{ matrix.buildtype }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + # So we can skip the `data` submodule. + #with: + #submodules: 'recursive' + # Same as above, but skip the `data` submodule. + - name: Checkout submodules + run: git -c submodule."data".update=none submodule update --init --recursive + + - name: Configure CMake + # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. + # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type + run: cmake -B ${{runner.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DENABLE_LTO=FALSE + + - name: Build + # Build your program with the given configuration + run: cmake --build ${{runner.workspace}}/build --config ${{env.BUILD_TYPE}} + + - name: Test + working-directory: ${{runner.workspace}}/build + # Execute tests defined by the CMake configuration. + # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail + run: ctest -C ${{env.BUILD_TYPE}} + diff --git a/.gitignore b/.gitignore index 77ca8c597..7e047478a 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,8 @@ source/vcpp/x86/ .vscode/ Debug*/ Release*/ +.*-Debug/ +.*-Release/ Profile*/ autoexec.cfg master.cfg diff --git a/.gitmodules b/.gitmodules index 00cb69336..aea62e20e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,21 @@ [submodule "data"] path = data url = https://github.com/project-valhalla/data.git +[submodule "external/SDL2"] + path = external/SDL2 + url = https://github.com/libsdl-org/SDL.git + branch = SDL2 +[submodule "external/SDL_image"] + path = external/SDL_image + url = https://github.com/libsdl-org/SDL_image.git + branch = SDL2 +[submodule "external/SDL_mixer"] + path = external/SDL_mixer + url = https://github.com/libsdl-org/SDL_mixer.git + branch = SDL2 +[submodule "external/doctest"] + path = external/doctest + url = https://github.com/onqtam/doctest.git +[submodule "external/libmaxminddb"] + path = external/libmaxminddb + url = https://github.com/maxmind/libmaxminddb.git diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..8f698de37 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,675 @@ +# +# Main CMakelists for the VALHALLA project. +# +# It aims to be a template and a CMake reference, and as such is documented as much as possible. +# While everything might not fit in any project, it should give good defaults and avoid CMake antipatterns. +# If you disagree with some pieces of advice given here, please discuss it with me by opening a Github Issue ! +# +# Project specific options : +# - VALHALLA_BUILD_TESTS (requires BUILD_TESTING set to ON) +# Other options might be available through the cmake scripts including (not exhaustive): +# - ENABLE_WARNINGS_SETTINGS +# - ENABLE_LTO +# + +# Tells cmake the minimum version supported is 3.16, but has been updated to work with 3.29 policies +# It is recommended to use the `cmake_minimum_required(VERSION [...])` syntax to indicate the max version that was known to work. +# Many projects broke when CMake 4.0 was released even though they should have been compatible. +cmake_minimum_required(VERSION 3.16...3.29) + +if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) + message(FATAL_ERROR "Do not build in-source. Please remove CMakeCache.txt and the CMakeFiles/ directory. Then build out-of-source.") +endif() + +# Put the project early since modules might need to detect the compiler. +# More information https://cmake.org/cmake/help/latest/command/project.html +project( + "VALHALLA" # This will exposed as the variable PROJECT_NAME. + VERSION 0.1.0 # Used for installation and defines variables PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR, PROJECT_VERSION_PATCH, and PROJECT_VERSION_TWEAK. + LANGUAGES C CXX # Used to determine the languages to use based on file extensions +) + +############################ +## Modules and scripts ## +############################ + +# Standard CMake modules + +include(CTest) # Must be called before adding tests but after calling project(). This automatically calls enable_testing() and configures ctest targets when using Make/Ninja +include(CMakeDependentOption) # This is a really useful scripts that creates options that depends on other options. It can even be used with generator expressions ! +include(GNUInstallDirs) # This will define the default values for installation directories (all platforms even if named GNU) +include(InstallRequiredSystemLibraries) # Tell CMake that the `install` target needs to install required system libraries (eg: Windows SDK) +include(CMakePackageConfigHelpers) # Helper to create relocatable packages + +# Custom modules and scripts + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") # Make our cmake scripts available + +include(LTO) +include(Warnings) +include(CopyDllsForDebug) +include(Coverage) + +############### +## OPTIONS ## +############### + +# You should try to give as much control over the project setup to the user. +# When modifying compile flags for example, if they are not mandatory, provide an option. + +option(${PROJECT_NAME}_INSTALL "Should ${PROJECT_NAME} be added to the install list? Useful if included using add_subdirectory." ON) + +# Use your own option for tests, in case people use your library through add_subdirectory +cmake_dependent_option(${PROJECT_NAME}_BUILD_TESTS + "Enable ${PROJECT_NAME} project tests targets" ON # By default we want tests if CTest is enabled + "BUILD_TESTING" OFF # Stay coherent with CTest variables +) + +# External dependencies +add_subdirectory(external EXCLUDE_FROM_ALL) + +# It is always easier to navigate in an IDE when projects are organized in folders. +set_property(GLOBAL PROPERTY USE_FOLDERS ON) + +# Whe building a shared library, you do not want to export all symbols by default +# gcc (and hence clang) are wrong about this. +# +# For more information, see https://gcc.gnu.org/wiki/Visibility and https://www.youtube.com/embed/m0DwB4OvDXk +set(CMAKE_CXX_VISIBILITY_PRESET hidden) +set(CMAKE_VISIBILITY_INLINES_HIDDEN 1) + +############### +## Project ## +############### + +# Check for LTO support (needs to be after project(...) ) +find_lto(CXX) + +# We use this on windows to add executable icons and other resources +# This is a stupid workaround because if we use .rc files, it will cause our build to fail +# This seems to be caused by the fact that CMake doesn't wrapp paths with quotes and if they contain white-space, +# we will get a bunch of "No such file or directory" compiler errors. And I haven't been able to find a workaround, yet +# other than "don't have your compiler in a path with spaces!" +if(MSYS OR MINGW) + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(RCEDIT_EXE_NAME "rcedit-x64.exe") + else() + set(RCEDIT_EXE_NAME "rcedit-x86.exe") + endif() + include(FetchContent) + FetchContent_Declare( + rcedit + URL "https://github.com/electron/rcedit/releases/download/v2.0.0/${RCEDIT_EXE_NAME}" + DOWNLOAD_NO_EXTRACT TRUE + DOWNLOAD_NAME ${RCEDIT_EXE_NAME} + ) + FetchContent_MakeAvailable(rcedit) + FetchContent_GetProperties(rcedit SOURCE_DIR RCEDIT_SOURCE_DIR) + cmake_path(APPEND RCEDIT_SOURCE_DIR "${RCEDIT_EXE_NAME}" OUTPUT_VARIABLE RCEDIT_EXE_PATH) +endif() + +#==========================# +# Enet library # +#==========================# + +# Note that we use both the include and source folders for headers, based on wether they are part of the public API or not. +# For more information about this rationale, see https://github.com/vector-of-bool/pitchfork +add_library(enet + source/enet/callbacks.c + source/enet/compress.c + source/enet/host.c + source/enet/list.c + source/enet/packet.c + source/enet/peer.c + source/enet/protocol.c + # While these two could be added only on their speciffic platform by cmake, they have include guards for anything else and works better this way + source/enet/unix.c + source/enet/win32.c + # Headers (not necessary but...) + source/enet/include/enet/callbacks.h + source/enet/include/enet/enet.h + source/enet/include/enet/list.h + source/enet/include/enet/protocol.h + source/enet/include/enet/time.h + source/enet/include/enet/types.h + source/enet/include/enet/unix.h + source/enet/include/enet/utility.h + source/enet/include/enet/win32.h +) + +# Setup include folders +target_include_directories(enet + PUBLIC + $ + PRIVATE + $ +) + +# Platform speciffic options +if(MSVC OR MSYS OR MINGW) + target_link_libraries(enet PUBLIC ws2_32) +endif() + +# Check for existence of some platform speciffic functions +include(CheckSymbolExists) +# Check for function getaddrinfo +check_symbol_exists(getaddrinfo "netdb.h" HAS_GETADDRINFO) +if(HAS_GETADDRINFO) + target_compile_definitions(enet PRIVATE HAS_GETADDRINFO=1) +endif() +# Check for function getnameinfo +check_symbol_exists(getnameinfo "netdb.h" HAS_GETNAMEINFO) +if(HAS_GETNAMEINFO) + target_compile_definitions(enet PRIVATE HAS_GETNAMEINFO=1) +endif() +# Check for function gethostbyaddr_r +check_symbol_exists(gethostbyaddr_r "netdb.h" HAS_GETHOSTBYADDR_R) +if(HAS_GETHOSTBYADDR_R) + target_compile_definitions(enet PRIVATE HAS_GETHOSTBYADDR_R=1) +endif() +# Check for function gethostbyname_r +check_symbol_exists(gethostbyname_r "netdb.h" HAS_GETHOSTBYNAME_R) +if(HAS_GETHOSTBYNAME_R) + target_compile_definitions(enet PRIVATE HAS_GETHOSTBYNAME_R=1) +endif() +# Check for function poll +check_symbol_exists(poll "poll.h" HAS_POLL) +if(HAS_POLL) + target_compile_definitions(enet PRIVATE HAS_POLL=1) +endif() +# Check for function fcntl +check_symbol_exists(fcntl "fcntl.h" HAS_FCNTL) +if(HAS_FCNTL) + target_compile_definitions(enet PRIVATE HAS_FCNTL=1) +endif() +# Check for function inet_pton +check_symbol_exists(inet_pton "arpa/inet.h" HAS_INET_PTON) +if(HAS_INET_PTON) + target_compile_definitions(enet PRIVATE HAS_INET_PTON=1) +endif() +# Check for function inet_ntop +check_symbol_exists(inet_ntop "arpa/inet.h" HAS_INET_NTOP) +if(HAS_INET_NTOP) + target_compile_definitions(enet PRIVATE HAS_INET_NTOP=1) +endif() + +include(CheckStructHasMember) +# Check for function struct msghdr has msg_flags member +CHECK_STRUCT_HAS_MEMBER("struct msghdr" msg_flags "sys/socket.h" HAS_MSGHDR_FLAGS LANGUAGE C) +if(HAS_INET_NTOP) + target_compile_definitions(enet PRIVATE HAS_MSGHDR_FLAGS=1) +endif() + +include(CheckTypeSize) +# Check for size of socklen_t +check_type_size(socklen_t SIZEOF_SOCKLEN_T) +if(HAVE_SIZEOF_SOCKLEN_T AND NOT "${SIZEOF_SOCKLEN_T}" STREQUAL "" AND NOT "${SIZEOF_SOCKLEN_T}" STREQUAL "0") + target_compile_definitions(enet PRIVATE HAS_SOCKLEN_T=1) +endif() + +#==========================# +# System info # +#==========================# + +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(VH_ARCH_BITS "64") +else() + set(VH_ARCH_BITS "32") +endif() + +if(MSVC OR MSYS OR MINGW) + set(VH_BIN_DIR_NAME "bin${VH_ARCH_BITS}") + set(VH_BIN_EXT ".exe") + set(CLIENT_BIN_NAME "valhalla") + set(SERVER_BIN_NAME "valhalla_server") + set(MASTER_BIN_NAME "valhalla_master") +elseif(UNIX AND NOT APPLE) + set(VH_BIN_DIR_NAME "bin_unix") + set(VH_BIN_EXT "") + set(CLIENT_BIN_NAME "linux_${VH_ARCH_BITS}_client") + set(SERVER_BIN_NAME "linux_${VH_ARCH_BITS}_server") + set(MASTER_BIN_NAME "linux_${VH_ARCH_BITS}_master") +endif() + +#==========================# +# Client executable # +#==========================# + +# Client source files +set(CLIENT_SOURCES + source/shared/crypto.cpp + source/shared/geom.cpp + source/shared/glemu.cpp + source/shared/stream.cpp + source/shared/tools.cpp + source/shared/zip.cpp + source/engine/aa.cpp + source/engine/bih.cpp + source/engine/blend.cpp + source/engine/client.cpp + source/engine/command.cpp + source/engine/console.cpp + source/engine/dynlight.cpp + source/engine/grass.cpp + source/engine/light.cpp + source/engine/main.cpp + source/engine/material.cpp + source/engine/menus.cpp + source/engine/movie.cpp + source/engine/normal.cpp + source/engine/octa.cpp + source/engine/octaedit.cpp + source/engine/octarender.cpp + source/engine/physics.cpp + source/engine/pvs.cpp + source/engine/rendergl.cpp + source/engine/renderlights.cpp + source/engine/rendermodel.cpp + source/engine/renderparticles.cpp + source/engine/rendersky.cpp + source/engine/rendertext.cpp + source/engine/renderva.cpp + source/engine/server.cpp + source/engine/serverbrowser.cpp + source/engine/shader.cpp + source/engine/sound.cpp + source/engine/stain.cpp + source/engine/texture.cpp + source/engine/ui.cpp + source/engine/liquid.cpp + source/engine/world.cpp + source/engine/worldio.cpp + source/game/ai.cpp + source/game/gameclient.cpp + source/game/entity.cpp + source/game/game.cpp + source/game/render.cpp + source/game/scoreboard.cpp + source/game/gameserver.cpp + source/game/waypoint.cpp + source/game/monster.cpp + source/game/weapon.cpp + source/game/gamephysics.cpp + source/game/hud.cpp + source/game/projectile.cpp + source/game/announcer.cpp + source/game/camera.cpp + source/game/event.cpp + source/game/query.cpp + source/game/worlddata.cpp + source/game/gameshader.cpp +) + +# Always list the source files explicitly, including headers so that they are listed in the IDE +# If you need to use files based on a variable value, use target_sources +if(WIN32) + add_executable(Client WIN32 ${CLIENT_SOURCES}) +else() + add_executable(Client ${CLIENT_SOURCES}) +endif() + +# Configure include folders +target_include_directories(Client + PRIVATE + $ + $ + $ +) + +# Configure third-party libraries +target_link_libraries(Client + #PUBLIC # Useful for libraries, see https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html for more details about transitive usage requirements. + #libraries/targets to link when linking this library + #this will automatically setup the needed flags and dependencies when linking against this target + PRIVATE # The following libraries are only linked for this target, and its flags/dependencies will not be used when linking against this target + general zlibstatic enet SDL2::SDL2-static SDL2_image::SDL2_image-static SDL2_mixer::SDL2_mixer-static # It is possible to link some libraries for debug or optimized builds only + #debug DEBUGLIBS + #optimized RELEASELIBS +) + +# Specify that we're linking to a static version of zlib +target_compile_definitions(Client PRIVATE ZLIB_STATIC=1) + +# Platform speciffic options +if(MSVC OR MSYS OR MINGW) + if(MSYS OR MINGW) + target_compile_options(Client PRIVATE -fomit-frame-pointer -ffast-math -Wimplicit-fallthrough -fsigned-char -fno-exceptions -fno-rtti) + target_link_options(Client PRIVATE -mwindows -static-libgcc -static-libstdc++) + # Configure executable resources post-build (workaround for .rc causing build errors if compiler path includes spaces) + add_custom_command( + TARGET Client POST_BUILD + COMMAND ${RCEDIT_EXE_PATH} $ --set-icon "${CMAKE_CURRENT_SOURCE_DIR}/source/vcpp/valhalla.ico" + COMMENT "Adding client executable icon." + VERBATIM + ) + else() + # MSVC needs this or release builds will fail + target_link_libraries(Client PRIVATE dbghelp) + # We don't need the workaround for MSVC + enable_language("RC") + target_sources(Client PRIVATE source/vcpp/valhalla.rc) + endif() + target_link_libraries(Client PRIVATE winmm) +elseif(UNIX AND NOT APPLE) + # Find and link X11 + find_package(X11) + if(X11_FOUND) + target_link_libraries(Client PRIVATE X11::X11) + endif() +endif() +# Put the executable in the bin folder +add_custom_command( + TARGET Client POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy $ "${CMAKE_CURRENT_SOURCE_DIR}/bin/${VH_BIN_DIR_NAME}/${CLIENT_BIN_NAME}${VH_BIN_EXT}" + COMMENT "Copying client executable to bin/${VH_BIN_DIR_NAME} folder." + VERBATIM +) + +# Find and link OpeGL +find_package(OpenGL COMPONENTS OpenGL) +if(OpenGL_FOUND) + target_link_libraries(Client PRIVATE OpenGL::GL) +endif() + +# Require c++11, this is better than setting CMAKE_CXX_STANDARD since it won't pollute other targets +# note : cxx_std_* features were added in CMake 3.8.2 +target_compile_features(Client PRIVATE cxx_std_11) + +# CMake scripts extensions +# Helper that can set default warning flags for you +if(NOT MSVC) + target_set_warnings(Client ENABLE ALL DISABLE Annoying extra pedantic unused ignored-qualifiers cast-function-type) +else() + target_set_warnings(Client DISABLE ALL) # MSVC has a lot to say about this code. let's ignore it +endif() + +target_enable_lto(Client optimized) #enable lto if available for non-debug configurations +copy_dlls_for_debug(Client "" "") # Copy dependencies next to the executable (DLLs for example) + +# Setup our project as the startup project for Visual so that people don't need to do it manually +set_directory_properties(PROPERTIES VS_STARTUP_PROJECT Client) + + +#==========================# +# Server executable # +#==========================# + +# Server source files +set(SERVER_SOURCES + source/shared/crypto.cpp + source/shared/stream.cpp + source/shared/tools.cpp + source/engine/command.cpp + source/engine/server.cpp + source/engine/worldio.cpp + source/game/entity.cpp + source/game/gameserver.cpp +) + +# Always list the source files explicitly, including headers so that they are listed in the IDE +# If you need to use files based on a variable value, use target_sources +if(WIN32) + add_executable(Server WIN32 ${SERVER_SOURCES}) +else() + add_executable(Server ${SERVER_SOURCES}) +endif() + +# Configure include folders +target_include_directories(Server + PRIVATE + $ + $ + $ +) + +# Configure third-party libraries +target_link_libraries(Server + #PUBLIC # Useful for libraries, see https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html for more details about transitive usage requirements. + #libraries/targets to link when linking this library + #this will automatically setup the needed flags and dependencies when linking against this target + PRIVATE # The following libraries are only linked for this target, and its flags/dependencies will not be used when linking against this target + general zlibstatic enet# It is possible to link some libraries for debug or optimized builds only + #debug DEBUGLIBS + #optimized RELEASELIBS +) + +# Specify that we're linking to a static version of zlib and rendering is not necessary +target_compile_definitions(Server PRIVATE ZLIB_STATIC=1 STANDALONE=1) + +# TODO: find out why lib maxminddb doesn't like MSVC +if(NOT MSVC) + target_link_libraries(Server PRIVATE maxminddb::maxminddb) + target_compile_definitions(Server PRIVATE HAVE_MAXMINDDB=1) +endif() + +# Platform speciffic options +if(MSVC OR MSYS OR MINGW) + if(MSYS OR MINGW) + target_compile_options(Server PRIVATE -fomit-frame-pointer -ffast-math -Wimplicit-fallthrough -fsigned-char -fno-exceptions -fno-rtti) + target_link_options(Server PRIVATE -mwindows -static-libgcc -static-libstdc++) + # Configure executable resources post-build (workaround for .rc causing build errors if compiler path includes spaces) + add_custom_command( + TARGET Server POST_BUILD + COMMAND ${RCEDIT_EXE_PATH} $ --set-icon "${CMAKE_CURRENT_SOURCE_DIR}/source/vcpp/valhalla.ico" + COMMENT "Adding server executable icon." + VERBATIM + ) + else() + # We don't need the workaround for MSVC + enable_language("RC") + target_sources(Server PRIVATE source/vcpp/valhalla.rc) + endif() + target_link_libraries(Server PRIVATE opengl32 winmm) +endif() + +# Put the executable in the bin folder +add_custom_command( + TARGET Server POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy $ "${CMAKE_CURRENT_SOURCE_DIR}/bin/${VH_BIN_DIR_NAME}/${SERVER_BIN_NAME}${VH_BIN_EXT}" + COMMENT "Copying server executable to bin/${VH_BIN_DIR_NAME} folder." + VERBATIM +) + +# Require c++11, this is better than setting CMAKE_CXX_STANDARD since it won't pollute other targets +# note : cxx_std_* features were added in CMake 3.8.2 +target_compile_features(Server PRIVATE cxx_std_11) + +# CMake scripts extensions +# Helper that can set default warning flags for you +if(NOT MSVC) + target_set_warnings(Server ENABLE ALL DISABLE Annoying extra pedantic unused ignored-qualifiers cast-function-type) +else() + target_set_warnings(Server DISABLE ALL) # MSVC has a lot to say about this code. let's ignore it +endif() + +target_enable_lto(Server optimized) #enable lto if available for non-debug configurations +copy_dlls_for_debug(Server "" "") # Copy dependencies next to the executable (DLLs for example) + +#==========================# +# Master executable # +#==========================# + +# Master source files +set(MASTER_SOURCES + source/shared/crypto.cpp + source/shared/stream.cpp + source/shared/tools.cpp + source/engine/command.cpp + source/engine/master.cpp +) + +# Always list the source files explicitly, including headers so that they are listed in the IDE +# If you need to use files based on a variable value, use target_sources +add_executable(Master ${MASTER_SOURCES}) + +# Configure include folders +target_include_directories(Master + PRIVATE + $ + $ + $ +) + +# Configure third-party libraries +target_link_libraries(Master + #PUBLIC # Useful for libraries, see https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html for more details about transitive usage requirements. + #libraries/targets to link when linking this library + #this will automatically setup the needed flags and dependencies when linking against this target + PRIVATE # The following libraries are only linked for this target, and its flags/dependencies will not be used when linking against this target + general zlibstatic enet # It is possible to link some libraries for debug or optimized builds only + #debug DEBUGLIBS + #optimized RELEASELIBS +) + +# Specify that we're linking to a static version of zlib and rendering is not necessary +target_compile_definitions(Master PRIVATE ZLIB_STATIC=1 STANDALONE=1) + +# TODO: find out why lib maxminddb doesn't like MSVC +if(NOT MSVC) + target_link_libraries(Master PRIVATE maxminddb::maxminddb) + target_compile_definitions(Master PRIVATE HAVE_MAXMINDDB=1) +endif() + +# Platform speciffic options +if(MSVC OR MSYS OR MINGW) + if(MSYS OR MINGW) + target_compile_options(Master PRIVATE -fomit-frame-pointer -ffast-math -Wimplicit-fallthrough -fsigned-char -fno-exceptions -fno-rtti) + target_link_options(Master PRIVATE -mwindows -static-libgcc -static-libstdc++) + # Configure executable resources post-build (workaround for .rc causing build errors if compiler path includes spaces) + add_custom_command( + TARGET Master POST_BUILD + COMMAND ${RCEDIT_EXE_PATH} $ --set-icon "${CMAKE_CURRENT_SOURCE_DIR}/source/vcpp/valhalla.ico" + COMMENT "Adding master executable icon." + VERBATIM + ) + else() + # We don't need the workaround for MSVC + enable_language("RC") + target_sources(Master PRIVATE source/vcpp/valhalla.rc) + endif() + target_link_libraries(Master PRIVATE opengl32 winmm) +endif() + +# Put the executable in the bin folder +add_custom_command( + TARGET Master POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy $ "${CMAKE_CURRENT_SOURCE_DIR}/bin/${VH_BIN_DIR_NAME}/${MASTER_BIN_NAME}${VH_BIN_EXT}" + COMMENT "Copying server executable to bin/${VH_BIN_DIR_NAME} folder." + VERBATIM +) + +# Require c++11, this is better than setting CMAKE_CXX_STANDARD since it won't pollute other targets +# note : cxx_std_* features were added in CMake 3.8.2 +target_compile_features(Master PRIVATE cxx_std_11) + +# CMake scripts extensions +# Helper that can set default warning flags for you +if(NOT MSVC) + target_set_warnings(Master ENABLE ALL DISABLE Annoying extra pedantic unused ignored-qualifiers cast-function-type) +else() + target_set_warnings(Master DISABLE ALL) # MSVC has a lot to say about this code. let's ignore it +endif() + +target_enable_lto(Master optimized) #enable lto if available for non-debug configurations +copy_dlls_for_debug(Master "" "") # Copy dependencies next to the executable (DLLs for example) + +#===========# +# Tests # +#===========# + +if(${PROJECT_NAME}_BUILD_TESTS) + # Let the user add options to the test runner if needed + set(TEST_RUNNER_PARAMS "--force-colors=true" CACHE STRING "Options to add to our test runners commands") + # In a real project you most likely want to exclude test folders + # list(APPEND CUSTOM_COVERAGE_EXCLUDE "/test/") + add_subdirectory(tests) + # You can setup some custom variables and add them to the CTestCustom.cmake.in template to have custom ctest settings + # For example, you can exclude some directories from the coverage reports such as third-parties and tests + configure_file( + ${CMAKE_CURRENT_LIST_DIR}/cmake/CTestCustom.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/CTestCustom.cmake + @ONLY + ) +endif() + +############### +## Packaging ## +############### + +if(${PROJECT_NAME}_INSTALL) + # If we want to use CPack, we need to include it so that it populates variables from our CMakeLists.txt. + # This will also create a `package` target on supported build systems (make, ninja, VS). + # There are various CPACK_* variables you can set before `include(CPack)` to configure it (see https://cmake.org/cmake/help/latest/module/CPack.html#variables-common-to-all-cpack-generators). + set(CPACK_RESOURCE_FILE_README ${CMAKE_CURRENT_LIST_DIR}/readme.md) + include(CPack) + + # Let users choose where to install the cmake package descriptions + # For that we make use of the CMake Cache + set(${PROJECT_NAME}_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" CACHE STRING "Path to install ${PROJECT_NAME} Config*.cmake files to.") + set(${PROJECT_NAME}_MODULE_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake" CACHE STRING "Path to install ${PROJECT_NAME}'s .cmake module files to.") + + # Use version checking helper provided by CMake so that users can safely use a version number in their find_package calls + write_basic_package_version_file( + ${PROJECT_NAME}ConfigVersion.cmake # The name of the version file needed by find_package. + VERSION ${PROJECT_VERSION} # The version of the project, already set by the `project` command at the top of this file + COMPATIBILITY SameMajorVersion # We use semantic versioning, backward compatibity is only guaranteed for a same major version + ) + + + # We will need our own file if we have our own dependencies or want some special behavior when the user calls find_package + # otherwise we could simply install the exports as the ${PROJECT_NAME}Config.cmake + configure_package_config_file( + ${PROJECT_SOURCE_DIR}/cmake/${PROJECT_NAME}Config.cmake.in # This is your template file + ${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake # This is the resulting file + INSTALL_DESTINATION ${${PROJECT_NAME}_INSTALL_CMAKEDIR} # This is where the file will be installed + # List of paths that needs to be relocated once installed + # For example if the variable containing the path is named MY_PATH, all instances of @PACKAGE_MY_PATH@ in the template will be replaced by the relocated version of the path + # This is mostly only needed when you want to install cmake modules or have an unusual layout that cmake is not aware of. + PATH_VARS ${PROJECT_NAME}_MODULE_INSTALL_DIR # This will be exposed as @PACKAGE_VALHALLA_MODULE_INSTALL_DIR@ in the template file + # Imported targets do not require the following macros + NO_SET_AND_CHECK_MACRO + NO_CHECK_REQUIRED_COMPONENTS_MACRO + ) + + + # The following will export the targets under the name ${PROJECT_NAME}_Targets, not install them yet + # It will then need a call to `install(EXPORT)` + install( + TARGETS # We can install executables + Client + Server + Master + EXPORT ${PROJECT_NAME}_Targets + # Following is only needed pre-cmake3.14 + # RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + # LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + # ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + # Note PUBLIC_HEADER DESTINATION is necessary only if you provide RUNTIME/LIBRARY/ARCHIVE otherwise CMake will map it to the INCLUDES destination (CMake will warn you with "INSTALL TARGETS - target Client has PUBLIC_HEADER files but no PUBLIC_HEADER DESTINATION." ) + # PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + # If you want to split between runtime and dev for examples, take a look at COMPONENT, NAMELINK_COMPONENT etc + # More info in Craig Scott's talk "Deep CMake for library authors" https://www.youtube.com/watch?v=m0DwB4OvDXk + INCLUDES + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + ) + + # This time, install all the exported targets under the ${PROJECT_NAME}_Targets name. + install( + EXPORT ${PROJECT_NAME}_Targets + NAMESPACE ${PROJECT_NAME}:: # Always specify a namespace so that users can make sure they link targets with transitive properties and not only the library + FILE ${PROJECT_NAME}Targets.cmake # This is the file that needs to be included from your *Config.cmake. Otherwise, you could just make this your actual *Config.cmake file. + DESTINATION ${${PROJECT_NAME}_INSTALL_CMAKEDIR} + ) + + + # So far we only installed the exported targets, now install the package config files. + # If you do not list headers in the PUBLIC_HEADER property, you will need to copy them using `install(FILES)` or `install(DIRECTORY)` too. + # In that case, you can use CMAKE_INSTALL_INCLUDEDIR as the base destination path. + install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake + DESTINATION + ${${PROJECT_NAME}_INSTALL_CMAKEDIR} + ) + +endif() + diff --git a/CTestConfig.cmake b/CTestConfig.cmake new file mode 100644 index 000000000..c18c25151 --- /dev/null +++ b/CTestConfig.cmake @@ -0,0 +1,17 @@ +set(CTEST_PROJECT_NAME "cpp-uh") +set(CTEST_NIGHTLY_START_TIME "01:00:00 UTC") + +set(CTEST_DROP_METHOD "http") +set(CTEST_DROP_SITE "my.cdash.org") +set(CTEST_DROP_LOCATION "/submit.php?project=cpp-uh") +set(CTEST_DROP_SITE_CDASH TRUE) + +# In case where you don't want to submit your reports to CDash, +# You can : +# - use CTest in script mode and not call the Submit step +# - Call the various steps directly from make/ninja (targets are {Mode}{Step}) +# where Mode is Nightly, Continuous, or Experimental +# and Step is one of Start Update Configure Build Test Coverage MemCheck +# Check the CTest documentation for more details +# - Same but using the 'ctest' command line +# - set(CTestSubmitRetryCount 0) and wait for timeout but this will return an error ? \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 000000000..fbb8ee4bd --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,53 @@ +#---------------------------------# +# environment configuration # +#---------------------------------# + +# Build worker image (VM template) +image: Visual Studio 2015 + +clone_depth: 3 + +platform: + - Win32 + - x64 + +configuration: + - Debug + - Release + +environment: + matrix: + - TOOLSET: v140 +# - TOOLSET: v140_clang_c2 + +matrix: + fast_finish: true + allow_failures: + - TOOLSET: v140_clang_c2 + +# scripts that are called at very beginning, before repo cloning +init: + - cmd: cmake --version + - cmd: msbuild /version + +install: + - git submodule update --init --recursive + +before_build: + - mkdir build + - cd build + - if "%platform%"=="Win32" set CMAKE_GENERATOR_NAME=Visual Studio 14 2015 + - if "%platform%"=="x64" set CMAKE_GENERATOR_NAME=Visual Studio 14 2015 Win64 + - cmake -G "%CMAKE_GENERATOR_NAME%" -T %TOOLSET% -DCMAKE_BUILD_TYPE=%configuration% -DUH_BUILD_TESTS=ON .. + - cd .. + +build: + project: build/UH.sln + parallel: true + verbosity: minimal + +test_script: + - cd build + - ctest -C %configuration% . + - cd .. + diff --git a/cmake/CI.CTestScript.cmake b/cmake/CI.CTestScript.cmake new file mode 100644 index 000000000..794fdbc7c --- /dev/null +++ b/cmake/CI.CTestScript.cmake @@ -0,0 +1,38 @@ +# It might be better than calling 'make Continuous' for CI such as travis since it will skip the update step while still doing the later steps +# It is also makes it easier to customize the test runs and show the output since we can use command-line arguments +set(CTEST_SOURCE_DIRECTORY "./") +set(CTEST_BINARY_DIRECTORY "./buildCI") + +set(CTEST_CMAKE_GENERATOR "Unix Makefiles") +#set(CTEST_USE_LAUNCHERS 1) +set(CTEST_PROJECT_NAME "VALHALLA") +set(CTEST_BUILD_CONFIGURATION "Coverage") # Only works for multi-config generators + +if(NOT "$ENV{GCOV}" STREQUAL "") + set(GCOV_NAME "$ENV{GCOV}") +else() + set(GCOV_NAME "gcov") +endif() + +find_program(CTEST_COVERAGE_COMMAND NAMES "${GCOV_NAME}") + +#set(CTEST_MEMORYCHECK_COMMAND "valgrind") +#set(CTEST_MEMORYCHECK_TYPE "ThreadSanitizer") + +ctest_start("Continuous") +ctest_configure(OPTIONS -DCMAKE_BUILD_TYPE=${CTEST_BUILD_CONFIGURATION}) +# Done by default when not using a script... Do it here since the CTestCustom.cmake file is generated by our CMakeLists. +ctest_read_custom_files( ${CTEST_BINARY_DIRECTORY} ) +ctest_build() +ctest_test(RETURN_VALUE RET_VAL_TEST) +if(RET_VAL_TEST) + # We need to send an error if we want to detect fails in CI + message(FATAL_ERROR "Some tests failed !") +endif() +if(CTEST_COVERAGE_COMMAND) + ctest_coverage() +else() + message(WARNING "GCov not found, not running coverage") +endif() +#ctest_memcheck() +ctest_submit() # Comment this if you want to use the script but not use CDash \ No newline at end of file diff --git a/cmake/CTestCustom.cmake.in b/cmake/CTestCustom.cmake.in new file mode 100644 index 000000000..09a784fb7 --- /dev/null +++ b/cmake/CTestCustom.cmake.in @@ -0,0 +1,10 @@ +list(APPEND CTEST_CUSTOM_COVERAGE_EXCLUDE + # Exclude list set by cmake + @CUSTOM_COVERAGE_EXCLUDE@ + + # Exclude try_compile sources from coverage results: + "/CMakeFiles/CMakeTmp/" + + # Exclude Qt source files from coverage results: + "[A-Za-z]./[Qq]t/qt-.+-opensource-src" +) \ No newline at end of file diff --git a/cmake/CopyDllsForDebug.cmake b/cmake/CopyDllsForDebug.cmake new file mode 100644 index 000000000..7ec18e829 --- /dev/null +++ b/cmake/CopyDllsForDebug.cmake @@ -0,0 +1,35 @@ +# This is a helper script to run BundleUtilities fixup_bundle as postbuild +# for a target. The primary use case is to copy .DLLs to the build directory for +# the Windows platform. It allows generator expressions to be used to determine +# the binary location +# +# Usage : copy_dlls_for_debug TARGET LIBS DIRS +# - TARGET : A cmake target +# - See fixup_bundle for LIBS and DIRS arguments + +if(RUN_IT) +# Script ran by the add_custom_command + include(BundleUtilities) + fixup_bundle("${TO_FIXUP_FILE}" "${TO_FIXUP_LIBS}" "${TO_FIXUP_DIRS}") +# End of script ran by the add_custom_command +else() + set(THIS_FILE ${CMAKE_CURRENT_LIST_FILE}) + function(copy_dlls_for_debug _target _libs _dirs) + if(WIN32) + + if(CMAKE_VERSION GREATER_EQUAL 3.21) + add_custom_command(TARGET ${_target} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy -t $ $ + COMMAND_EXPAND_LISTS + ) + else() + add_custom_command( + TARGET ${_target} POST_BUILD + COMMAND ${CMAKE_COMMAND} -DRUN_IT:BOOL=ON -DTO_FIXUP_FILE=$ -DTO_FIXUP_LIBS=${_libs} -DTO_FIXUP_DIRS=${_dirs} -P ${THIS_FILE} + COMMENT "Fixing up dependencies for ${_target}" + VERBATIM + ) + endif() + endif(WIN32) + endfunction() +endif() \ No newline at end of file diff --git a/cmake/Coverage.cmake b/cmake/Coverage.cmake new file mode 100644 index 000000000..ce4614874 --- /dev/null +++ b/cmake/Coverage.cmake @@ -0,0 +1,110 @@ +# +# CMake module that detects if the compilers support coverage +# +# If this is the case, the build type Coverage is set up for coverage, and COVERAGE_SUPPORTED is set to true. +# By default the Coverage build type is added to CMAKE_CONFIGURATION_TYPES on multi-config generators. +# This can be controlled through the COVERAGE_IN_CONFIGURATION_TYPES option. +# + +# License: +# +# Copyright (C) 2017 Lectem +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the 'Software') deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +include(CMakeDependentOption) + +set(COVERAGE_COMPILER_FLAGS "-g -O0 --coverage" CACHE INTERNAL "") +set(COVERAGE_LINKER_FLAGS "--coverage" CACHE INTERNAL "") + +get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) + +foreach(_LANG IN LISTS ENABLED_LANGUAGES) + include(Check${_LANG}CompilerFlag OPTIONAL) + set(CMAKE_REQUIRED_LIBRARIES ${COVERAGE_LINKER_FLAGS}) # This is ugly, but better than rewriting/fixing check__compiler_flag + + if(_LANG STREQUAL "C") + check_c_compiler_flag("--coverage" ${_LANG}_COVERAGE_SUPPORTED) + elseif(_LANG STREQUAL "CXX") + check_cxx_compiler_flag("--coverage" ${_LANG}_COVERAGE_SUPPORTED) + else() + if(DEFINED ${_LANG}_COVERAGE_SUPPORTED) + message(STATUS "Skipping ${_LANG}, not supported by Coverage.cmake script") + endif() + set(${_LANG}_COVERAGE_SUPPORTED FALSE) + continue() + endif() + if(${_LANG}_COVERAGE_SUPPORTED) + set(CMAKE_${_LANG}_FLAGS_COVERAGE + ${COVERAGE_COMPILER_FLAGS} + CACHE STRING "Flags used by the ${_LANG} compiler during coverage builds." + ) + mark_as_advanced(CMAKE_${_LANG}_FLAGS_COVERAGE) + set(COVERAGE_SUPPORTED TRUE CACHE INTERNAL "Whether or not coverage is supported by at least one compiler.") + endif() +endforeach() + +if(COVERAGE_SUPPORTED) + set(CMAKE_EXE_LINKER_FLAGS_COVERAGE + "${COVERAGE_LINKER_FLAGS}" + CACHE STRING "Flags used for linking binaries during coverage builds." + ) + set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE + "${COVERAGE_LINKER_FLAGS}" + CACHE STRING "Flags used by the shared libraries linker during coverage builds." + ) + mark_as_advanced( + CMAKE_EXE_LINKER_FLAGS_COVERAGE + CMAKE_SHARED_LINKER_FLAGS_COVERAGE + ) +endif() + + +cmake_dependent_option(COVERAGE_IN_CONFIGURATION_TYPES + "Should the Coverage target be in the CMAKE_CONFIGURATION_TYPES list if supported ?" ON + "CMAKE_CONFIGURATION_TYPES;COVERAGE_SUPPORTED" OFF # No need for this option if we are not using a multi-config generator +) + +if(COVERAGE_IN_CONFIGURATION_TYPES) + # Modify this only if using a multi-config generator, some modules rely on this variable to detect those generators. + if(CMAKE_CONFIGURATION_TYPES AND COVERAGE_SUPPORTED) + list(APPEND CMAKE_CONFIGURATION_TYPES Coverage) + list(REMOVE_DUPLICATES CMAKE_CONFIGURATION_TYPES) + set(CMAKE_CONFIGURATION_TYPES + "${CMAKE_CONFIGURATION_TYPES}" + CACHE STRING + "Semicolon separated list of supported configuration types, only supports ${CMAKE_CONFIGURATION_TYPES} anything else will be ignored." + FORCE + ) + endif() +else() + if(Coverage IN_LIST CMAKE_CONFIGURATION_TYPES) + message(STATUS "Removing Coverage configuration type (COVERAGE_IN_CONFIGURATION_TYPES is OFF)") + list(REMOVE_ITEM CMAKE_CONFIGURATION_TYPES Coverage) + list(REMOVE_DUPLICATES CMAKE_CONFIGURATION_TYPES) + set(CMAKE_CONFIGURATION_TYPES + "${CMAKE_CONFIGURATION_TYPES}" + CACHE STRING + "Semicolon separated list of supported configuration types, only supports ${CMAKE_CONFIGURATION_TYPES} anything else will be ignored." + FORCE + ) + endif() +endif() \ No newline at end of file diff --git a/cmake/LTO.cmake b/cmake/LTO.cmake new file mode 100644 index 000000000..cdebca307 --- /dev/null +++ b/cmake/LTO.cmake @@ -0,0 +1,253 @@ +# Usage : +# +# Variable : ENABLE_LTO | Enable or disable LTO support for this build +# +# find_lto(lang) +# - lang is C or CXX (the language to test LTO for) +# - call it after project() so that the compiler is already detected +# +# This will check for LTO support and create a target_enable_lto(target [debug,optimized,general]) macro. +# The 2nd parameter has the same meaning as in target_link_libraries, and is used to enable LTO only for those build configurations +# 'debug' is by default the Debug configuration, and 'optimized' all the other configurations +# +# if ENABLE_LTO is set to false, an empty macro will be generated +# +# Then to enable LTO for your target use +# +# target_enable_lto(mytarget general) +# +# It is however recommended to use it only for non debug builds the following way : +# +# target_enable_lto(mytarget optimized) +# +# Note : For CMake versions < 3.9, target_link_library is used in it's non plain version. +# You will need to specify PUBLIC/PRIVATE/INTERFACE to all your other target_link_library calls for the target +# +# WARNING for cmake versions older than 3.9 : +# This module will override CMAKE_AR CMAKE_RANLIB and CMAKE_NM by the gcc versions if found when building with gcc + + +# License: +# +# Copyright (C) 2016 Lectem +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the 'Software') deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +cmake_minimum_required(VERSION 3.10) + +option(ENABLE_LTO "enable link time optimization" ON) + +macro(find_lto lang) + if(ENABLE_LTO AND NOT LTO_${lang}_CHECKED) + + #LTO support was added for clang/gcc in 3.9 + if(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} VERSION_LESS 3.9) + cmake_policy(SET CMP0054 NEW) + message(STATUS "Checking for LTO Compatibility") + # Since GCC 4.9 we need to use gcc-ar / gcc-ranlib / gcc-nm + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_GCC_AR OR NOT CMAKE_GCC_RANLIB OR NOT CMAKE_GCC_NM) + find_program(CMAKE_GCC_AR NAMES + "${_CMAKE_TOOLCHAIN_PREFIX}gcc-ar" + "${_CMAKE_TOOLCHAIN_PREFIX}gcc-ar-${_version}" + DOC "gcc provided wrapper for ar which adds the --plugin option" + ) + find_program(CMAKE_GCC_RANLIB NAMES + "${_CMAKE_TOOLCHAIN_PREFIX}gcc-ranlib" + "${_CMAKE_TOOLCHAIN_PREFIX}gcc-ranlib-${_version}" + DOC "gcc provided wrapper for ranlib which adds the --plugin option" + ) + # Not needed, but at least stay coherent + find_program(CMAKE_GCC_NM NAMES + "${_CMAKE_TOOLCHAIN_PREFIX}gcc-nm" + "${_CMAKE_TOOLCHAIN_PREFIX}gcc-nm-${_version}" + DOC "gcc provided wrapper for nm which adds the --plugin option" + ) + mark_as_advanced(CMAKE_GCC_AR CMAKE_GCC_RANLIB CMAKE_GCC_NM) + set(CMAKE_LTO_AR ${CMAKE_GCC_AR}) + set(CMAKE_LTO_RANLIB ${CMAKE_GCC_RANLIB}) + set(CMAKE_LTO_NM ${CMAKE_GCC_NM}) + endif() + if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") + set(CMAKE_LTO_AR ${CMAKE_AR}) + set(CMAKE_LTO_RANLIB ${CMAKE_RANLIB}) + set(CMAKE_LTO_NM ${CMAKE_NM}) + endif() + + if(CMAKE_LTO_AR AND CMAKE_LTO_RANLIB) + set(__lto_flags -flto) + + if(NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 4.7) + list(APPEND __lto_flags -fno-fat-lto-objects) + endif() + + if(NOT DEFINED CMAKE_${lang}_PASSED_LTO_TEST) + set(__output_dir "${CMAKE_PLATFORM_INFO_DIR}/LtoTest1${lang}") + file(MAKE_DIRECTORY "${__output_dir}") + set(__output_base "${__output_dir}/lto-test-${lang}") + + execute_process( + COMMAND ${CMAKE_COMMAND} -E echo "void foo() {}" + COMMAND ${CMAKE_${lang}_COMPILER} ${__lto_flags} -c -xc - + -o "${__output_base}.o" + RESULT_VARIABLE __result + ERROR_QUIET + OUTPUT_QUIET + ) + + if("${__result}" STREQUAL "0") + execute_process( + COMMAND ${CMAKE_LTO_AR} cr "${__output_base}.a" "${__output_base}.o" + RESULT_VARIABLE __result + ERROR_QUIET + OUTPUT_QUIET + ) + endif() + + if("${__result}" STREQUAL "0") + execute_process( + COMMAND ${CMAKE_LTO_RANLIB} "${__output_base}.a" + RESULT_VARIABLE __result + ERROR_QUIET + OUTPUT_QUIET + ) + endif() + + if("${__result}" STREQUAL "0") + execute_process( + COMMAND ${CMAKE_COMMAND} -E echo "void foo(); int main() {foo();}" + COMMAND ${CMAKE_${lang}_COMPILER} ${__lto_flags} -xc - + -x none "${__output_base}.a" -o "${__output_base}" + RESULT_VARIABLE __result + ERROR_QUIET + OUTPUT_QUIET + ) + endif() + + if("${__result}" STREQUAL "0") + set(__lto_found TRUE) + endif() + + set(CMAKE_${lang}_PASSED_LTO_TEST + ${__lto_found} CACHE INTERNAL + "If the compiler passed a simple LTO test compile") + endif() + if(CMAKE_${lang}_PASSED_LTO_TEST) + message(STATUS "Checking for LTO Compatibility - works") + set(LTO_${lang}_SUPPORT TRUE CACHE BOOL "Do we have LTO support ?") + set(LTO_COMPILE_FLAGS -flto CACHE STRING "Link Time Optimization compile flags") + set(LTO_LINK_FLAGS -flto CACHE STRING "Link Time Optimization link flags") + else() + message(STATUS "Checking for LTO Compatibility - not working") + endif() + + endif() + elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + message(STATUS "Checking for LTO Compatibility - works (assumed for clang)") + set(LTO_${lang}_SUPPORT TRUE CACHE BOOL "Do we have LTO support ?") + set(LTO_COMPILE_FLAGS -flto CACHE STRING "Link Time Optimization compile flags") + set(LTO_LINK_FLAGS -flto CACHE STRING "Link Time Optimization link flags") + elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + message(STATUS "Checking for LTO Compatibility - works") + set(LTO_${lang}_SUPPORT TRUE CACHE BOOL "Do we have LTO support ?") + set(LTO_COMPILE_FLAGS /GL CACHE STRING "Link Time Optimization compile flags") + set(LTO_LINK_FLAGS -LTCG:INCREMENTAL CACHE STRING "Link Time Optimization link flags") + else() + message(STATUS "Checking for LTO Compatibility - compiler not handled by module") + endif() + mark_as_advanced(LTO_${lang}_SUPPORT LTO_COMPILE_FLAGS LTO_LINK_FLAGS) + + + set(LTO_${lang}_CHECKED TRUE CACHE INTERNAL "" ) + + if(CMAKE_GCC_AR AND CMAKE_GCC_RANLIB AND CMAKE_GCC_NM) + # THIS IS HACKY BUT THERE IS NO OTHER SOLUTION ATM + set(CMAKE_AR ${CMAKE_GCC_AR} CACHE FILEPATH "Forcing gcc-ar instead of ar" FORCE) + set(CMAKE_NM ${CMAKE_GCC_NM} CACHE FILEPATH "Forcing gcc-nm instead of nm" FORCE) + set(CMAKE_RANLIB ${CMAKE_GCC_RANLIB} CACHE FILEPATH "Forcing gcc-ranlib instead of ranlib" FORCE) + endif() + endif(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} VERSION_LESS 3.9) + endif(ENABLE_LTO AND NOT LTO_${lang}_CHECKED) + + + if(ENABLE_LTO) + #Special case for cmake older than 3.9, using a library for gcc/clang, but could setup the flags directly. + #Taking advantage of the [debug,optimized] parameter of target_link_libraries + if(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} VERSION_LESS 3.9) + if(LTO_${lang}_SUPPORT) + if(NOT TARGET __enable_lto_tgt) + add_library(__enable_lto_tgt INTERFACE) + endif() + target_compile_options(__enable_lto_tgt INTERFACE ${LTO_COMPILE_FLAGS}) + #this might not work for all platforms... in which case we'll have to set the link flags on the target directly + target_link_libraries(__enable_lto_tgt INTERFACE ${LTO_LINK_FLAGS} ) + macro(target_enable_lto _target _build_configuration) + if(${_build_configuration} STREQUAL "optimized" OR ${_build_configuration} STREQUAL "debug" ) + target_link_libraries(${_target} PRIVATE ${_build_configuration} __enable_lto_tgt) + else() + target_link_libraries(${_target} PRIVATE __enable_lto_tgt) + endif() + endmacro() + else() + #In old cmake versions, we can set INTERPROCEDURAL_OPTIMIZATION even if not supported by the compiler + #So if we didn't detect it, let cmake give it a try + set(__IPO_SUPPORTED TRUE) + endif() + else() + cmake_policy(SET CMP0069 NEW) + include(CheckIPOSupported) + # Optional IPO. Do not use IPO if it's not supported by compiler. + check_ipo_supported(RESULT __IPO_SUPPORTED OUTPUT output) + if(NOT __IPO_SUPPORTED) + message(STATUS "IPO is not supported or broken.") + else() + message(STATUS "IPO is supported !") + endif() + endif() + if(__IPO_SUPPORTED) + macro(target_enable_lto _target _build_configuration) + if(NOT ${_build_configuration} STREQUAL "debug" ) + #enable for all configurations + set_target_properties(${_target} PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE) + endif() + if(${_build_configuration} STREQUAL "optimized" ) + #blacklist debug configurations + set(__enable_debug_lto FALSE) + else() + #enable only for debug configurations + set(__enable_debug_lto TRUE) + endif() + get_property(DEBUG_CONFIGURATIONS GLOBAL PROPERTY DEBUG_CONFIGURATIONS) + if(NOT DEBUG_CONFIGURATIONS) + set(DEBUG_CONFIGURATIONS DEBUG) # This is what is done by CMAKE internally... since DEBUG_CONFIGURATIONS is empty by default + endif() + foreach(config IN LISTS DEBUG_CONFIGURATIONS) + set_target_properties(${_target} PROPERTIES INTERPROCEDURAL_OPTIMIZATION_${config} ${__enable_debug_lto}) + endforeach() + endmacro() + endif() + endif() + if(NOT COMMAND target_enable_lto) + macro(target_enable_lto _target _build_configuration) + endmacro() + endif() +endmacro() diff --git a/cmake/VALHALLAConfig.cmake.in b/cmake/VALHALLAConfig.cmake.in new file mode 100644 index 000000000..2c71eb725 --- /dev/null +++ b/cmake/VALHALLAConfig.cmake.in @@ -0,0 +1,17 @@ +@PACKAGE_INIT@ + +# Required so that on windows Release and RelWithDebInfo can be used instead of default fallback which is Debug +# See https://gitlab.kitware.com/cmake/cmake/issues/20319 + +set(CMAKE_MAP_IMPORTED_CONFIG_MINSIZEREL MinSizeRel RelWithDebInfo Release Debug "") +set(CMAKE_MAP_IMPORTED_CONFIG_RELWITHDEBINFO RelWithDebInfo Release MinSizeRel Debug "") +set(CMAKE_MAP_IMPORTED_CONFIG_RELEASE Release RelWithDebInfo MinSizeRel Debug "") + +# Since we install some cmake modules, add them to the modules path +list(APPEND CMAKE_MODULE_PATH "@PACKAGE_VALHALLA_MODULE_INSTALL_DIR@") + +# If your package depends an another one, you MUST specify it here +include(CMakeFindDependencyMacro) +#find_dependency(NAME_OF_THE_REQUIRED_PACKAGE REQUIRED) + +include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") diff --git a/cmake/Warnings.cmake b/cmake/Warnings.cmake new file mode 100644 index 000000000..d4d46272c --- /dev/null +++ b/cmake/Warnings.cmake @@ -0,0 +1,156 @@ +# Helper script to set warnings +# Usage : +# target_set_warnings(target +# [ENABLE [ALL] [list of warning names]] +# [DISABLE [ALL/Annoying] [list of warning names]] +# [AS_ERROR ALL] +# ) +# +# ENABLE +# * ALL: means all the warnings possible to enable through a one parameter switch. +# Note that for some compilers, this does not mean every single warning will be enabled (GCC for instance). +# * Any other name: enable the warning with the given name +# +# DISABLE +# * ALL: will override any other settings and this target INTERFACE includes will be considered as system includes by targets linking it. +# * Annoying: Warnings that the author thinks should only be used as static analysis tools not in production. On MSVC, also sets _CRT_SECURE_NO_WARNINGS. +# * Any other name: disable the warning with the given name +# +# AS_ERROR +# * ALL: is the only option available as not all compilers let us set specific warnings as error from command line (MSVC). +# +# +# License: +# +# Copyright (C) 2019 Lectem +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the 'Software') deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +cmake_minimum_required(VERSION 3.10) + +option(ENABLE_WARNINGS_SETTINGS "Allow target_set_warnings to add flags and defines. Set this to OFF if you want to provide your own warning parameters." ON) + +# fix: error: include location '/usr/local/include' is unsafe for cross-compilation [-Werror,-Wpoison-system-directories] +if(APPLE) + add_compile_options(-Wno-poison-system-directories) +endif() + +function(target_set_warnings) + if(NOT ENABLE_WARNINGS_SETTINGS) + return() + endif() + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + set(WMSVC TRUE) + set(WARNING_ENABLE_PREFIX "/w1") # Means the warning will be available at all levels that do emit warnings + set(WARNING_DISABLE_PREFIX "/wd") + elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + set(WGCC TRUE) + set(WARNING_ENABLE_PREFIX "-W") + set(WARNING_DISABLE_PREFIX "-Wno-") + elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") + set(WCLANG TRUE) + set(WARNING_ENABLE_PREFIX "-W") + set(WARNING_DISABLE_PREFIX "-Wno-") + endif() + set(multiValueArgs ENABLE DISABLE AS_ERROR) + cmake_parse_arguments(this "" "" "${multiValueArgs}" ${ARGN}) + list(FIND this_ENABLE "ALL" enable_all) + list(FIND this_DISABLE "ALL" disable_all) + list(FIND this_AS_ERROR "ALL" as_error_all) + if(NOT ${enable_all} EQUAL -1) + if(WMSVC) + # Not all the warnings, but WAll is unusable when using libraries + # Unless you'd like to support MSVC in the code with pragmas, this is probably the best option + list(APPEND WarningFlags "/W4") + elseif(WGCC) + list(APPEND WarningFlags "-Wall" "-Wextra" "-Wpedantic") + elseif(WCLANG) + list(APPEND WarningFlags "-Wall" "-Weverything" "-Wpedantic") + endif() + elseif(NOT ${disable_all} EQUAL -1) + set(SystemIncludes TRUE) # Treat includes as if coming from system + if(WMSVC) + list(APPEND WarningFlags "/w" "/W0") + elseif(WGCC OR WCLANG) + list(APPEND WarningFlags "-w") + endif() + endif() + + list(FIND this_DISABLE "Annoying" disable_annoying) + if(NOT ${disable_annoying} EQUAL -1) + if(WMSVC) + # bounds-checked functions require to set __STDC_WANT_LIB_EXT1__ which we usually don't need/want + list(APPEND WarningDefinitions -D_CRT_SECURE_NO_WARNINGS) + # disable C4514 C4710 C4711... Those are useless to add most of the time + #list(APPEND WarningFlags "/wd4514" "/wd4710" "/wd4711") + #list(APPEND WarningFlags "/wd4365") #signed/unsigned mismatch + #list(APPEND WarningFlags "/wd4668") # is not defined as a preprocessor macro, replacing with '0' for + elseif(WGCC OR WCLANG) + list(APPEND WarningFlags -Wno-switch-enum) + if(WCLANG) + list(APPEND WarningFlags -Wno-unknown-warning-option -Wno-padded -Wno-undef -Wno-reserved-id-macro -Wno-inconsistent-missing-destructor-override -fcomment-block-commands=test,retval) + if(NOT CMAKE_CXX_STANDARD EQUAL 98) + list(APPEND WarningFlags -Wno-c++98-compat -Wno-c++98-compat-pedantic) + endif() + if ("${CMAKE_CXX_SIMULATE_ID}" STREQUAL "MSVC") # clang-cl has some VCC flags by default that it will not recognize... + list(APPEND WarningFlags -Wno-unused-command-line-argument) + endif() + endif(WCLANG) + endif() + endif() + + if(NOT ${as_error_all} EQUAL -1) + if(WMSVC) + list(APPEND WarningFlags "/WX") + elseif(WGCC OR WCLANG) + list(APPEND WarningFlags "-Werror") + endif() + endif() + + if(this_ENABLE) + list(REMOVE_ITEM this_ENABLE ALL) + foreach(warning-name IN LISTS this_ENABLE) + list(APPEND WarningFlags "${WARNING_ENABLE_PREFIX}${warning-name}") + endforeach() + endif() + + + if(this_DISABLE) + list(REMOVE_ITEM this_DISABLE ALL Annoying) + foreach(warning-name IN LISTS this_DISABLE) + list(APPEND WarningFlags "${WARNING_DISABLE_PREFIX}${warning-name}") + endforeach() + endif() + + foreach(target IN LISTS this_UNPARSED_ARGUMENTS) + if(WarningFlags) + target_compile_options(${target} PRIVATE ${WarningFlags}) + endif() + if(WarningDefinitions) + target_compile_definitions(${target} PRIVATE ${WarningDefinitions}) + endif() + if(SystemIncludes) + set_target_properties(${target} PROPERTIES + INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $) + endif() + endforeach() +endfunction(target_set_warnings) diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt new file mode 100644 index 000000000..8e6973748 --- /dev/null +++ b/external/CMakeLists.txt @@ -0,0 +1,85 @@ +project(external C CXX) + +set(CMAKE_FOLDER external) # This will regroup all the external targets in a subfolder in IDEs such as Visual Studio + +set(BUILD_TESTING_BCKP ${BUILD_TESTING}) +set(BUILD_TESTING OFF CACHE BOOL "Force disable of tests for external dependencies" FORCE) + +set(CUSTOM_COVERAGE_EXCLUDE ${CUSTOM_COVERAGE_EXCLUDE} "external" PARENT_SCOPE) # Replaced in CTestCustom.cmake.in + +# Disable testing or fuzzing if we can +set(BUILD_TESTING OFF CACHE BOOL "" FORCE) +set(BUILD_FUZZING OFF CACHE BOOL "" FORCE) +# Build everything statically so we can bundle everything in one executable +set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) +set(SDL_SHARED_ENABLED_BY_DEFAULT OFF CACHE BOOL "" FORCE) +set(SDL_STATIC_ENABLED_BY_DEFAULT ON CACHE BOOL "" FORCE) + +# Use SLD2 for platform abstraction +add_subdirectory(SDL2 EXCLUDE_FROM_ALL) +# Treat SDL2 as a system include as to ignore the warnings +target_set_warnings(SDL2-static DISABLE ALL) +#target_set_warnings(SDL2main DISABLE ALL) + +# Force everything to be built statically +set(SDL2IMAGE_BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) +set(SDL2IMAGE_ZLIB_SHARED OFF CACHE BOOL "" FORCE) +# Don't bother with demos and samples +set(SDL2IMAGE_SAMPLES_DEFAULT OFF CACHE BOOL "" FORCE) +# Use built-in libraries to avoid extra work +set(SDL2IMAGE_VENDORED ON CACHE BOOL "" FORCE) +set(SDL2IMAGE_ZLIB ON CACHE BOOL "" FORCE) +set(SDL2IMAGE_PNG_VENDORED ON CACHE BOOL "" FORCE) +set(SDL2IMAGE_ZLIB_VENDORED ON CACHE BOOL "" FORCE) +# Use libpng for handling png files instead of alternatives +#set(SDL2IMAGE_BACKEND_STB OFF CACHE BOOL "" FORCE) +# Disable loading AVIF images as it requires setting up NASM +set(SDL2IMAGE_AVIF OFF CACHE BOOL "" FORCE) # large and unnecessary library +set(SDL2IMAGE_WEBP OFF CACHE BOOL "" FORCE) # large and unnecessary library +# Use SDL_image for image abstraction +add_subdirectory(SDL_image EXCLUDE_FROM_ALL) +# Treat SDL2_image as a system include as to ignore the warnings +target_set_warnings(SDL2_image DISABLE ALL) + +# We use zlib ourselves and if SDL_image didn't include it, we can do it ourselves, manually +if (NOT ZLIB_LIBRARY OR ZLIB_LIBRARY STREQUAL "") + # disable build of zlib example programs + set(ZLIB_BUILD_EXAMPLES OFF CACHE BOOL "zlib examples" FORCE) + # The engine uses ZLIB for itself and SDL_image includes the sources in its vendor folder + add_subdirectory(SDL_image/external/zlib EXCLUDE_FROM_ALL) + # Make the correct ZLIb available (static, always) + if(SDL2IMAGE_ZLIB_SHARED) + set(ZLIB_LIBRARY zlib) + else() + set(ZLIB_LIBRARY zlibstatic) + endif() + if(NOT TARGET ZLIB::ZLIB) + add_library(ZLIB::ZLIB ALIAS ${ZLIB_LIBRARY}) + endif() +endif() + +# Use built-in libraries to avoid extra work +set(SDL2MIXER_VENDORED ON CACHE BOOL "" FORCE) +# Use SDL_mixer for sound abstraction +add_subdirectory(SDL_mixer EXCLUDE_FROM_ALL) +# Treat SDL2_mixer as a system include as to ignore the warnings +target_set_warnings(SDL2_mixer DISABLE ALL) + +# Don't build the binary program +set(MAXMINDDB_BUILD_BINARIES OFF CACHE BOOL "" FORCE) +# Use libmaxminddb for geolocation +add_subdirectory(libmaxminddb EXCLUDE_FROM_ALL) +# Treat libmaxminddb as a system include as to ignore the warnings +target_set_warnings(maxminddb DISABLE ALL) + +# Doctest for unit tests +add_library(doctest INTERFACE) +target_include_directories( + doctest + INTERFACE + doctest/doctest # note : will expose the parts/ folder... +) +add_library(doctest::doctest ALIAS doctest) +target_compile_features(doctest INTERFACE cxx_std_11) + +set(BUILD_TESTING ${BUILD_TESTING_BCKP} CACHE BOOL "Build tests (default variable for CTest)" FORCE) #Set it back to its past value diff --git a/external/SDL2 b/external/SDL2 new file mode 160000 index 000000000..f432937f9 --- /dev/null +++ b/external/SDL2 @@ -0,0 +1 @@ +Subproject commit f432937f9ca8b5a66dda8ad011ffdd605dbe9d02 diff --git a/external/SDL_image b/external/SDL_image new file mode 160000 index 000000000..249cab5e1 --- /dev/null +++ b/external/SDL_image @@ -0,0 +1 @@ +Subproject commit 249cab5e1bc0fc328e57d9065be8c3666fa65a72 diff --git a/external/SDL_mixer b/external/SDL_mixer new file mode 160000 index 000000000..3be014189 --- /dev/null +++ b/external/SDL_mixer @@ -0,0 +1 @@ +Subproject commit 3be014189f705756b2d01308f46ab8f5cdc95c50 diff --git a/external/doctest b/external/doctest new file mode 160000 index 000000000..1da23a3e8 --- /dev/null +++ b/external/doctest @@ -0,0 +1 @@ +Subproject commit 1da23a3e8119ec5cce4f9388e91b065e20bf06f5 diff --git a/external/libmaxminddb b/external/libmaxminddb new file mode 160000 index 000000000..bec0392ec --- /dev/null +++ b/external/libmaxminddb @@ -0,0 +1 @@ +Subproject commit bec0392ec5663fa646b31cc62efc7b53242c5e9b diff --git a/source/shared/cube.h b/source/shared/cube.h index 57d368f22..64827e262 100644 --- a/source/shared/cube.h +++ b/source/shared/cube.h @@ -33,7 +33,10 @@ #include #include #endif - #define ZLIB_DLL + // So we don't get undefined references when we want to link statically + #ifndef ZLIB_STATIC + #define ZLIB_DLL + #endif #endif #ifndef STANDALONE diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 000000000..3876eceb0 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,28 @@ +cmake_minimum_required(VERSION 3.10) +# Note : must be included by master CMakeLists.txt +# Tests in static libraries might not get registered, see https://github.com/onqtam/doctest/blob/master/doc/markdown/faq.md#why-are-my-tests-in-a-static-library-not-getting-registered +# For this reason, and because it is interesting to have individual +# test executables for each library, it is suggested not to put tests directly in the libraries (even though doctest advocates this usage) +# Creating multiple executables is of course not mandatory, and one could use the same executable with various command lines to filter what tests to run. + +add_executable(failtest failtest.cpp) +target_link_libraries(failtest doctest::doctest) + +add_test( + # Use some per-module/project prefix so that it is easier to run only tests for this module + NAME VALHALLA.failtest + COMMAND failtest ${TEST_RUNNER_PARAMS} +) +set_tests_properties( + VALHALLA.failtest + PROPERTIES + WILL_FAIL TRUE # We expect this test to fail +) + +add_executable(successtest successtest.cpp) +target_link_libraries(successtest doctest::doctest) + +add_test( + NAME VALHALLA.successtest + COMMAND successtest ${TEST_RUNNER_PARAMS} +) diff --git a/tests/failtest.cpp b/tests/failtest.cpp new file mode 100644 index 000000000..04e15db26 --- /dev/null +++ b/tests/failtest.cpp @@ -0,0 +1,21 @@ +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "doctest.h" + +static int factorial(int number) { return number <= 1 ? number : factorial(number - 1) * number; } + +TEST_CASE("testing the factorial function") { + CHECK(factorial(0) == 1); + CHECK(factorial(1) == 1); + CHECK(factorial(2) == 2); + CHECK(factorial(3) == 6); + CHECK(factorial(10) == 3628800); +} +#if defined(__GNUC__) && !defined(_WIN32) // Doesn't crash for gcc/clang, but will with msvc +TEST_CASE("Trigger ASan") +{ + int *array = new int[100]; + delete [] array; + array[0] = 0; //boom + REQUIRE(false); +} +#endif \ No newline at end of file diff --git a/tests/successtest.cpp b/tests/successtest.cpp new file mode 100644 index 000000000..761fc8bd3 --- /dev/null +++ b/tests/successtest.cpp @@ -0,0 +1,31 @@ +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "doctest.h" +#include + +int foo(bool branch = false) +{ + if(branch) + { + puts("This line will be untested, so that coverage is not 100%\n"); + } + else + { + puts("This is the default behaviour and will be tested\n"); + } + return 0; +} + + +static int the_answer_to_life(){return (1<<1) + (1<<3) + (1<<5);} + +TEST_CASE("Main test") { + CHECK(the_answer_to_life() == 42); +} + +int untested_function(){ return 666; } // This should show as not tested in coverage + +TEST_CASE("Foo test") { + CHECK(foo() == 0); + // We are not testing this correctly on purpose to test coverage + // Should check foo(true) too for full coverage +} From 622f061df1c9b08b05b4a3de984b8b7546d6b20a Mon Sep 17 00:00:00 2001 From: Sandu Liviu Catalin Date: Fri, 2 Jan 2026 18:22:52 +0200 Subject: [PATCH 2/3] Implement artifact uploading. --- .github/workflows/linux.yml | 6 ++++++ .github/workflows/mingw.yml | 8 ++++++++ .github/workflows/windows.yml | 8 ++++++++ 3 files changed, 22 insertions(+) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index f7c75588b..fcb28e4b2 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -40,6 +40,12 @@ jobs: # Build your program with the given configuration run: cmake --build ${{runner.workspace}}/build --config ${{env.BUILD_TYPE}} + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: ${{env.BUILD_TYPE}}-linux-x64--artifact${{github.sha}} + path: bin/bin_unix + - name: Test working-directory: ${{runner.workspace}}/build # Execute tests defined by the CMake configuration. diff --git a/.github/workflows/mingw.yml b/.github/workflows/mingw.yml index 238f0ed94..d85e95fc9 100644 --- a/.github/workflows/mingw.yml +++ b/.github/workflows/mingw.yml @@ -42,6 +42,14 @@ jobs: # Build your program with the given configuration run: cmake --build ${{runner.workspace}}/build --config ${{env.BUILD_TYPE}} + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: ${{env.BUILD_TYPE}}-mingw-x64-artifact${{github.sha}} + path: | + bin/bin64 + !bin/bin64/*.dll + - name: Test working-directory: ${{runner.workspace}}/build # Execute tests defined by the CMake configuration. diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 1a7953376..9532d8eb8 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -37,6 +37,14 @@ jobs: # Build your program with the given configuration run: cmake --build ${{runner.workspace}}/build --config ${{env.BUILD_TYPE}} + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: ${{env.BUILD_TYPE}}-msvc-x64-artifact${{github.sha}} + path: | + bin/bin64 + !bin/bin64/*.dll + - name: Test working-directory: ${{runner.workspace}}/build # Execute tests defined by the CMake configuration. From 521ede407095bf4ba909f4916d89da818b5bab70 Mon Sep 17 00:00:00 2001 From: Sandu Liviu Catalin Date: Sat, 10 Jan 2026 09:04:04 +0200 Subject: [PATCH 3/3] Update CMakeLists.txt Fix some compiler flags not being applied on Linux. --- CMakeLists.txt | 63 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f698de37..cca9ee029 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -330,10 +330,17 @@ target_link_libraries(Client # Specify that we're linking to a static version of zlib target_compile_definitions(Client PRIVATE ZLIB_STATIC=1) +# GNU compatible options +if (MSYS OR MINGW OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + target_compile_options(Client PRIVATE -Wimplicit-fallthrough -fsigned-char -fno-exceptions -fno-rtti) + if(CMAKE_BUILD_TYPE STREQUAL "Release") + target_compile_options(Client PRIVATE -fomit-frame-pointer -ffast-math) + endif() +endif() + # Platform speciffic options if(MSVC OR MSYS OR MINGW) if(MSYS OR MINGW) - target_compile_options(Client PRIVATE -fomit-frame-pointer -ffast-math -Wimplicit-fallthrough -fsigned-char -fno-exceptions -fno-rtti) target_link_options(Client PRIVATE -mwindows -static-libgcc -static-libstdc++) # Configure executable resources post-build (workaround for .rc causing build errors if compiler path includes spaces) add_custom_command( @@ -350,13 +357,27 @@ if(MSVC OR MSYS OR MINGW) target_sources(Client PRIVATE source/vcpp/valhalla.rc) endif() target_link_libraries(Client PRIVATE winmm) -elseif(UNIX AND NOT APPLE) +elseif(APPLE) + #MacOS... +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + if (WIN32) + #Windows clang... + elseif(UNIX) + #Linux clang... + endif() +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + #Linux... +endif() + +# X11 deppendencies +if(UNIX AND NOT APPLE) # Find and link X11 find_package(X11) if(X11_FOUND) target_link_libraries(Client PRIVATE X11::X11) endif() endif() + # Put the executable in the bin folder add_custom_command( TARGET Client POST_BUILD @@ -442,10 +463,17 @@ if(NOT MSVC) target_compile_definitions(Server PRIVATE HAVE_MAXMINDDB=1) endif() +# GNU compatible options +if (MSYS OR MINGW OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + target_compile_options(Server PRIVATE -Wimplicit-fallthrough -fsigned-char -fno-exceptions -fno-rtti) + if(CMAKE_BUILD_TYPE STREQUAL "Release") + target_compile_options(Server PRIVATE -fomit-frame-pointer -ffast-math) + endif() +endif() + # Platform speciffic options if(MSVC OR MSYS OR MINGW) if(MSYS OR MINGW) - target_compile_options(Server PRIVATE -fomit-frame-pointer -ffast-math -Wimplicit-fallthrough -fsigned-char -fno-exceptions -fno-rtti) target_link_options(Server PRIVATE -mwindows -static-libgcc -static-libstdc++) # Configure executable resources post-build (workaround for .rc causing build errors if compiler path includes spaces) add_custom_command( @@ -460,6 +488,16 @@ if(MSVC OR MSYS OR MINGW) target_sources(Server PRIVATE source/vcpp/valhalla.rc) endif() target_link_libraries(Server PRIVATE opengl32 winmm) +elseif(APPLE) + #MacOS... +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + if (WIN32) + #Windows clang... + elseif(UNIX) + #Linux clang... + endif() +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + #Linux... endif() # Put the executable in the bin folder @@ -530,10 +568,17 @@ if(NOT MSVC) target_compile_definitions(Master PRIVATE HAVE_MAXMINDDB=1) endif() +# GNU compatible options +if (MSYS OR MINGW OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + target_compile_options(Master PRIVATE -Wimplicit-fallthrough -fsigned-char -fno-exceptions -fno-rtti) + if(CMAKE_BUILD_TYPE STREQUAL "Release") + target_compile_options(Master PRIVATE -fomit-frame-pointer -ffast-math) + endif() +endif() + # Platform speciffic options if(MSVC OR MSYS OR MINGW) if(MSYS OR MINGW) - target_compile_options(Master PRIVATE -fomit-frame-pointer -ffast-math -Wimplicit-fallthrough -fsigned-char -fno-exceptions -fno-rtti) target_link_options(Master PRIVATE -mwindows -static-libgcc -static-libstdc++) # Configure executable resources post-build (workaround for .rc causing build errors if compiler path includes spaces) add_custom_command( @@ -548,6 +593,16 @@ if(MSVC OR MSYS OR MINGW) target_sources(Master PRIVATE source/vcpp/valhalla.rc) endif() target_link_libraries(Master PRIVATE opengl32 winmm) +elseif(APPLE) + #MacOS... +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + if (WIN32) + #Windows clang... + elseif(UNIX) + #Linux clang... + endif() +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + #Linux... endif() # Put the executable in the bin folder