Makefile では、これは次のようなもので行われます。
g++ -DGIT_SHA1="`git log -1 | head -n 1`" ...
バイナリは正確なコミット SHA1 を認識しているため、segfault が発生した場合にそれをダンプできるため、これは非常に便利です。
CMakeで同じことを達成するにはどうすればよいですか?
バージョニングや同様の目的でgitリポジトリをピアリングするCMakeモジュールをいくつか作成しました。これらはすべてhttps://github.com/rpavlik/cmake-modulesのリポジトリにあります。
これらの関数の良いところは、HEADコミットが変更されるたびに、ビルドの前に再構成(cmakeの再実行)を強制することです。execute_processで1回だけ何かを行うのとは異なり、ハッシュ定義を更新するためにre-cmakeを覚えておく必要はありません。
この特定の目的のために、少なくともGetGitRevisionDescription.cmake
とGetGitRevisionDescription.cmake.in
ファイルが必要になります。次に、メインCMakeLists.txt
ファイルに次のようなものがあります
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/whereYouPutMyModules/")
include(GetGitRevisionDescription)
get_git_head_revision(GIT_REFSPEC GIT_SHA1)
次に、それをシステム全体の定義として追加することができます(残念ながら、多くの再構築が発生します)
add_definitions("-DGIT_SHA1=${GIT_SHA1}")
または、私の提案する代替案:生成されたソースファイルを作成します。ソースに次の2つのファイルを作成します。
GitSHA1.cpp.in:
#define GIT_SHA1 "@GIT_SHA1@"
const char g_GIT_SHA1[] = GIT_SHA1;
GitSHA1.h:
extern const char g_GIT_SHA1[];
これをに追加しますCMakeLists.txt
(SOURCESにソースファイルのリストがあると仮定します):
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/GitSHA1.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/GitSHA1.cpp" @ONLY)
list(APPEND SOURCES "${CMAKE_CURRENT_BINARY_DIR}/GitSHA1.cpp" GitSHA1.h)
次に、SHA文字列を含むグローバル変数があります。SHAが変更されてもexternのヘッダーは変更されないため、文字列を参照する場所を含めるだけで、生成されたCPPのみが変更されます。コミットするたびに再コンパイルして、どこからでもSHAにアクセスできるようにします。
CMakeLists.txt で次のようなものを使用します。
execute_process(
COMMAND git describe
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE VERSION )
string( REGEX MATCH "-g.*$" VERSION_SHA1 ${VERSION} )
string( REGEX REPLACE "[-g]" "" VERSION_SHA1 ${VERSION_SHA1} )
add_definitions( -DGIT_SHA1="${VERSION_SHA1}" )
CMakeList.txt
との 2 つのファイルにコードを追加するだけですmain.cpp
。
# git commit hash macro
execute_process(
COMMAND git log -1 --format=%h
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_COMMIT_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
add_definitions("-DGIT_COMMIT_HASH=\"${GIT_COMMIT_HASH}\"")
inline void LogGitCommitHash() {
#ifndef GIT_COMMIT_HASH
#define GIT_COMMIT_HASH "0000000" // 0000000 means uninitialized
#endif
std::cout << "GIT_COMMIT_HASH[" << GIT_COMMIT_HASH << "]"; // 4f34ee8
}
ではCMakeList.txt
、CMake コマンドを使用して、 のような文字列で SHA-1 値の短くて一意の省略形を提供するexecute_process()
コマンドを呼び出します。この文字列は、 という CMake 変数に割り当てられます。CMake コマンドは、マクロをgcc コンパイルの直前の値に定義します。ハッシュ値は、プリプロセッサによって C++ コードのマクロを置き換えるために使用されるため、オブジェクト ファイルとコンパイル済みバイナリに存在します。git log -1 --format=%h
4f34ee8
GIT_COMMIT_HASH
add_definitions()
GIT_COMMIT_HASH
4f34ee8
main.o
a.out
達成する別の方法は、という CMake コマンドconfigure_file()
を使用することですが、CMake が実行される前にファイルが存在しないため、私はそれを使用したくありません。
これが私の解決策です。これはかなり短いですが効果的だと思います;-)
まず、ソース ツリーにファイルが必要です (名前はgit-rev.h.in
)。次のようになります。
#define STR_EXPAND(x) #x
#define STR(x) STR_EXPAND(x)
#define GIT_REV STR(GIT_REV_)
#define GIT_REV_ \
(これらのマクロは気にしないでください。生の値から文字列を作成するのは少し常軌を逸したトリックです。)値を追加できるように、このファイルの末尾に空の改行が 1 つだけあることが不可欠です。
そして今、このコードはそれぞれのCMakeLists.txt
ファイルに入ります:
# --- Git revision ---
add_dependencies(your_awesome_target gitrev) #put name of your target here
include_directories(${CMAKE_CURRENT_BINARY_DIR}) #so that the include file is found
set(gitrev_in git-rev.h.in) #just filenames, feel free to change them...
set(gitrev git-rev.h)
add_custom_target(gitrev
${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/${gitrev}
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/${gitrev_in} ${CMAKE_CURRENT_BINARY_DIR}/${gitrev}
COMMAND git rev-parse HEAD >> ${CMAKE_CURRENT_BINARY_DIR}/${gitrev}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} #very important, otherwise git repo might not be found in shadow build
VERBATIM #portability wanted
)
このコマンドにより、git-rev.h.in
がビルド ツリーにコピーされ、git-rev.h
その最後に git リビジョンが追加されます。
したがって、次に行う必要があるgit-rev.h
のは、ファイルの 1 つにインクルードし、GIT_REV
マクロで必要なことを行うことだけです。これにより、現在の git リビジョン ハッシュが文字列値として生成されます。
このソリューションの優れた点はgit-rev.h
、関連するターゲットをビルドするたびに が再作成されるため、何cmake
度も実行する必要がないことです。
また、かなり移植性が高いはずです-移植性のない外部ツールは使用されておらず、血まみれの愚かなWindowsコマンドでさえ>
and>>
演算子をサポートしています;-)
CMake にこの置換を行う機能が組み込まれていない場合は、テンプレート ファイルを読み取り、上記のように SHA1 ハッシュを正しい場所に置き換え (sed
たとえば、を使用)、実際のCMake ビルド ファイルを作成し、CMake を呼び出してプロジェクトをビルドします。
少し異なるアプローチは、SHA1 置換をオプションにすることです。などのダミーのハッシュ値を使用して CMake ファイルを作成します"NO_OFFICIAL_SHA1_HASH"
。開発者が作業ディレクトリから独自のビルドをビルドすると、ビルドされたコードには SHA1 ハッシュ値が含まれません (ダミー値のみ)。これは、作業ディレクトリのコードには対応する SHA1 ハッシュ値がまだないためです。
一方、公式のビルドがビルド サーバーによって中央リポジトリから取得されたソースから作成された場合、ソース コードの SHA1 ハッシュ値がわかります。その時点で、CMake ファイルのハッシュ値を置き換えてから、CMake を実行できます。
CMake を使用して git SHA-1 を C または C++ プロジェクトに取り込むための、手早く汚い、おそらく移植性のない方法として、CMakeLists.txt でこれを使用します。
add_custom_target(git_revision.h
git log -1 "--format=format:#define GIT_REVISION \"%H\"%n" HEAD > git_revision.h
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} VERBATIM)
CMAKE_SOURCE_DIR
が git リポジトリの一部であり、システムで git が利用可能であり、出力リダイレクトがシェルによって適切に解析されることを前提としています。
次に、このターゲットを他のターゲットの依存関係にすることができます
add_dependencies(your_program git_revision.h)
ビルドされるたびyour_program
に、Makefile (または、他のビルド システムで機能する場合は他のビルド システム) は、ソース ディレクトリに git_revision.h を内容とともに再作成します。
#define GIT_REVISION "<SHA-1 of the current git revision>"
したがって#include git_revision.h
、ソースコードファイルからそのように使用できます。ヘッダーは文字通りすべてのビルドで作成されることに注意してください。つまり、他のすべてのオブジェクト ファイルが最新であっても、このコマンドを実行して git_revision.h を再作成します。通常、同じ git リビジョンを何度も再構築することはないため、これは大きな問題にはならないと思いますが、これは注意が必要です。それが問題である場合は、これを使用しないでください。(おそらく を使用して回避策をハックすることは可能ですが、今のadd_custom_command
ところ必要ありません。)