2013-08-07 59 views
1

是部分:Cmake可變更新

我有一個運行外部程序並創建項目特定變量的CMake宏。我想讓CMake做的是在每個構建中運行這個腳本,檢查變量是否發生了變化,如果它們有(防止完全重建項目時不重建),重新生成一個CONFIGURE_FILE頭文件...我'米不確定如何做到這一點,雖然。 (添加自定義目標每次都會重新創建頭文件,無法調用宏,與添加自定義命令相同)。

X部分:

所以我寫了下面的腳本拉用在C++項目汞柱版本信息:

macro (ReadProjectRevisionStatus) 
exec_program(hg ${PROJECT_SOURCE_DIR} ARGS paths OUTPUT_VARIABLE ${PROJECT_NAME}_HGPATHS) 
message(STATUS "${PROJECT_NAME}_HGPATHS=${${PROJECT_NAME}_HGPATHS}}") 
if (NOT(${PROJECT_NAME}_HGPATHS STREQUAL "")) 

string(REPLACE "\n" ";" ${PROJECT_NAME}_HGPATHS ${${PROJECT_NAME}_HGPATHS}) 

foreach(HGPATH ${${PROJECT_NAME}_HGPATHS}) 
string(SUBSTRING "${HGPATH}" 0 10 HGPATHSTART) 
if (HGPATHSTART MATCHES "default = ") 
string(LENGTH "${HGPATH}" HGPATHLENGTH) 
math(EXPR HGSUBLEN "${HGPATHLENGTH}-10") 
string(SUBSTRING "${HGPATH}" 10 ${HGSUBLEN} ${PROJECT_NAME}_HGREMOTEDIR) 
endif() 
endforeach() 

endif() 

if (NOT ${PROJECT_NAME}_HGREMOTEDIR) 
message(WARNING "No remote repository set. Will use current direcoty for build number, but this value may be inaccurate.") 
set(${PROJECT_NAME}_HGREMOTEDIR ${PROJECT_SOURCE_DIR}) 
else() 
exec_program(hg ${${PROJECT_NAME}_HGREMOTEDIR} ARGS status RETURN_VALUE HGREMOTESTATUSVALUE OUTPUT_VARIABLE NUL) 
if (NOT HGREMOTESTATUSVALUE EQUAL 0) 
message(WARNING "Cannot connect to remote repository at ${${PROJECT_NAME}_HGREMOTEDIR}. Will use current direcoty for build number, but this value may be inaccurate.") 
set(${PROJECT_NAME}_HGREMOTEDIR ${PROJECT_SOURCE_DIR}) 
endif() 
endif() 

#Identify changeset 
exec_program(hg ${PROJECT_SOURCE_DIR} ARGS "id" "-i" OUTPUT_VARIABLE OUTPUT_VARIABLE ${PROJECT_NAME}_HGHASHCODE) 

if (${PROJECT_NAME}_HGHASHCODE MATCHES ".*\\+") 
MESSAGE(STATUS "Node is dirty. Will generate temporary version number...") 
set (${PROJECT_NAME}_HGDIRTY 1) 
string(LENGTH ${${PROJECT_NAME}_HGHASHCODE} HGHASHLEN) 
MATH(EXPR HGHASHLEN "${HGHASHLEN}-1") 
string(SUBSTRING ${${PROJECT_NAME}_HGHASHCODE} 0 ${HGHASHLEN} ${PROJECT_NAME}_HGHASHCODE) 
endif() 
#check if remote repository contains changeset 
exec_program(hg ${${PROJECT_NAME}_HGREMOTEDIR} 
ARGS "log" "-r" "${${PROJECT_NAME}_HGHASHCODE}" 
RETURN_VALUE HGREMOTEHASCHANGESET 
OUTPUT_VARIABLE NUL) 
if (NOT HGREMOTEHASCHANGESET EQUAL 0) 
message(WARNING "Remote repository ${${PROJECT_NAME}_HGREMOTEDIR} does not have changeset ${${PROJECT_NAME}_HGHASHCODE}. Will use current direcoty for build number, but this value may be inaccurate.") 
set(${PROJECT_NAME}_HGREMOTEDIR ${PROJECT_SOURCE_DIR}) 
endif() 

exec_program(hg ${${PROJECT_NAME}_HGREMOTEDIR} 
ARGS "log" "-r" ${${PROJECT_NAME}_HGHASHCODE} "--template" "{latesttag}" 
OUTPUT_VARIABLE ${PROJECT_NAME}_HGMAJORMINORVERSION) 

MESSAGE(STATUS "${PROJECT_NAME}_HGMAJORMINORVERSION=${${PROJECT_NAME}_HGMAJORMINORVERSION}") 

