From 39afeaf8b1a474cd662d5975994cb5cb939597f8 Mon Sep 17 00:00:00 2001 From: Gleb Mazovetskiy Date: Tue, 21 Jun 2022 09:38:53 +0100 Subject: [PATCH] CMake: gc-sections + no-rtti/exceptions options Turns out gc-sections helps significantly even with LTO (-84 KiB for the MinSizeRel rg99 build). Also adds options for disabling RTTI and exceptions. --- CMakeLists.txt | 33 +++++++++++++++++++++++++++ test/animationinfo_test.cpp | 45 ++++++++++++++++++++++++++++--------- 2 files changed, 67 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2459f2a9f..c59c9042c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,6 +64,9 @@ option(DEVILUTIONX_RESAMPLER_SDL "Build with SDL resampler" ON) option(DEVILUTIONX_PALETTE_TRANSPARENCY_BLACK_16_LUT "Whether to use a lookup table for transparency blending with black. This improves performance of blending transparent black overlays, such as quest dialog background, at the cost of 128 KiB of RAM." ON) +cmake_dependent_option(DEVILUTIONX_DISABLE_RTTI "Disable RTTI" ON "NONET" OFF) +cmake_dependent_option(DEVILUTIONX_DISABLE_EXCEPTIONS "Disable exceptions" ON "NONET" OFF) + if(TSAN) set(ASAN OFF) endif() @@ -156,6 +159,8 @@ endif() if(NONET) set(DISABLE_TCP ON) set(DISABLE_ZERO_TIER ON) + set(DISABLE_RTTI ON) + set(DISABLE_EXCEPTIONS ON) set(PACKET_ENCRYPTION OFF) endif() @@ -177,6 +182,34 @@ if(CCACHE_PROGRAM) set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}") endif() +if(DEVILUTIONX_DISABLE_RTTI) + if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") + elseif(MSVC) + string(REGEX REPLACE "/GR" "/GR-" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + endif() +endif() + +if(DEVILUTIONX_DISABLE_EXCEPTIONS) + if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions") + elseif(MSVC) + string(REGEX REPLACE "/EHsc" "/EHs-c-" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + endif() +endif() + +# Remove unused symbols in non-debug mode. +# This is useful even with LTO (-84 KiB with MinSizeRel). +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + # For some reason, adding to CMAKE_CXX_FLAGS results in a slightly smaller + # binary than using `add_compile/link_options` + set(_extra_flags "-ffunction-sections -fdata-sections -Wl,--gc-sections") + + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${_extra_flags}") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${_extra_flags}") + set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} ${_extra_flags}") +endif() + # Not a genexp because CMake doesn't support it # https://gitlab.kitware.com/cmake/cmake/-/issues/20546 if(NOT DISABLE_LTO) diff --git a/test/animationinfo_test.cpp b/test/animationinfo_test.cpp index 8ede00e61..b3c843244 100644 --- a/test/animationinfo_test.cpp +++ b/test/animationinfo_test.cpp @@ -5,17 +5,24 @@ using namespace devilution; +enum class TestDataType { + SetNewAnimation, + GameTick, + Rendering +}; + /** * @brief Represents a Action in the game_logic or rendering. */ struct TestData { virtual ~TestData() = default; + virtual TestDataType type() const = 0; }; /** * @brief Represents a call to SetNewAnimation */ -struct SetNewAnimationData : TestData { +struct SetNewAnimationData : public TestData { SetNewAnimationData(int numberOfFrames, int delayLen, AnimationDistributionFlags params = AnimationDistributionFlags::None, int numSkippedFrames = 0, int distributeFramesBeforeFrame = 0) { _NumberOfFrames = numberOfFrames; @@ -24,6 +31,12 @@ struct SetNewAnimationData : TestData { _NumSkippedFrames = numSkippedFrames; _DistributeFramesBeforeFrame = distributeFramesBeforeFrame; } + + TestDataType type() const override + { + return TestDataType::SetNewAnimation; + } + int _NumberOfFrames; int _DelayLen; AnimationDistributionFlags _Params; @@ -42,6 +55,11 @@ struct GameTickData : TestData { _ExpectedAnimationFrame = expectedAnimationFrame; _ExpectedAnimationCnt = expectedAnimationCnt; } + + TestDataType type() const override + { + return TestDataType::GameTick; + } }; /** @@ -59,6 +77,11 @@ struct RenderingData : TestData { this->_fProgressToNextGameTick = fProgressToNextGameTick; this->_ExpectedRenderingFrame = expectedRenderingFrame; } + + TestDataType type() const override + { + return TestDataType::Rendering; + } }; /** @@ -73,21 +96,20 @@ void RunAnimationTest(const std::vector &vecTestData) int currentGameTick = 0; for (TestData *x : vecTestData) { - auto setNewAnimationData = dynamic_cast(x); - if (setNewAnimationData != nullptr) { + switch (x->type()) { + case TestDataType::SetNewAnimation: { + auto setNewAnimationData = static_cast(x); animInfo.SetNewAnimation(std::nullopt, setNewAnimationData->_NumberOfFrames, setNewAnimationData->_DelayLen, setNewAnimationData->_Params, setNewAnimationData->_NumSkippedFrames, setNewAnimationData->_DistributeFramesBeforeFrame); - } - - auto gameTickData = dynamic_cast(x); - if (gameTickData != nullptr) { + } break; + case TestDataType::GameTick: { + auto gameTickData = static_cast(x); currentGameTick += 1; animInfo.ProcessAnimation(); EXPECT_EQ(animInfo.CurrentFrame, gameTickData->_ExpectedAnimationFrame); EXPECT_EQ(animInfo.TickCounterOfCurrentFrame, gameTickData->_ExpectedAnimationCnt); - } - - auto renderingData = dynamic_cast(x); - if (renderingData != nullptr) { + } break; + case TestDataType::Rendering: { + auto renderingData = static_cast(x); gfProgressToNextGameTick = renderingData->_fProgressToNextGameTick; EXPECT_EQ(animInfo.GetFrameToUseForRendering(), renderingData->_ExpectedRenderingFrame) << std::fixed << std::setprecision(2) @@ -95,6 +117,7 @@ void RunAnimationTest(const std::vector &vecTestData) << " CurrentFrame: " << animInfo.CurrentFrame << " DelayCounter: " << animInfo.TickCounterOfCurrentFrame << " GameTick: " << currentGameTick; + } break; } } for (TestData *x : vecTestData) {