ぼくの薄い本

技術的なメモを残していく薄い本的なものです

シンプルでかっこいいコンパイルログにする小技

はじめに

オープンソースに限らず何かをビルドする時にコンパイルのログが流れると思いますが、その表示の仕方は様々です。 僕としてはコンパイルのコマンドなどは極力出さない方がかっこいいと思っているので、オープンソースでどのように実現しているか見てみました。 たまたま手元にダウンロードしてあった ruby と git を見てみました。 どちらも「コマンド行の先頭に@(アットマーク)を記述することでログに出さない」という機能を使っていますが、その実現方法は異なるようです。

Ruby のケース

ビルドログ

compiling gc.c
compiling hash.c
compiling inits.c
compiling io.c
compiling marshal.c
compiling math.c
compiling node.c
compiling numeric.c
compiling object.c
compiling pack.c
compiling parse.c
compiling process.c
compiling random.c
compiling range.c
compiling rational.c
compiling re.c
compiling regcomp.c

今何をコンパイルしているのか明確で、余計なものがなくて、スッキリしていますね。個人的にはスゴい好きなビルドログです。

実装

make のオプションとして、V=1 を渡してあげると詳細なビルドログになります。どうやって実装されているか見てみましょう。

オプションの解析は、common.mk に書いてありました。

# V=0 quiet, V=1 verbose.  other values don't work.
V = 0
Q1 = $(V:1=)
Q = $(Q1:0=@)

丁寧に説明します。

  • 引数で渡された V が優先されるので、V = 0 は実行されません。(参考)
  • 変数 V の中身で 1 の部分を空文字列に置き換えて、Q1 に代入します。 (参考)
  • V が 1 の場合、Q1 には空文字列が代入されます
  • V が 0 の場合、Q1 には 0 が代入されます
  • 変数 Q1 の中身で 0 の部分を @ に置き換えて、Q に代入します。
  • Q1 が空文字列の場合、Q には空文字列が代入されます
  • Q1 が 0 の場合、Q には @ が代入されます

オプションを渡さずに make を行った場合、変数 Q に @ が代入されています。 そして、Makefile を見てみるとコマンドの先頭に $(Q) が記述されています。このため make コマンドを実行したときに余計なコンパイルログが出ずにスッキリします。デバッグしたい時は V=1 をつけて make を実行するようになっています。

.c.o:
        @$(ECHO) compiling $<
        $(Q) $(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) $(COUTFLAG)$@ -c $<

git のケース

ビルドログ

    CC cache-tree.o
    CC color.o
    CC column.o
    CC combine-diff.o
    CC commit.o
    CC compat/obstack.o
    CC compat/terminal.o
    CC config.o
    CC connect.o
    CC connected.o
    CC convert.o
    CC copy.o

git の場合も同じような情報量ですね。こちらも好きです。

実装

こちらは、変数 V に何か定義されていれば良いようです。V=2 などでも問題ありません。実装を見てみましょう。

ifndef V
        QUIET_CC       = @echo '   ' CC $@;
        QUIET_AR       = @echo '   ' AR $@;
        QUIET_LINK     = @echo '   ' LINK $@;
        QUIET_BUILT_IN = @echo '   ' BUILTIN $@;
        QUIET_GEN      = @echo '   ' GEN $@;
        QUIET_LNCP     = @echo '   ' LN/CP $@;
        QUIET_XGETTEXT = @echo '   ' XGETTEXT $@;
        QUIET_MSGFMT   = @echo '   ' MSGFMT $@;
        QUIET_GCOV     = @echo '   ' GCOV $@;
        QUIET_SP       = @echo '   ' SP $<;
        QUIET_RC       = @echo '   ' RC $@;
        QUIET_SUBDIR0  = +@subdir=
        QUIET_SUBDIR1  = ;$(NO_SUBDIR) echo '   ' SUBDIR $$subdir; \
                         $(MAKE) $(PRINT_DIR) -C $$subdir
        export V
        export QUIET_GEN
        export QUIET_BUILT_IN
endif

CC や AR など各コマンドの前に QUIET_XXX という変数を定義してます。 やはりこちらも先頭に @ をつけています。空白文字列がいくつか入ってますね。$@ にはビルドターゲットが入るので、さきほどのビルドログのような出力されます。末尾にセミコロンがあるところが味噌ですね。

実際、QUITET_CC を使用している箇所を見てみましょう。

$(C_OBJ): %.o: %.c GIT-CFLAGS $(missing_dep_dirs)
        $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<

QUIET_CC の直後から通常通りコマンドを記述していますね。QUIET_CC の末尾にセミコロンがあるから、1行で2つのコマンドを実行できます。

おわりに

ruby と git のビルドログの出力方法についてみてきました。 個人的には ruby の実装方法の方が好みですね。シンプルだし、どんなコマンドにもすぐ適用できますからね。 自分のプロジェクトの Makefile を記述するときにログも気をつけて書いてみよう。