exec_program(hg ${${PROJECT_NAME}_HGREMOTEDIR} 
ARGS "log" "-r" ${${PROJECT_NAME}_HGHASHCODE} "--template" "{latesttagdistance}" 
OUTPUT_VARIABLE ${PROJECT_NAME}_HGBUILDNUMBER) 

if (${PROJECT_NAME}_HGDIRTY) 
MATH(EXPR ${PROJECT_NAME}_HGBUILDNUMBER "${${PROJECT_NAME}_HGBUILDNUMBER}+1") 
set(${PROJECT_NAME}_HGHASHCODE "${${PROJECT_NAME}_HGHASHCODE}+") 
endif() 

MESSAGE(STATUS "Version=${${PROJECT_NAME}_HGMAJORMINORVERSION}.${${PROJECT_NAME}_HGBUILDNUMBER}.${${PROJECT_NAME}_HGHASHCODE}") 
endmacro() 

而且我現在這樣稱呼它。

ReadProjectRevisionStatus() 
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/main.h.in ${CMAKE_CURRENT_BINARY_DIR}/main.h) 

其中main.h.in是:

#ifndef MAIN_H 
#define MAIN_H 
#include <string> 

const std::string ${PROJECT_NAME}_HGMAJORMINORVERSION = "${${PROJECT_NAME}_HGMAJORMINORVERSION}"; 
const std::string ${PROJECT_NAME}_HGBUILDNUMBER = "${${PROJECT_NAME}_HGBUILDNUMBER}"; 
const std::string ${PROJECT_NAME}_HGHASHCODE = "${${PROJECT_NAME}_HGHASHCODE}"; 

const std::string ${PROJECT_NAME}_HG_SHORT_VERSION = 
    ${PROJECT_NAME}_HGMAJORMINORVERSION+"."+ 
    ${PROJECT_NAME}_HGBUILDNUMBER; 

const std::string ${PROJECT_NAME}_HG_VERSION = 
    ${PROJECT_NAME}_HG_SHORT_VERSION + "." + 
    ${PROJECT_NAME}_HGHASHCODE; 

#endif 

我想什麼做的是運行在每個構建命令這個宏(我可以用ADD_CUSTOM_TARGET然後設置變量,而不是閱讀他們來自項目),但我只想重新生成main.h,如果變量已更改(以防止不必要的重新編譯)。

編輯:工作液

發了HGVersion.CMake

cmake_minimum_required (VERSION 2.8) 

macro (ReadProjectRevisionStatus) 
message(STATUS PROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR}) 

exec_program(hg ${PROJECT_SOURCE_DIR} ARGS paths OUTPUT_VARIABLE ${PROJECT_NAME}_HGPATHS) 
message(STATUS "${PROJECT_NAME}_HGPATHS=${${PROJECT_NAME}_HGPATHS}}") 
if (NOT(${PROJECT_NAME}_HGPATHS STREQUAL "")) 

string(REPLACE "\n" ";" ${PROJECT_NAME}_HGPATHS ${${PROJECT_NAME}_HGPATHS}) 

foreach(HGPATH ${${PROJECT_NAME}_HGPATHS}) 
string(SUBSTRING "${HGPATH}" 0 10 HGPATHSTART) 
if (HGPATHSTART MATCHES "default = ") 
string(LENGTH "${HGPATH}" HGPATHLENGTH) 
math(EXPR HGSUBLEN "${HGPATHLENGTH}-10") 
string(SUBSTRING "${HGPATH}" 10 ${HGSUBLEN} ${PROJECT_NAME}_HGREMOTEDIR) 
endif() 
endforeach() 

endif() 

if (NOT ${PROJECT_NAME}_HGREMOTEDIR) 
message(WARNING "No remote repository set. Will use current direcoty for build number, but this value may be inaccurate.") 
set(${PROJECT_NAME}_HGREMOTEDIR ${PROJECT_SOURCE_DIR}) 
else() 
exec_program(hg ${${PROJECT_NAME}_HGREMOTEDIR} ARGS status RETURN_VALUE HGREMOTESTATUSVALUE OUTPUT_VARIABLE NUL) 
if (NOT HGREMOTESTATUSVALUE EQUAL 0) 
message(WARNING "Cannot connect to remote repository at ${${PROJECT_NAME}_HGREMOTEDIR}. Will use current direcoty for build number, but this value may be inaccurate.") 
set(${PROJECT_NAME}_HGREMOTEDIR ${PROJECT_SOURCE_DIR}) 
endif() 
endif() 

#Identify changeset 
exec_program(hg ${PROJECT_SOURCE_DIR} ARGS "id" "-i" OUTPUT_VARIABLE OUTPUT_VARIABLE ${PROJECT_NAME}_HGHASHCODE) 

