S/Wだとそんなことはまずないが、H/Wだと今動いているコードが何か知りたいので、コードの一部にgitのコミット番号を埋め込みたい、みたいなことが起こる (らしい。) その時に引っかかったことがあるので残しておく。結論から言うとTARGETを使うadd_custom_commandを使うのが一番いい気がする。なおCMakeに関してはほとんどわかっていないのでご容赦を...
gitのコミットハッシュを取得する
gitのコミットハッシュ自体は下で取得できる(長いやつ)
$ git log --pretty=format:%H -1
# 又は
$ git rev-parse HEAD
短いやつ
$ git log --pretty=format:%h -1
# 又は
$ git rev-parse --short HEAD
CMakeの処理3段階
- Configure ファイルの依存関係をさらう
- Generate さらった依存関係を元にビルド用ファイルを作成
- Build ビルドを実行
の主に3段階ある。よく
-- Configuring done
-- Generating done
-- Build files have been written to: /hogehoge
みたいな表示を見る。
CMakeでコマンド実行
CMakeでコマンドを実行する方法は主に2通りある。 execute_process と add_custom_commandの2つ。2つと書いたが、add_custom_commandには使い方が2通りあって、頭にOUTPUTを持ってくるかTARGETを持ってくるかで処理が全く違う。OUTPUTを持ってきた場合はビルド用のファイル生成でTARGETを使うのはビルド時にコマンド実行(ビルドイベント)をする用途になる。
cf. add_custom_command - CMake
このうち、上のビルド時に実行されるのはadd_custom_commandのTARGETのみ。他は configure or generate で実行される。
Gitハッシュ埋め込み
execute_processとadd_custom_commandの使い方についてはCMakeの公式リファレンスにしっかり載ってるのでそちらに譲る。
cf. execute_process - CMake
1つ目の方法としてexecute_processでハッシュ値を取得、configure_fileで埋め込み、という手がある。WORKING_DIRECTORYはgit ~を実行するディレクトリを指定するので、git submodule内部のハッシュ値が欲しい場合はそのディレクトリを指定してあげればいい。
execute_process(COMMAND git rev-parse --short HEAD
OUTPUT_VARIABLE git_rev
OUTPUT_STRIP_TRAILING_WHITESPACE
WORKING_DIRECTORY ${WORKING_DIRECTORY})
configure_file ("hogehoge.tmp" "hogehoge.h")
hogehoge.tmpの中に@git_rev@みたいな文字列を用意しておけば、そこが勝手にgitのハッシュに置き換わってhogehoge.hを出力してくれる。
別の方法としてadd_custom_commandでOUTPUTを使う場合。こちらは公式リファレンスにもあるが役目がGenerating Filesなのでビルド前にファイル生成を行うのが主目的。そのファイルがCMakeLists.txtでビルドに使用されるとわかっている時、適当に文字列をハッシュに書きかえる.batなり.shなりを用意してあげればconfigure & generate中にそのコマンドが実行されてくれる。
add_custom_command(OUTPUT hogehoge.h
COMMAND hogehoge.bat
WORKING_DIRECTORY ${WORKING_DIRECTORY})
ただ上の2つの問題点は上でも書いたようにビルド直前では実行されないことだ。一度フォルダを開いてconfigure & generateが済まされた場合、hogehoge.hに何らかの変更が加えられてもその変更を超えてgitのハッシュの反映をなされない。そういう場合でも変わらず埋め込みたい場合はadd_custom_commandのTARGETを使用する。こちらの役割はBuild Eventsである。
add_custom_command(TARGET ${PROJECT_NAME}
PRE_BUILD
COMMAND hogehoge.bat
WORKING_DIRECTORY ${WORKING_DIRECTORY})
これはビルドが実行される場合、つまりプログラムが走る場合常に直前に実行されるので他の改変の影響を受けない。のでそうして欲しい場合はadd_custom_commandのTARGETを使用しよう。ここではビルド直前に反映されて欲しいのでPRE_BUILDとしているが、PRE_LINK, POST_BUILDなどで実行するタイミングを指定できる。