gpt4 book ai didi

visual-studio - cmake:add_custom_command 仅在第一次调用

转载 作者:行者123 更新时间:2023-12-02 00:04:04 24 4
gpt4 key购买 nike

我遇到了自定义目标(使用 add_custom_target 创建)的 add_custom_command 问题。

我的总体想法是将静态代码分析工具合并到 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 ()

稍后在函数中添加了自定义命令:

 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() 命令验证了以下内容:

  • 目标只创建一次
  • add_custom_command 为调用该函数的每个项目运行,并带有适当的参数

但是当我在 visual studio 中实际查看目标时,只添加了第一个包含/函数调用命令。

如果只包含文件而不调用函数,则根本不会添加任何自定义命令。

期望的行为:

我想要一个名为“ANALYZE_CODE”的目标来运行通过调用该函数添加的所有命令。

即如果 3 个项目包含上面的两行,则会创建一次目标 ANALYZE_CODE,但会向其中添加 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 的文档:

Source file properties are visible only to targets added in the same directory (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()

因此,这是在将给定目标的每个源文件添加到要提供给 cppcheck 的文件列表之前检查是否将其指定为 C++ 文件。如果从定义目标的 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 调用留在子目录中,并让函数添加自定义 target 而不是命令。这些目标可以作为顶级目标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})

关于visual-studio - cmake:add_custom_command 仅在第一次调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19528810/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com