if (${PROJECT_NAME}_HGHASHCODE MATCHES ".*\\+") 
MESSAGE(STATUS "Node is dirty. Will generate temporary version number...") 
set (${PROJECT_NAME}_HGDIRTY 1) 
string(LENGTH ${${PROJECT_NAME}_HGHASHCODE} HGHASHLEN) 
MATH(EXPR HGHASHLEN "${HGHASHLEN}-1") 
string(SUBSTRING ${${PROJECT_NAME}_HGHASHCODE} 0 ${HGHASHLEN} ${PROJECT_NAME}_HGHASHCODE) 
endif() 
#check if remote repository contains changeset 
exec_program(hg ${${PROJECT_NAME}_HGREMOTEDIR} 
ARGS "log" "-r" "${${PROJECT_NAME}_HGHASHCODE}" 
RETURN_VALUE HGREMOTEHASCHANGESET 
OUTPUT_VARIABLE NUL) 
if (NOT HGREMOTEHASCHANGESET EQUAL 0) 
message(WARNING "Remote repository ${${PROJECT_NAME}_HGREMOTEDIR} does not have changeset ${${PROJECT_NAME}_HGHASHCODE}. Will use current direcoty for build number, but this value may be inaccurate.") 
set(${PROJECT_NAME}_HGREMOTEDIR ${PROJECT_SOURCE_DIR}) 
endif() 

exec_program(hg ${${PROJECT_NAME}_HGREMOTEDIR} 
ARGS "log" "-r" ${${PROJECT_NAME}_HGHASHCODE} "--template" "{latesttag}" 
OUTPUT_VARIABLE ${PROJECT_NAME}_HGMAJORMINORVERSION) 

MESSAGE(STATUS "${PROJECT_NAME}_HGMAJORMINORVERSION=${${PROJECT_NAME}_HGMAJORMINORVERSION}") 

exec_program(hg ${${PROJECT_NAME}_HGREMOTEDIR} 
ARGS "log" "-r" ${${PROJECT_NAME}_HGHASHCODE} "--template" "{latesttagdistance}" 
OUTPUT_VARIABLE ${PROJECT_NAME}_HGBUILDNUMBER) 

if (${PROJECT_NAME}_HGDIRTY) 
MATH(EXPR ${PROJECT_NAME}_HGBUILDNUMBER "${${PROJECT_NAME}_HGBUILDNUMBER}+1") 
set(${PROJECT_NAME}_HGHASHCODE "${${PROJECT_NAME}_HGHASHCODE}+") 
endif() 

MESSAGE(STATUS "Version=${${PROJECT_NAME}_HGMAJORMINORVERSION}.${${PROJECT_NAME}_HGBUILDNUMBER}.${${PROJECT_NAME}_HGHASHCODE}") 
endmacro() 
message(STATUS "GETTING HG VERSION") 
ReadProjectRevisionStatus() 
CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/main.h.in ${PROJECT_BINARY_DIR}/main.h) 

在主cmake的文件

add_custom_target(
${PROJECT_NAME}_hg_version_target 
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/main.h.in 
COMMAND ${CMAKE_COMMAND} 
ARGS -DPROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR} 
-DPROJECT_NAME=${PROJECT_NAME} 
-DPROJECT_BINARY_DIR=${PROJECT_BINARY_DIR} 
-P "${CMAKE_CURRENT_SOURCE_DIR}/HGVersion.CMake") 

add_dependencies($ {PROJECT_NAME} $ {PROJECT_NAME } _hg_version_target)

工程,但似乎......真正混亂。任何人有更好的東西?

回答

1

如果構建過程中的某些內容決定了要生成的文件的內容,則無法使用configure_file生成該文件,因爲configure_file在配置階段運行,而不是在構建階段運行。這是CMake的設計選擇。

在你的情況下,你真的必須在構建過程中使用add_custom_command和add_custom_target來生成該文件,因爲你已經發現了。

對於您提出的解決方案,可能有機會簡化這一點。在生成C/C++頭文件時,CMake內部解析器應該能夠自動發現通常的源代碼文件依賴於main.h。所以應該提供一個帶有add_custom_command的自定義命令,該命令將聲明爲OUTPUT它將生成的main.h文件。一旦CMake嘗試構建一個C/C++文件所依賴的目標,它應該自動調用該命令。所以你可能不需要自定義目標和手動聲明的依賴關係。

+0

我試過:但是,CMake並不知道它需要檢查**每個**版本的版本:如果有一個main.h它不會重新生成main.h.每次只有add_custom_target(沒有輸出)。 – IdeaHat

+0

對,我沒有想到這一點。然後你做了一切符合CMake的概念。我不認爲有一種非黑客方式來簡化這一點。 – languitar

+0

是的,我要將整個混亂包裹在一個宏中。不過謝謝。 – IdeaHat