GitバージョンハッシュにアクセスできるCコードを書く簡単な方法はありますか?
実験室で科学データを収集するために、Cでソフトウェアを作成しました。私のコードは、後で分析するために収集したデータを.yamlファイルに記録します。私の実験は日々変化し、コードを修正しなければならないことがよくあります。リビジョンを追跡するために、gitリポジトリを使用します。
.yamlデータファイルにGitリビジョンハッシュをコメントとして含めることができます。そうすれば、.yamlファイルを見て、そのファイルに表示されるデータを生成するためにどのコードが使用されたかを正確に知ることができます。これを自動的に行う簡単な方法はありますか?
私のプログラムでは、次のようなversion.c
と呼ばれる別のファイルにgitバージョン番号とビルドの日付を保持しています。
#include "version.h"
const char * build_date = "2009-11-10 11:09";
const char * build_git_sha = "6b54ea36e92d4907aba8b3fade7f2d58a921b6cd";
次のようなヘッダーファイルもあります。
#ifndef VERSION_H
#define VERSION_H
extern const char * build_date; /* 2009-11-10 11:09 */
extern const char * build_git_sha; /* 6b54ea36e92d4907aba8b3fade7f2d58a921b6cd */
#endif /* VERSION_H */
ヘッダーファイルとCファイルの両方は、次のようなPerlスクリプトによって生成されます。
my $git_sha = `git rev-parse HEAD`;
$git_sha =~ s/\s+//g;
# This contains all the build variables.
my %build;
$build{date} = make_date_time ();
$build{git_sha} = $git_sha;
hash_to_c_file ("version.c", \%build, "build_");
ここで、hash_to_c_file
はversion.c
とversion.h
を作成するすべての作業を行い、make_date_time
は示されているように文字列を作成します。
メインプログラムには、ルーチンがあります
#include "version.h"
// The name of this program.
const char * program_name = "magikruiser";
// The version of this program.
const char * version = "0.010";
/* Print an ID stamp for the program. */
static void _program_id_stamp (FILE * output)
{
fprintf (output, "%s / %s / %s / %s\n",
program_name, version,
build_date, build_git_sha);
}
私はgitについてそれほど詳しくないので、もっと良い方法があればコメントを歓迎します。
Makeベースのビルドを使用している場合、これをMakefileに入れることができます。
GIT_VERSION := "$(Shell git describe --abbrev=4 --dirty --always --tags)"
(スイッチの機能については man git describe を参照)
次に、これをCFLAGSに追加します。
-DVERSION=\"$(GIT_VERSION)\"
次に、#defineのようにプログラムで直接バージョンを参照できます。
printf("Version: %s\n", VERSION);
デフォルトでは、これは単にgit commit idを出力しますが、オプションで特定のリリースに次のようなタグを付けることができます:
git tag -a v1.1 -m "Release v1.1"
次に印刷されます:
Version: v1.1-2-g766d
つまり、v1.1を超えて2回コミットし、GitコミットIDが「766d」で始まります。
ツリーにコミットされていない変更がある場合、「-dirty」が追加されます。
依存関係のスキャンは行われないため、バージョンを強制的に更新するには、明示的なmake clean
を実行する必要があります。これ 解決可能 ただし。
利点は、シンプルであり、Perlやawkのような追加のビルド依存関係を必要としないことです。私はこのアプローチをGNU automakeおよびAndroid NDKビルドで使用しました。
@Kinopikoの答えに非常に似たものを使用することになりましたが、Perlではなくawkを使用しました。これは、mingwの性質によりawkがインストールされているがPerlではないWindowsマシンにこだわっている場合に便利です。仕組みは次のとおりです。
私のメイクファイルには、git、date、awkを呼び出してcファイルを作成する行が含まれています。
$(MyLibs)/version.c: FORCE
$(GIT) rev-parse HEAD | awk ' BEGIN {print "#include \"version.h\""} {print "const char * build_git_sha = \"" $$0"\";"} END {}' > $(MyLibs)/version.c
date | awk 'BEGIN {} {print "const char * build_git_time = \""$$0"\";"} END {} ' >> $(MyLibs)/version.c
コードをコンパイルするたびに、awkコマンドは次のようなversion.cファイルを生成します。
/* version.c */
#include "version.h"
const char * build_git_sha = "ac5bffc90f0034df9e091a7b3aa12d150df26a0e";
const char * build_git_time = "Thu Dec 3 18:03:58 EST 2009";
次のような静的version.hファイルがあります。
/*version.h*/
#ifndef VERSION_H_
#define VERSION_H_
extern const char * build_git_time;
extern const char * build_git_sha;
#endif /* VERSION_H_ */
残りのコードは、version.hヘッダーを含めるだけでビルド時間とgitハッシュにアクセスできるようになりました。最後に、.gitignoreファイルに行を追加して、version.cを無視するようにgitに指示します。このように、gitは常にマージの競合を与えません。お役に立てれば!
あなたのプログラムはgit describe
、実行時またはビルドプロセスの一部として。
できることは2つあります。
Gitを作成して、ファイルにバージョン情報を埋め込むことができます。
より簡単な方法は、ident
attribute を使用することです。これは、(たとえば)
*.yaml ident
.gitattributes
ファイルに、$Id$
に適切な場所に。ファイルの内容のSHA-1識別子に自動的に展開されます(blob id) :これはファイルバージョンでも、最後のコミットでもありません。
Gitはこの方法で$ Id $キーワードをサポートし、ブランチの切り替え、ブランチの巻き戻しなどの間に変更されなかったファイルに触れないようにします。Gitでファイルにコミット(バージョン)識別子または説明を入れたい場合、(ab)use filter
属性。clean/ smudgeフィルターを使用して、チェックアウト時にキーワード(たとえば、$ Revision $)を展開し、コミットのためにクリーンアップします。
LinuxカーネルやGit自体が行うように、build processを作成することができます。
GIT-VERSION-GEN スクリプトとGitでの使用 Makefile をご覧ください。または、たとえば、このMakefileがgitweb/gitweb.cgi
の生成/構成中にバージョン情報を埋め込む方法をご覧ください。ファイル。
GIT-VERSION-GENはgit describeを使用してバージョンの説明を生成します。プロジェクトのリリース/マイルストーンに(署名付き/注釈付きタグを使用して)タグを付けることが、より適切に機能する必要があります。
これを行う必要があるときは、RELEASE_1_23
のような tag を使用します。 SHA-1を知らなくても、タグが何であるかを判断できます。コミットしてからタグ付けします。とにかく、そのタグをプログラムに保存できます。
Njd27による答えに基づいて、コードが異なる方法で構築されたときのデフォルト値を持つversion.hファイルと組み合わせて、依存関係スキャン付きのバージョンを使用しています。 version.hを含むすべてのファイルが再構築されます。
また、個別の定義として改訂日も含まれます。
# Get git commit version and date
GIT_VERSION := $(Shell git --no-pager describe --tags --always --dirty)
GIT_DATE := $(firstword $(Shell git --no-pager show --date=short --format="%ad" --name-only))
# recompile version.h dependants when GIT_VERSION changes, uses temporary file version~
.PHONY: force
version~: force
@echo '$(GIT_VERSION) $(GIT_DATE)' | cmp -s - $@ || echo '$(GIT_VERSION) $(GIT_DATE)' > $@
version.h: version~
@touch $@
@echo Git version $(GIT_VERSION) $(GIT_DATE)
また、科学コードの変更を追跡するためにgitを使用しています。コードの移植性を制限するため、外部プログラムを使用したくありませんでした(誰かがMSVSで変更を加えたい場合など)。
私の解決策は、計算にメインブランチのみを使用し、プリプロセッサマクロを使用してビルド時間を出力することでした__DATE__
および__TIME__
。そうすれば、gitログで確認して、使用しているバージョンを確認できます。参照: http://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html
問題を解決する別のエレガントな方法は、gitログを実行可能ファイルに含めることです。 gitログからオブジェクトファイルを作成し、コードに含めます。今回は、使用する外部プログラムはobjcopyのみですが、コーディングは少なくなります。参照: http://www.linuxjournal.com/content/embedding-file-executable-aka-hello-world-version-5967 および C++プログラムにデータを埋め込む
必要なことは、次のようなヘッダーファイルを生成することです(たとえば、cmd行からのエコーを使用)。
#define GIT_HASH \
"098709a0b098c098d0e"
生成するには、次のようなものを使用します。
echo #define GIT_HASH \ > file.h
echo " > file.h
echo git status <whatever cmd to get the hash> > file.h
echo " > file.h
引用符とバックスラッシュを少し使用してコンパイルする必要があるかもしれませんが、アイデアは得られます。
Makefileとシェルに基づくさらに別のバリエーション
GIT_COMMIT_FILE=git_commit_filename.h
$(GIT_COMMIT_FILE): phony
$(eval GIT_COMMIT_SHA=$(Shell git describe --abbrev=6 --always 2>/dev/null || echo 'Error'))
@echo SHA=$(GIT_COMMIT_SHA)
echo -n "static const char *GIT_COMMIT_SHA = \"$(GIT_COMMIT_SHA)\";" > $(GIT_COMMIT_FILE)
ファイルgit_commit_filename.hは、静的const char * GIT_COMMIT_SHA = "";を含む1行で終わります。
から https://Gist.github.com/larytet/898ec8814dd6b3ceee65532a9916d406
元のコミット でmemcachedに対してどのように行ったかを確認できます。
基本的に、ときどきタグを付け、配信するものがmake dist
または類似。