diff --git a/CMakeLists.txt b/CMakeLists.txt index 5fd99b59f9..22b9a6a5ee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,6 +21,9 @@ list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") # We don't support building in-tree. include(PreventInTreeBuilds) +include(Util) + +set(TOUCHES_DIR ${PROJECT_BINARY_DIR}/touches) set_property(GLOBAL PROPERTY USE_FOLDERS ON) @@ -611,34 +614,44 @@ find_program(STYLUA_PRG stylua) find_program(FLAKE8_PRG flake8) find_program(UNCRUSTIFY_PRG uncrustify) find_program(SHELLCHECK_PRG shellcheck) -include(DefCmdTarget) -def_cmd_target(lintlua ${LUACHECK_PRG} LUACHECK_PRG true) -if(LUACHECK_PRG) - add_custom_command(TARGET lintlua - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - COMMAND ${LUACHECK_PRG} -q runtime/ scripts/ src/ test/) -endif() -if(STYLUA_PRG) - add_custom_command(TARGET lintlua - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - COMMAND ${STYLUA_PRG} --color=always --check runtime/) -else() - add_custom_command(TARGET lintlua COMMAND ${CMAKE_COMMAND} -E echo "STYLUA_PRG not found") -endif() -def_cmd_target(lintpy ${FLAKE8_PRG} FLAKE8_PRG false) -if(FLAKE8_PRG) - add_custom_command(TARGET lintpy - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - COMMAND ${FLAKE8_PRG} contrib/ scripts/ src/ test/) -endif() -def_cmd_target(lintsh ${SHELLCHECK_PRG} SHELLCHECK_PRG false) -if(SHELLCHECK_PRG) - add_custom_command(TARGET lintsh - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - COMMAND ${SHELLCHECK_PRG} scripts/vim-patch.sh) -endif() + +add_glob_targets( + REQUIRED + TARGET lintlua-luacheck + COMMAND ${LUACHECK_PRG} + FLAGS -q + GLOB_DIRS runtime/ scripts/ src/ test/ + GLOB_PAT *.lua + TOUCH_STRATEGY SINGLE + ) + +add_glob_targets( + TARGET lintlua-stylua + COMMAND ${STYLUA_PRG} + FLAGS --color=always --check + GLOB_DIRS runtime/ + GLOB_PAT *.lua + TOUCH_STRATEGY SINGLE + ) + +add_custom_target(lintlua) +add_dependencies(lintlua lintlua-luacheck lintlua-stylua) include(InstallHelpers) +add_glob_targets( + TARGET lintpy + COMMAND ${FLAKE8_PRG} + GLOB_DIRS contrib scripts src test + GLOB_PAT *.py + TOUCH_STRATEGY SINGLE + ) + +add_glob_targets( + TARGET lintsh + COMMAND ${SHELLCHECK_PRG} + FILES scripts/vim-patch.sh + TOUCH_STRATEGY SINGLE + ) install_helper( FILES ${CMAKE_SOURCE_DIR}/src/man/nvim.1 diff --git a/cmake/DefCmdTarget.cmake b/cmake/DefCmdTarget.cmake deleted file mode 100644 index 48e90cf5c8..0000000000 --- a/cmake/DefCmdTarget.cmake +++ /dev/null @@ -1,19 +0,0 @@ -# Defines a target named ${target}. If ${prg} is undefined the target prints -# "not found". -# -# - Use add_custom_command(TARGET ...) to append a command to the -# target. -function(def_cmd_target target prg prg_name prg_fatal) - add_custom_target(${target}) - - if(NOT prg) - if(prg_fatal) - add_custom_command(TARGET ${target} - COMMAND ${CMAKE_COMMAND} -E echo "${target}: ${prg_name} not found" - COMMAND false) - else() - add_custom_command(TARGET ${target} - COMMAND ${CMAKE_COMMAND} -E echo "${target}: SKIP: ${prg_name} not found") - endif() - endif() -endfunction() diff --git a/cmake/RunUncrustify.cmake b/cmake/RunUncrustify.cmake deleted file mode 100644 index 7f5e2a34f4..0000000000 --- a/cmake/RunUncrustify.cmake +++ /dev/null @@ -1,16 +0,0 @@ -# HACK: This script is invoked with "cmake -P …" as a workaround to silence uncrustify. - -# Split space-separated string into a cmake list, so that execute_process() -# will pass each file as individual arg to uncrustify. -string(REPLACE " " ";" NVIM_SOURCES ${NVIM_SOURCES}) -string(REPLACE " " ";" NVIM_HEADERS ${NVIM_HEADERS}) - -execute_process( - COMMAND ${UNCRUSTIFY_PRG} -c "${PROJECT_SOURCE_DIR}/src/uncrustify.cfg" -q --check ${NVIM_SOURCES} ${NVIM_HEADERS} - OUTPUT_VARIABLE crusty_out - ERROR_VARIABLE crusty_err - RESULT_VARIABLE crusty_res) - -if(NOT crusty_res EQUAL 0) - message(FATAL_ERROR "crusty: ${crusty_res} ${crusty_err}") -endif() diff --git a/cmake/Util.cmake b/cmake/Util.cmake new file mode 100644 index 0000000000..b485f4606b --- /dev/null +++ b/cmake/Util.cmake @@ -0,0 +1,145 @@ +# Defines a target that depends on FILES and the files found by globbing +# when using GLOB_PAT and GLOB_DIRS. The target will rerun if any files it +# depends on has changed. Which files the target will run the command on +# depends on the value of TOUCH_STRATEGY. +# +# Options: +# REQUIRED - Abort if COMMAND doesn't exist. +# +# Single value arguments: +# TARGET - Name of the target +# COMMAND - Path of the command to be run +# GLOB_PAT - Glob pattern to use. Only used if GLOB_DIRS is specified +# TOUCH_STRATEGY - Specify touch strategy, meaning decide how to group files +# and connect them to a specific touch file. +# +# For example, let us say we have file A and B and that we create a touch file +# for each of them, TA and TB. This would essentially make file A and B +# independent of each other, meaning that if I change file A and run the +# target, then the target will only run its commands for file A and ignore +# file B. +# +# Another example: let's say we have file A and B, but now we create only a +# single touch file T for both of them. This would mean that if I change +# either file A or B, then the target will run its commands on both A and B. +# Meaning that even if I only change file A, the target will still run +# commands on both A and B. +# +# The more touch files we create for a target, the fewer commands we'll need +# to rerun, and by extension, the more time we'll save. Unfortunately, the +# more touch files we create the more intermediary targets will be created, +# one for each touch file. This makes listing all targets with +# `cmake --build build --target help` less useful since each touch file will +# be listed. The tradeoff that needs to be done here is between performance +# and "discoverability". As a general guideline: the more popular a target is +# and the more time it takes to run it, the more granular you want your touch +# files to be. Conversely, if a target rarely needs to be run or if it's fast, +# then you should create fewer targets. +# +# Possible values for TOUCH_STRATEGY: +# "SINGLE": create a single touch file for all files. +# "PER_FILE": create a touch file for each file. Defaults to this if +# TOUCH_STRATEGY isn't specified. +# "PER_DIR": create a touch file for each directory. +# +# List arguments: +# FLAGS - List of flags to use after COMMAND +# FILES - List of files to use COMMAND on. It's possible to combine this +# with GLOB_PAT and GLOB_DIRS; the files found by globbing will +# simple be added to FILES +# GLOB_DIRS - The directories to recursively search for files with extension +# GLOB_PAT +# +function(add_glob_targets) + cmake_parse_arguments(ARG + "REQUIRED" + "TARGET;COMMAND;GLOB_PAT;TOUCH_STRATEGY" + "FLAGS;FILES;GLOB_DIRS" + ${ARGN} + ) + + if(NOT ARG_COMMAND) + add_custom_target(${ARG_TARGET}) + if(ARG_REQUIRED) + add_custom_command(TARGET ${ARG_TARGET} + COMMAND ${CMAKE_COMMAND} -E echo "${ARG_TARGET}: ${ARG_COMMAND} not found" + COMMAND false) + else() + add_custom_command(TARGET ${ARG_TARGET} + COMMAND ${CMAKE_COMMAND} -E echo "${ARG_TARGET} SKIP: ${ARG_COMMAND} not found") + endif() + return() + endif() + + foreach(gd ${ARG_GLOB_DIRS}) + file(GLOB_RECURSE globfiles ${PROJECT_SOURCE_DIR}/${gd}/${ARG_GLOB_PAT}) + list(APPEND ARG_FILES ${globfiles}) + endforeach() + + if(NOT ARG_TOUCH_STRATEGY) + set(ARG_TOUCH_STRATEGY PER_FILE) + endif() + set(POSSIBLE_TOUCH_STRATEGIES SINGLE PER_FILE PER_DIR) + if(NOT ARG_TOUCH_STRATEGY IN_LIST POSSIBLE_TOUCH_STRATEGIES) + message(FATAL_ERROR "Unrecognized value for TOUCH_STRATEGY: ${ARG_TOUCH_STRATEGY}") + endif() + + if(ARG_TOUCH_STRATEGY STREQUAL SINGLE) + set(touch_file ${TOUCHES_DIR}/ran-${ARG_TARGET}) + add_custom_command( + OUTPUT ${touch_file} + COMMAND ${CMAKE_COMMAND} -E touch ${touch_file} + COMMAND ${ARG_COMMAND} ${ARG_FLAGS} ${ARG_FILES} + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + DEPENDS ${ARG_FILES}) + list(APPEND touch_list ${touch_file}) + elseif(ARG_TOUCH_STRATEGY STREQUAL PER_FILE) + set(touch_dir ${TOUCHES_DIR}/${ARG_TARGET}) + file(MAKE_DIRECTORY ${touch_dir}) + foreach(f ${ARG_FILES}) + string(REGEX REPLACE "^${PROJECT_SOURCE_DIR}/" "" tf ${f}) + string(REGEX REPLACE "[/.]" "-" tf ${tf}) + set(touch_file ${touch_dir}/ran-${tf}) + add_custom_command( + OUTPUT ${touch_file} + COMMAND ${CMAKE_COMMAND} -E touch ${touch_file} + COMMAND ${ARG_COMMAND} ${ARG_FLAGS} ${f} + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + DEPENDS ${f}) + list(APPEND touch_list ${touch_file}) + endforeach() + elseif(ARG_TOUCH_STRATEGY STREQUAL PER_DIR) + set(touch_dirs) + foreach(f ${ARG_FILES}) + get_filename_component(out ${f} DIRECTORY) + list(APPEND touch_dirs ${out}) + endforeach() + list(REMOVE_DUPLICATES touch_dirs) + + foreach(touch_dir ${touch_dirs}) + set(relevant_files) + foreach(f ${ARG_FILES}) + get_filename_component(out ${f} DIRECTORY) + if(${touch_dir} STREQUAL ${out}) + list(APPEND relevant_files ${f}) + endif() + endforeach() + + set(td ${TOUCHES_DIR}/${ARG_TARGET}) + file(MAKE_DIRECTORY ${td}) + string(REGEX REPLACE "^${PROJECT_SOURCE_DIR}/" "" tf ${touch_dir}) + string(REGEX REPLACE "[/.]" "-" tf ${tf}) + set(touch_file ${td}/ran-${tf}) + + add_custom_command( + OUTPUT ${touch_file} + COMMAND ${CMAKE_COMMAND} -E touch ${touch_file} + COMMAND ${ARG_COMMAND} ${ARG_FLAGS} ${relevant_files} + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + DEPENDS ${relevant_files}) + list(APPEND touch_list ${touch_file}) + endforeach() + endif() + + add_custom_target(${ARG_TARGET} DEPENDS ${touch_list}) +endfunction() diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index a6c4bafc78..a0b8f16a39 100755 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -1,7 +1,5 @@ option(USE_GCOV "Enable gcov support" OFF) -include(DefCmdTarget) - if(USE_GCOV) if(CLANG_TSAN) # GCOV and TSAN results in false data race reports @@ -24,7 +22,6 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -framework CoreServices") endif() -set(TOUCHES_DIR ${PROJECT_BINARY_DIR}/touches) set(GENERATOR_DIR ${CMAKE_CURRENT_LIST_DIR}/generators) set(GENERATED_DIR ${PROJECT_BINARY_DIR}/src/nvim/auto) set(BINARY_LIB_DIR ${PROJECT_BINARY_DIR}/lib/nvim/) @@ -800,16 +797,12 @@ foreach(sfile ${LINT_NVIM_SOURCES}) endforeach() add_custom_target(lintc DEPENDS ${LINT_TARGETS}) -def_cmd_target(lintuncrustify ${UNCRUSTIFY_PRG} UNCRUSTIFY_PRG false) -if(UNCRUSTIFY_PRG) - add_custom_command(TARGET lintuncrustify - COMMAND ${CMAKE_COMMAND} - -D UNCRUSTIFY_PRG=${UNCRUSTIFY_PRG} - -D PROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR} - -D NVIM_SOURCES="${NVIM_SOURCES}" - -D NVIM_HEADERS="${NVIM_HEADERS}" - -P ${PROJECT_SOURCE_DIR}/cmake/RunUncrustify.cmake) -endif() +add_glob_targets( + TARGET lintuncrustify + COMMAND ${UNCRUSTIFY_PRG} + FLAGS -c "${PROJECT_SOURCE_DIR}/src/uncrustify.cfg" -q --check + FILES ${LINT_NVIM_SOURCES} + ) add_custom_target( lintcfull