From 2e6be8d504a69d69f6ff8e88e4c18d66b6970fc0 Mon Sep 17 00:00:00 2001 From: nomdenom Date: Mon, 24 Sep 2018 22:01:58 -0700 Subject: [PATCH] code coverage & asm cmake tweaks --- Absolute/absolute-decls.h | 36 ++--- CMake/32bit.cmake | 3 + CMake/CodeCoverage.cmake | 302 +++++++++++++++++++++++++++++++++++++ CMake/absolute.cmake | 22 +-- CMakeLists.txt | 17 ++- Stub/main_test_harness.cpp | 86 +++++++++++ 6 files changed, 430 insertions(+), 36 deletions(-) create mode 100644 CMake/CodeCoverage.cmake create mode 100644 Stub/main_test_harness.cpp diff --git a/Absolute/absolute-decls.h b/Absolute/absolute-decls.h index 3e81ef1fd..c38ffa01c 100644 --- a/Absolute/absolute-decls.h +++ b/Absolute/absolute-decls.h @@ -759,7 +759,7 @@ void __fastcall d_gmenu_left_right(int a1); int __fastcall d_gmenu_on_mouse_move(LPARAM lParam); bool __fastcall d_gmenu_valid_mouse_pos(int * plOffset); int __fastcall d_gmenu_left_mouse(int a1); -void __fastcall d_gmenu_enable(TMenuItem * pMenuItem,bool enable); +void __fastcall d_gmenu_enable(TMenuItem * pMenuItem,BOOL enable); void __fastcall d_gmenu_slider_1(TMenuItem * pItem,int min,int max,int gamma); int __fastcall d_gmenu_slider_get(TMenuItem * pItem,int min,int max); void __fastcall d_gmenu_slider_3(TMenuItem * pItem,int dwTicks); @@ -1306,7 +1306,7 @@ bool __fastcall d_SpawnSkeleton(int ii,int x,int y); int __cdecl d_PreSpawnSkeleton(); void __fastcall d_TalktoMonster(int i); void __fastcall d_SpawnGolum(int i,int x,int y,int mi); -bool __fastcall d_CanTalkToMonst(int m); +BOOL __fastcall d_CanTalkToMonst(int m); BOOL __fastcall d_CheckMonsterHit(int m,BOOL * ret); int __fastcall d_encode_enemy(int m); void __fastcall d_decode_enemy(int m,int enemy); @@ -1370,24 +1370,24 @@ bool __fastcall d_delta_quest_inited(int i); void __fastcall d_DeltaAddItem(int ii); void __cdecl d_DeltaSaveLevel(); void __cdecl d_DeltaLoadLevel(); -void __fastcall d_NetSendCmd(unsigned char bHiPri,unsigned char bCmd); +void __fastcall d_NetSendCmd(BOOL bHiPri,unsigned char bCmd); void __fastcall d_NetSendCmdGolem(unsigned char mx,unsigned char my,unsigned char dir,unsigned char menemy,int hp,int cl); -void __fastcall d_NetSendCmdLoc(unsigned char bHiPri,unsigned char bCmd,unsigned char x,unsigned char y); -void __fastcall d_NetSendCmdLocParam1(unsigned char bHiPri,unsigned char bCmd,unsigned char x,unsigned char y,int wParam1); -void __fastcall d_NetSendCmdLocParam2(unsigned char bHiPri,unsigned char bCmd,unsigned char x,unsigned char y,int wParam1,int wParam2); -void __fastcall d_NetSendCmdLocParam3(unsigned char bHiPri,unsigned char bCmd,unsigned char x,unsigned char y,int wParam1,int wParam2,int wParam3); +void __fastcall d_NetSendCmdLoc(BOOL bHiPri,unsigned char bCmd,unsigned char x,unsigned char y); +void __fastcall d_NetSendCmdLocParam1(BOOL bHiPri,unsigned char bCmd,unsigned char x,unsigned char y,int wParam1); +void __fastcall d_NetSendCmdLocParam2(BOOL bHiPri,unsigned char bCmd,unsigned char x,unsigned char y,int wParam1,int wParam2); +void __fastcall d_NetSendCmdLocParam3(BOOL bHiPri,unsigned char bCmd,unsigned char x,unsigned char y,int wParam1,int wParam2,int wParam3); void __fastcall d_NetSendCmdParam1(BOOL bHiPri,unsigned char bCmd,unsigned short wParam1); void __fastcall d_NetSendCmdParam2(BOOL bHiPri,unsigned char bCmd,unsigned short wParam1,unsigned short wParam2); -void __fastcall d_NetSendCmdParam3(unsigned char bHiPri,unsigned char bCmd,unsigned short wParam1,unsigned short wParam2,int wParam3); -void __fastcall d_NetSendCmdQuest(unsigned char bHiPri,unsigned char q); -void __fastcall d_NetSendCmdGItem(unsigned char bHiPri,unsigned char bCmd,unsigned char mast,unsigned char pnum,int ii); +void __fastcall d_NetSendCmdParam3(BOOL bHiPri,unsigned char bCmd,unsigned short wParam1,unsigned short wParam2,int wParam3); +void __fastcall d_NetSendCmdQuest(BOOL bHiPri,unsigned char q); +void __fastcall d_NetSendCmdGItem(BOOL bHiPri,unsigned char bCmd,unsigned char mast,unsigned char pnum,int ii); void __fastcall d_NetSendCmdGItem2(unsigned char usonly,unsigned char bCmd,unsigned char mast,unsigned char pnum,struct TCmdGItem * p); bool __fastcall d_NetSendCmdReq2(unsigned char bCmd,unsigned char mast,unsigned char pnum,struct TCmdGItem * p); void __fastcall d_NetSendCmdExtra(struct TCmdGItem * p); -void __fastcall d_NetSendCmdPItem(unsigned char bHiPri,unsigned char bCmd,unsigned char x,unsigned char y); -void __fastcall d_NetSendCmdChItem(unsigned char bHiPri,unsigned char bLoc); +void __fastcall d_NetSendCmdPItem(BOOL bHiPri,unsigned char bCmd,unsigned char x,unsigned char y); +void __fastcall d_NetSendCmdChItem(BOOL bHiPri,unsigned char bLoc); void __fastcall d_NetSendCmdDelItem(BOOL bHiPri,unsigned char bLoc); -void __fastcall d_NetSendCmdDItem(unsigned char bHiPri,int ii); +void __fastcall d_NetSendCmdDItem(BOOL bHiPri,int ii); void __fastcall d_NetSendCmdDamage(BOOL bHiPri,unsigned char bPlr,unsigned int dwDam); void __fastcall d_NetSendCmdString(int a1,const char * pszStr); void __fastcall d_RemovePlrPortal(int pnum); @@ -1660,7 +1660,7 @@ bool __fastcall d_OperateFountains(int pnum,int i); void __fastcall d_OperateWeaponRack(int pnum,int i,unsigned char sendmsg); void __fastcall d_OperateStoryBook(int pnum,int i); void __fastcall d_OperateLazStand(int pnum,int i); -void __fastcall d_OperateObject(int pnum,int i,unsigned char TeleFlag); +void __fastcall d_OperateObject(int pnum,int i,BOOL TeleFlag); void __fastcall d_SyncOpL1Door(int pnum,int cmd,int i); void __fastcall d_SyncOpL2Door(int pnum,int cmd,int i); void __fastcall d_SyncOpL3Door(int pnum,int cmd,int i); @@ -1734,14 +1734,14 @@ void __fastcall d_pfile_flush(bool is_single_player,int save_num); bool __fastcall d_pfile_create_player_description(char * dst,int len); int __fastcall d_pfile_create_save_file(char * name_1,char * name_2); void __cdecl d_pfile_flush_W(); -void __fastcall d_game_2_ui_player(PlayerStruct * p,_uiheroinfo * heroinfo,bool bHasSaveFile); +void __fastcall d_game_2_ui_player(PlayerStruct * p,_uiheroinfo * heroinfo,BOOL bHasSaveFile); char __fastcall d_game_2_ui_class(PlayerStruct * p); BOOL __stdcall d_pfile_ui_set_hero_infos(BOOL (__stdcall * ui_add_hero_info)(_uiheroinfo *)); char * __fastcall d_GetSaveDirectory(char * dst,int dst_size,int save_num); bool __fastcall d_pfile_read_hero(void * archive,PkPlayerStruct * pPack); void * __fastcall d_pfile_open_save_archive(int * unused,int save_num); void __fastcall d_pfile_SFileCloseArchive(void * hsArchive); -bool __fastcall d_pfile_archive_contains_game(void * hsArchive); +BOOL __fastcall d_pfile_archive_contains_game(void * hsArchive); BOOL __stdcall d_pfile_ui_set_class_stats(int player_class_nr,_uidefaultstats * class_stats); int __fastcall d_pfile_get_player_class(int player_class_nr); BOOL __stdcall d_pfile_ui_save_create(_uiheroinfo * heroinfo); @@ -1815,7 +1815,7 @@ BOOL __fastcall d_PM_DoWalk(int pnum); BOOL __fastcall d_PM_DoWalk2(int pnum); BOOL __fastcall d_PM_DoWalk3(int pnum); BOOL __fastcall d_WeaponDur(int pnum,int durrnd); -bool __fastcall d_PlrHitMonst(int pnum,int m); +BOOL __fastcall d_PlrHitMonst(int pnum,int m); BOOL __fastcall d_PlrHitPlr(int pnum,char p); BOOL __fastcall d_PlrHitObj(int pnum,int mx,int my); BOOL __fastcall d_PM_DoAttack(int pnum); @@ -1833,7 +1833,7 @@ void __cdecl d_ProcessPlayers(); void __fastcall d_CheckCheatStats(int pnum); void __fastcall d_ClrPlrPath(int pnum); BOOL __fastcall d_PosOkPlayer(int pnum,int px,int py); -void __fastcall d_MakePlrPath(int pnum,int xx,int yy,unsigned char endspace); +void __fastcall d_MakePlrPath(int pnum,int xx,int yy,BOOL endspace); void __fastcall d_CheckPlrSpell(); void __fastcall d_SyncPlrAnim(int pnum); void __fastcall d_SyncInitPlrPos(int pnum); diff --git a/CMake/32bit.cmake b/CMake/32bit.cmake index 4422883c6..cecb7a322 100644 --- a/CMake/32bit.cmake +++ b/CMake/32bit.cmake @@ -20,3 +20,6 @@ if(DIR) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) endif() + +# 32-bit NASM +set(CMAKE_ASM_NASM_OBJECT_FORMAT elf) \ No newline at end of file diff --git a/CMake/CodeCoverage.cmake b/CMake/CodeCoverage.cmake new file mode 100644 index 000000000..674f7cd94 --- /dev/null +++ b/CMake/CodeCoverage.cmake @@ -0,0 +1,302 @@ +# Copyright (c) 2012 - 2017, Lars Bilke +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors +# may be used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# CHANGES: +# +# 2012-01-31, Lars Bilke +# - Enable Code Coverage +# +# 2013-09-17, Joakim Söderberg +# - Added support for Clang. +# - Some additional usage instructions. +# +# 2016-02-03, Lars Bilke +# - Refactored functions to use named parameters +# +# 2017-06-02, Lars Bilke +# - Merged with modified version from github.com/ufz/ogs +# +# +# USAGE: +# +# 1. Copy this file into your cmake modules path. +# +# 2. Add the following line to your CMakeLists.txt: +# include(CodeCoverage) +# +# 3. Append necessary compiler flags: +# APPEND_COVERAGE_COMPILER_FLAGS() +# +# 4. If you need to exclude additional directories from the report, specify them +# using the COVERAGE_LCOV_EXCLUDES variable before calling SETUP_TARGET_FOR_COVERAGE_LCOV. +# Example: +# set(COVERAGE_LCOV_EXCLUDES 'dir1/*' 'dir2/*') +# +# 5. Use the functions described below to create a custom make target which +# runs your test executable and produces a code coverage report. +# +# 6. Build a Debug build: +# cmake -DCMAKE_BUILD_TYPE=Debug .. +# make +# make my_coverage_target +# + +include(CMakeParseArguments) + +# Check prereqs +find_program( GCOV_PATH gcov ) +find_program( LCOV_PATH NAMES lcov lcov.bat lcov.exe lcov.perl) +find_program( GENHTML_PATH NAMES genhtml genhtml.perl genhtml.bat ) +find_program( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test) +find_program( SIMPLE_PYTHON_EXECUTABLE python ) + +if(NOT GCOV_PATH) + message(WARNING "gcov not found") + return() +endif() # NOT GCOV_PATH + +if("${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang") + if("${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS 3) + message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...") + endif() +elseif(NOT CMAKE_COMPILER_IS_GNUCXX) + message(WARNING "Compiler is not GNU gcc") + return() +endif() + +set(COVERAGE_COMPILER_FLAGS --coverage -fprofile-arcs -ftest-coverage + CACHE INTERNAL "") + +set(CMAKE_CXX_FLAGS_COVERAGE + ${COVERAGE_COMPILER_FLAGS} + CACHE STRING "Flags used by the C++ compiler during coverage builds." + FORCE ) +set(CMAKE_C_FLAGS_COVERAGE + ${COVERAGE_COMPILER_FLAGS} + CACHE STRING "Flags used by the C compiler during coverage builds." + FORCE ) +set(CMAKE_EXE_LINKER_FLAGS_COVERAGE + "" + CACHE STRING "Flags used for linking binaries during coverage builds." + FORCE ) +set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE + "" + CACHE STRING "Flags used by the shared libraries linker during coverage builds." + FORCE ) + +mark_as_advanced( + CMAKE_CXX_FLAGS_COVERAGE + CMAKE_C_FLAGS_COVERAGE + CMAKE_EXE_LINKER_FLAGS_COVERAGE + CMAKE_SHARED_LINKER_FLAGS_COVERAGE ) + +if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") + message(WARNING "Code coverage results with an optimised (non-Debug) build may be misleading") +endif() # NOT CMAKE_BUILD_TYPE STREQUAL "Debug" + +# Defines a target for running and collection code coverage information +# Builds dependencies, runs the given executable and outputs reports. +# NOTE! The executable should always have a ZERO as exit code otherwise +# the coverage generation will not complete. +# +# SETUP_TARGET_FOR_COVERAGE_LCOV( +# NAME testrunner_coverage # New target name +# EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR +# DEPENDENCIES testrunner # Dependencies to build first +# ) +function(SETUP_TARGET_FOR_COVERAGE_LCOV) + + set(options NONE) + set(oneValueArgs NAME) + set(multiValueArgs EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES) + cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(NOT LCOV_PATH) + message(FATAL_ERROR "lcov not found! Aborting...") + endif() # NOT LCOV_PATH + + if(NOT GENHTML_PATH) + message(FATAL_ERROR "genhtml not found! Aborting...") + endif() # NOT GENHTML_PATH + + # Setup target + add_custom_target(${Coverage_NAME} + + # Cleanup lcov + COMMAND ${LCOV_PATH} --gcov-tool ${GCOV_PATH} -directory . --zerocounters + # Create baseline to make sure untouched files show up in the report + COMMAND ${LCOV_PATH} --gcov-tool ${GCOV_PATH} -c -i -d . -o ${Coverage_NAME}.base + + # Run tests + COMMAND ${Coverage_EXECUTABLE} + + # Capturing lcov counters and generating report + COMMAND ${LCOV_PATH} --gcov-tool ${GCOV_PATH} --directory . --capture --output-file ${Coverage_NAME}.info + # add baseline counters + COMMAND ${LCOV_PATH} --gcov-tool ${GCOV_PATH} -a ${Coverage_NAME}.base -a ${Coverage_NAME}.info --output-file ${Coverage_NAME}.total + COMMAND ${LCOV_PATH} --gcov-tool ${GCOV_PATH} --remove ${Coverage_NAME}.total ${COVERAGE_LCOV_EXCLUDES} --output-file ${PROJECT_BINARY_DIR}/${Coverage_NAME}.info.cleaned + COMMAND ${GENHTML_PATH} -o ${Coverage_NAME} ${PROJECT_BINARY_DIR}/${Coverage_NAME}.info.cleaned + COMMAND ${CMAKE_COMMAND} -E remove ${Coverage_NAME}.base ${Coverage_NAME}.total ${PROJECT_BINARY_DIR}/${Coverage_NAME}.info.cleaned + + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + DEPENDS ${Coverage_DEPENDENCIES} + COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report." + ) + + # Show where to find the lcov info report + add_custom_command(TARGET ${Coverage_NAME} POST_BUILD + COMMAND ; + COMMENT "Lcov code coverage info report saved in ${Coverage_NAME}.info." + ) + + # Show info where to find the report + add_custom_command(TARGET ${Coverage_NAME} POST_BUILD + COMMAND ; + COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report." + ) + +endfunction() # SETUP_TARGET_FOR_COVERAGE_LCOV + +# Defines a target for running and collection code coverage information +# Builds dependencies, runs the given executable and outputs reports. +# NOTE! The executable should always have a ZERO as exit code otherwise +# the coverage generation will not complete. +# +# SETUP_TARGET_FOR_COVERAGE_GCOVR_XML( +# NAME ctest_coverage # New target name +# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR +# DEPENDENCIES executable_target # Dependencies to build first +# ) +function(SETUP_TARGET_FOR_COVERAGE_GCOVR_XML) + + set(options NONE) + set(oneValueArgs NAME) + set(multiValueArgs EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES) + cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(NOT SIMPLE_PYTHON_EXECUTABLE) + message(FATAL_ERROR "python not found! Aborting...") + endif() # NOT SIMPLE_PYTHON_EXECUTABLE + + if(NOT GCOVR_PATH) + message(FATAL_ERROR "gcovr not found! Aborting...") + endif() # NOT GCOVR_PATH + + # Combine excludes to several -e arguments + set(GCOVR_EXCLUDES "") + foreach(EXCLUDE ${COVERAGE_GCOVR_EXCLUDES}) + list(APPEND GCOVR_EXCLUDES "-e") + list(APPEND GCOVR_EXCLUDES "${EXCLUDE}") + endforeach() + + add_custom_target(${Coverage_NAME} + # Run tests + ${Coverage_EXECUTABLE} + + # Running gcovr + COMMAND ${GCOVR_PATH} --xml + -r ${PROJECT_SOURCE_DIR} ${GCOVR_EXCLUDES} + --object-directory=${PROJECT_BINARY_DIR} + -o ${Coverage_NAME}.xml + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + DEPENDS ${Coverage_DEPENDENCIES} + COMMENT "Running gcovr to produce Cobertura code coverage report." + ) + + # Show info where to find the report + add_custom_command(TARGET ${Coverage_NAME} POST_BUILD + COMMAND ; + COMMENT "Cobertura code coverage report saved in ${Coverage_NAME}.xml." + ) + +endfunction() # SETUP_TARGET_FOR_COVERAGE_GCOVR_XML + +# Defines a target for running and collection code coverage information +# Builds dependencies, runs the given executable and outputs reports. +# NOTE! The executable should always have a ZERO as exit code otherwise +# the coverage generation will not complete. +# +# SETUP_TARGET_FOR_COVERAGE_GCOVR_HTML( +# NAME ctest_coverage # New target name +# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR +# DEPENDENCIES executable_target # Dependencies to build first +# ) +function(SETUP_TARGET_FOR_COVERAGE_GCOVR_HTML) + + set(options NONE) + set(oneValueArgs NAME) + set(multiValueArgs EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES) + cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(NOT SIMPLE_PYTHON_EXECUTABLE) + message(WARNING "python not found! Aborting...") + return() + endif() # NOT SIMPLE_PYTHON_EXECUTABLE + + if(NOT GCOVR_PATH) + message(WARNING "gcovr not found! Aborting...") + return() + endif() # NOT GCOVR_PATH + + # Combine excludes to several -e arguments + set(GCOVR_EXCLUDES "") + foreach(EXCLUDE ${COVERAGE_GCOVR_EXCLUDES}) + list(APPEND GCOVR_EXCLUDES "-e") + list(APPEND GCOVR_EXCLUDES "${EXCLUDE}") + endforeach() + + add_custom_target(${Coverage_NAME} + # Run tests + ${Coverage_EXECUTABLE} + + # Create folder + COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/${Coverage_NAME} + + # Running gcovr + COMMAND ${GCOVR_PATH} --html --html-details + -r ${PROJECT_SOURCE_DIR} ${GCOVR_EXCLUDES} + --object-directory=${PROJECT_BINARY_DIR} + -o ${Coverage_NAME}/index.html + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + DEPENDS ${Coverage_DEPENDENCIES} + COMMENT "Running gcovr to produce HTML code coverage report." + ) + + # Show info where to find the report + add_custom_command(TARGET ${Coverage_NAME} POST_BUILD + COMMAND ; + COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report." + ) + +endfunction() # SETUP_TARGET_FOR_COVERAGE_GCOVR_HTML + +function(APPEND_COVERAGE_COMPILER_FLAGS) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE) + message(STATUS "Appending code coverage compiler flags: ${COVERAGE_COMPILER_FLAGS}") +endfunction() # APPEND_COVERAGE_COMPILER_FLAGS diff --git a/CMake/absolute.cmake b/CMake/absolute.cmake index c3dad5754..b84535bf8 100644 --- a/CMake/absolute.cmake +++ b/CMake/absolute.cmake @@ -8,29 +8,19 @@ if(EXISTS "${ORIGINAL_EXE}") message(FATAL_ERROR "MD5 of EXE is not correct (${MD5SUM})") endif() - find_program(ASM NAMES nasm yasm) + enable_language(ASM_NASM) - set(HARNESS_OBJECT "${CMAKE_BINARY_DIR}/harness.o") set(HARNESS_ASM "${CMAKE_SOURCE_DIR}/Absolute/harness.asm") - add_library(harness OBJECT ${HARNESS_OBJECT}) - target_compile_options(harness PUBLIC -no-pie) + # This can not be an OBJECT library since those can not have link flags on older versions of cmake + add_library(harness STATIC ${HARNESS_ASM}) + target_compile_options(harness PRIVATE -f elf -DEXE=\"${ORIGINAL_EXE}\") + + target_compile_options(harness INTERFACE -no-pie) target_compile_definitions(harness INTERFACE -DNO_GLOBALS) - # For some reason, HARNESS_OBJECT needs to be added here even though it's in the sources above target_link_libraries(harness INTERFACE - ${HARNESS_OBJECT} -L${CMAKE_SOURCE_DIR}/Absolute -Tdefault.ld ) - - add_custom_command( - COMMENT Assembling - OUTPUT ${HARNESS_OBJECT} - MAIN_DEPENDENCY ${HARNESS_ASM} - COMMAND ${ASM} - -f elf -DEXE=\\"${ORIGINAL_EXE}\\" - -o ${HARNESS_OBJECT} - ${HARNESS_ASM} - ) else() message(STATUS "Original .exe not found at ${ORIGINAL_EXE}") endif() diff --git a/CMakeLists.txt b/CMakeLists.txt index 2932f52de..00e36439a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,7 +31,8 @@ endif() string(APPEND CMAKE_CXX_FLAGS_DEBUG " -fno-omit-frame-pointer") if(NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang") # Clang/LLVM optimizations break everything - string(APPEND CMAKE_CXX_FLAGS_DEBUG " -Og") +# string(APPEND CMAKE_CXX_FLAGS_DEBUG " -Og") +# string(APPEND CMAKE_CXX_FLAGS_DEBUG " -fvar-tracking-assignments -ggdb -gdwarf-4") endif() set(SOURCES @@ -148,6 +149,7 @@ set(STUB_SOURCES include(CMake/SDL2_fixed.cmake) include(CMake/sanitize.cmake) include(CMake/absolute.cmake) +include(CMake/CodeCoverage.cmake) include_directories(${SDL2_INCLUDE_DIRS}) @@ -190,7 +192,8 @@ if(TARGET harness) add_executable(devil-harness ${SOURCES} ${STUB_SOURCES} - Stub/main_harness.cpp + # Stub/main_harness.cpp + Stub/main_test_harness.cpp Absolute/absolute.cpp Absolute/hook.cpp ) @@ -211,10 +214,20 @@ add_executable(devil-sanitize target_compile_options(devil-sanitize PRIVATE ${SANITIZE_OPTIONS} + ${COVERAGE_COMPILER_FLAGS} ) target_link_libraries(devil-sanitize PUBLIC m ${SDL2_LIBRARIES} ${SANITIZE_OPTIONS} + ${COVERAGE_COMPILER_FLAGS} ) + +if(COVERAGE_COMPILER_FLAGS) + SETUP_TARGET_FOR_COVERAGE_GCOVR_HTML( + NAME devil-sanitize-coverage + EXECUTABLE devil-sanitize + DEPENDENCIES devil-sanitize + ) +endif() diff --git a/Stub/main_test_harness.cpp b/Stub/main_test_harness.cpp new file mode 100644 index 000000000..991d5bb9e --- /dev/null +++ b/Stub/main_test_harness.cpp @@ -0,0 +1,86 @@ +#include +#include + +#include "../types.h" +#include "Absolute/absolute.h" +#include "stubs.h" + +static void valgrind_init() +{ + char *start = &__start_bss; + unsigned len = (char *)&__end_bss - start; + VALGRIND_MAKE_MEM_UNDEFINED(start, len); + + // Global destructors in msgcmd_cleanup_chatcmd() read this + VALGRIND_MAKE_MEM_DEFINED(&sgChat_Cmd, sizeof(sgChat_Cmd)); +} + +static void init() +{ + valgrind_init(); + + init_archives(); + + encrypt_init_lookup_table(); + diablo_init_screen(); + + InitLightTable(); + + gdwNormalMsgSize = 512; + + gbMaxPlayers = 1; + + light4flag = 0; // VALGRIND +} + +static void test_levelgen() +{ + init(); + + SetRndSeed(123); + int v2 = 0; + do { + glSeedTbl[v2] = GetRndSeed(); + gnLevelTypeTbl[v2] = InitNewSeed(v2); + ++v2; + } while (v2 < 17); + + setlevel = 0; // VALGRIND + currlevel = 2; + leveltype = DTYPE_CATACOMBS; + + pHallList = 0; // VALGRIND: Linked list initialized to 0 + pSetPiece_2 = 0; // VALGRIND: Always freed, even when it is not loaded + + nSx1 = nSx2 = nSy1 = nSy2 = 0; // VALGRIND: Looks like the DRLG code assumes these can be 0 + + InitLighting(); + + InitQuests(); + + DRLG_Init_Globals(); // VALGRIND: Initialize the d* arrays. This is also called by DRLG_L2() but *after* it touches + // them. + + LoadLvlGFX(); + + CreateLevel(0); + + // LoadGameLevel(TRUE, 0); +} + +static void test_newgame() +{ + init(); + + start_game(WM_DIABNEWGAME); +} + +int main(int argc, char **argv) +{ + test_levelgen(); + // test_newgame(); + + eprintf("Done!\n"); + + return 0; +}