2013-10-22 73 views
3

我遇到了自定義目標(使用add_custom_target創建)的add_custom_command問題。cmake:只有第一次調用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) 

我看到的問題是該命令僅添加了包含該文件的項目。我不知道爲什麼和發生了什麼。我覈實了以下使用消息()命令:

  • 目標只創建一次
  • 的add_custom_command運行對每個調用該函數的項目,在適當的參數

但是當我真正在Visual Studio中查看目標,只添加第一個包含/函數調用命令。

如果僅在未調用該函數的情況下才包含該文件,則根本不添加任何自定義命令。

期望的行爲:

我想命名爲「ANALYZE_CODE」一個目標來運行通過調用函數添加的所有命令。

I.e.如果3個項目包含上面的兩行,則會創建一次目標ANALYZE_CODE,但會向其添加3個自定義命令,每個項目一個。

回答

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}) 
+0

我想我可能一直不清楚是什麼其實我是想發生,並且更新了我原來的職位。但我打算只有一個目標,但是在構建目標時會運行多個自定義命令。 – Max

+0

啊 - 好的。我會刪除這個。 – Fraser

+0

@Max我重構了我的答案一點點:-) – Fraser