簡體   English   中英

cmake:add_custom_command 僅第一次調用

[英]cmake: add_custom_command only invoked first time

對於自定義目標(使用 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的文檔:

源文件屬性僅對添加到同一目錄 (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})

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM