我遇到了自定义目标的add_custom_command问题(使用add_custom_target创建)。
我的一般想法是将静态代码分析工具整合到cmake工具链中。我的解决方案基于此处描述的解决方案:https://github.com/rpavlik/cmake-modules/blob/master/CppcheckTargets.cmake
简而言之,我想运行静态代码分析的每个项目都有以下两行代码:
include(cppcheck)
add_cppcheck(${le_project} STYLE POSSIBLE_ERROR FAIL_ON_WARNINGS)
模块位于文件顶部:
if (NOT TARGET ANALYZE_CODE)
add_custom_target(ANALYZE_CODE WORKING_DIRECTORY ${LE_LITEN_ROOT})
set_target_properties(ANALYZE_CODE PROPERTIES EXCLUDE_FROM_ALL TRUE)
endif ()
以及稍后在函数中添加了custom命令:
add_custom_command(TARGET
ANALYZE_CODE
PRE_BUILD
COMMAND
${CPPCHECK_EXECUTABLE}
${CPPCHECK_QUIET_ARG}
${CPPCHECK_TEMPLATE_ARG}
${_cppcheck_args}
${_files}
WORKING_DIRECTORY
"${CMAKE_CURRENT_SOURCE_DIR}"
COMMENT
"${_name}_cppcheck: Running cppcheck on target ${_name}..."
VERBATIM)
我看到的问题是该命令仅为包含该文件的项目添加。我不确定为什么以及发生了什么。我使用message()命令验证了以下内容:
但是当我实际查看visual studio中的目标时,只会添加第一个include / function call命令。
如果仅在不调用该函数的情况下包含该文件,则根本不会添加任何自定义命令。
所需行为
我想要一个名为“ANALYZE_CODE”的目标来运行通过调用函数添加的所有命令。
即。如果3个项目包含上面的两行,则创建目标ANALYZE_CODE一次,但会为其添加3个自定义命令,每个项目一个。
答案 0 :(得分:3)
事实证明,你在这里的岩石和硬地之间有点卡住了。我认为这个问题归结为几个因素。
首先,虽然文档没有说清楚,但add_custom_command(TARGET ...)
仅适用于在同一目录中创建的目标。因此,调用include(cppcheck)
的第一个子项目是唯一可以有效地向目标ANALYZE_CODE
添加自定义命令的子项目。
解决方法似乎是将所有对add_cppcheck
的调用从各自的子目录移至顶级CMakeLists文件。
include(cppcheck)
add_cppcheck(${le_first_project} STYLE POSSIBLE_ERROR FAIL_ON_WARNINGS)
add_cppcheck(${le_second_project} STYLE POSSIBLE_ERROR FAIL_ON_WARNINGS)
...
这不是一个很好的解决方案,因为它们确实属于它们自己的子目录。但更大的问题是源文件上的属性只存在于添加它们的CMakeLists.txt的范围内。这根本不是显而易见的,而是来自set_source_files_properties
的文档:
源文件属性仅对添加到同一目录(CMakeLists.txt)中的目标可见。
add_cppcheck
的内部有以下代码块:
foreach(_source ${_cppcheck_sources})
get_source_file_property(_cppcheck_lang "${_source}" LANGUAGE)
get_source_file_property(_cppcheck_loc "${_source}" LOCATION)
if("${_cppcheck_lang}" MATCHES "CXX")
list(APPEND _files "${_cppcheck_loc}")
endif()
endforeach()
所以这是检查给定目标的每个源文件是否被指定为C ++文件,然后将其添加到要提供给cppcheck的文件列表中。如果从定义目标的CMakeLists.txt(即子目录)中调用此函数,则文件都具有适当的属性并正确添加。
但是,如果从父CMakeLists.txt调用该函数,则文件已丢失其属性,因此没有添加任何文件,并且cppcheck被传递为空列表!
现在可以修复。可能很少有办法摆脱这个漏洞 - 我可以指出一对。
您可以继续选择始终从顶级CMake文件中调用add_cppcheck
,并避免使用源文件的属性。因此,上面的问题代码块可以更改为更像:
set(CxxExtensions .cpp .CPP .cc .CC .cxx .CXX)
foreach(_source ${_cppcheck_sources})
get_filename_component(Extension "${_source}" EXT)
list(FIND CxxExtensions "${Extension}" IsCxxFile)
if(IsCxxFile GREATER -1)
list(APPEND _files "${_source}")
endif()
endforeach()
你甚至可以通过在函数开头添加类似的东西来强制执行只从顶级CMakeLists.txt调用的函数:
if(NOT "${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
message(FATAL_ERROR "This can only be called from the top-level CMakeLists.txt")
endif()
第二个修复(我个人赞成)是将add_cppcheck
调用留在子目录中,并让函数添加自定义目标而不是命令。这些目标可以成功应用为顶级目标ANALYZE_CODE
的依赖项。例如,将add_custom_command
更改为:
add_custom_target(ANALYZE_${_name}
${CPPCHECK_EXECUTABLE}
${CPPCHECK_QUIET_ARG}
${CPPCHECK_TEMPLATE_ARG}
${_cppcheck_args}
${_files}
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
COMMENT "ANALYZE_${_name}: Running cppcheck on target ${_name}..."
VERBATIM)
add_dependencies(ANALYZE_CODE ANALYZE_${_name})
set_target_properties(ANALYZE_${_name} PROPERTIES FOLDER "Code Analysis")
这会导致构建ANALYZE_CODE
触发构建每个从属ANALYZE_...
目标。
它有很多额外目标“污染”解决方案的缺点,但好处是你可能在add_test
电话中使用这些目标(尽管这可能是太过分了):
# CMake 2.8.0 and newer
add_test(NAME ${_name}_cppcheck_test
COMMAND ${CMAKE_COMMAND}
--build ${CMAKE_BINARY_DIR}
--target ANALYZE_${_name})