From b4020e82e8cc4ffedd38abab1fe83dbfea198565 Mon Sep 17 00:00:00 2001 From: staphen Date: Mon, 11 Aug 2025 01:45:42 -0400 Subject: [PATCH] Automatically trim retired assets from the build folder --- CMake/Assets.cmake | 13 ++++- CMake/functions/trim_retired_files.cmake | 73 ++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 CMake/functions/trim_retired_files.cmake diff --git a/CMake/Assets.cmake b/CMake/Assets.cmake index f021786be..b592310a4 100644 --- a/CMake/Assets.cmake +++ b/CMake/Assets.cmake @@ -1,3 +1,5 @@ +include(functions/trim_retired_files) + if(NOT DEFINED DEVILUTIONX_ASSETS_OUTPUT_DIRECTORY) set(DEVILUTIONX_ASSETS_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/assets") endif() @@ -205,7 +207,7 @@ if(APPLE) else() # Copy assets to the build assets subdirectory. This serves two purposes: # - If smpq is installed, devilutionx.mpq is built from these files. - # - If smpq is not installed, the game will load the assets directly from this directoy. + # - If smpq is not installed, the game will load the assets directly from this directory. foreach(asset_file ${devilutionx_assets}) set(src "${CMAKE_CURRENT_SOURCE_DIR}/assets/${asset_file}") set(dst "${DEVILUTIONX_ASSETS_OUTPUT_DIRECTORY}/${asset_file}") @@ -224,6 +226,11 @@ else() endforeach() endif() + add_trim_command( + ROOT_FOLDER "${DEVILUTIONX_ASSETS_OUTPUT_DIRECTORY}" + CURRENT_FILES ${DEVILUTIONX_MPQ_FILES}) + add_custom_target(devilutionx_trim_assets DEPENDS "${TRIM_COMMAND_OUTPUT}") + if(BUILD_ASSETS_MPQ) set(DEVILUTIONX_MPQ "${CMAKE_CURRENT_BINARY_DIR}/devilutionx.mpq") add_custom_command( @@ -232,12 +239,14 @@ else() COMMAND ${CMAKE_COMMAND} -E remove -f "${DEVILUTIONX_MPQ}" COMMAND ${SMPQ} -A -M 1 -C BZIP2 -c "${DEVILUTIONX_MPQ}" ${DEVILUTIONX_MPQ_FILES} WORKING_DIRECTORY "${DEVILUTIONX_ASSETS_OUTPUT_DIRECTORY}" - DEPENDS ${DEVILUTIONX_OUTPUT_ASSETS_FILES} ${devilutionx_lang_targets} ${devilutionx_lang_files} + DEPENDS ${TRIM_COMMAND_BYPRODUCT} ${DEVILUTIONX_OUTPUT_ASSETS_FILES} ${devilutionx_lang_targets} ${devilutionx_lang_files} VERBATIM) add_custom_target(devilutionx_mpq DEPENDS "${DEVILUTIONX_MPQ}") + add_dependencies(devilutionx_mpq devilutionx_trim_assets) add_dependencies(libdevilutionx devilutionx_mpq) else() add_custom_target(devilutionx_copied_assets DEPENDS ${DEVILUTIONX_OUTPUT_ASSETS_FILES} ${devilutionx_lang_targets}) + add_dependencies(devilutionx_copied_assets devilutionx_trim_assets) add_dependencies(libdevilutionx devilutionx_copied_assets) endif() endif() diff --git a/CMake/functions/trim_retired_files.cmake b/CMake/functions/trim_retired_files.cmake new file mode 100644 index 000000000..36643ed21 --- /dev/null +++ b/CMake/functions/trim_retired_files.cmake @@ -0,0 +1,73 @@ +set(SCRIPT_CONTENT [=[ +include(functions/trim_retired_files) +trim_retired_files("${ROOT_FOLDER}" "${CURRENT_FILES}" "${OUTPUT_FILE}") +]=]) + +function(trim_retired_files root_folder current_files output_file) + file( + GLOB_RECURSE retired_files + RELATIVE "${root_folder}" + "${root_folder}/*") + + list(REMOVE_ITEM retired_files ${current_files}) + list(LENGTH retired_files retired_file_count) + foreach(retired_file ${retired_files}) + file(REMOVE "${root_folder}/${retired_file}") + endforeach() + + if(${retired_file_count} GREATER 0 OR NOT EXISTS ${output_file}) + file(TOUCH ${output_file}) + endif() +endfunction(trim_retired_files) + +function(add_trim_command) + set(oneValueArgs + ROOT_FOLDER + OUTPUT + BYPRODUCT + SCRIPT_PATH) + + set(multiValueArgs CURRENT_FILES) + cmake_parse_arguments(PARSE_ARGV 0 arg "" "${oneValueArgs}" "${multiValueArgs}") + + if(NOT arg_ROOT_FOLDER) + message(FATAL_ERROR "add_trim_command: missing required parameter ROOT_FOLDER") + endif() + if(NOT arg_OUTPUT OR NOT arg_BYPRODUCT OR NOT arg_SCRIPT_PATH) + cmake_path(GET arg_ROOT_FOLDER FILENAME root_filename) + if(NOT arg_OUTPUT) + set(arg_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${root_filename}.dne") + endif() + if(NOT arg_BYPRODUCT) + set(arg_BYPRODUCT "${CMAKE_CURRENT_BINARY_DIR}/${root_filename}.rm") + endif() + if(NOT arg_SCRIPT_PATH) + get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) + if(is_multi_config) + set(arg_SCRIPT_PATH "${CMAKE_CURRENT_BINARY_DIR}/${root_filename}_$.cmake") + else() + set(arg_SCRIPT_PATH "${CMAKE_CURRENT_BINARY_DIR}/${root_filename}.cmake") + endif() + endif() + endif() + + # Mark the output file as SYMBOLIC to indicate that it will not be created by the command. + # Since its output file is never created, this command should execute on every build. + set_source_files_properties("${arg_OUTPUT}" PROPERTIES SYMBOLIC true) + + file(GENERATE OUTPUT "${arg_SCRIPT_PATH}" CONTENT "${SCRIPT_CONTENT}") + add_custom_command( + COMMENT "Trimming ${arg_ROOT_FOLDER}" + OUTPUT "${arg_OUTPUT}" + BYPRODUCTS "${arg_BYPRODUCT}" + COMMAND ${CMAKE_COMMAND} + -D "CMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}" + -D "ROOT_FOLDER=${arg_ROOT_FOLDER}" + -D "CURRENT_FILES=${arg_CURRENT_FILES}" + -D "OUTPUT_FILE=${arg_BYPRODUCT}" + -P "${arg_SCRIPT_PATH}" + VERBATIM) + + set(TRIM_COMMAND_OUTPUT "${arg_OUTPUT}" PARENT_SCOPE) + set(TRIM_COMMAND_BYPRODUCT "${arg_BYPRODUCT}" PARENT_SCOPE) +endfunction(add_trim_command)