C/C++ コンパイルの流れ
$ gcc test.c
のように C のソースファイルから実行ファイルを作るとき、ざっくり言うと以下のような流れで処理されています。
- プリプロセッサ処理 (
#ifdef
や#define
マクロの展開) - 1 の結果からアセンブラコードを出力 (狭義のコンパイル)
- 2 の結果からアセンブラが機械語コードを出力 (
*.o
) - 3 の結果を複数集めてリンク
たいていのプログラムは複数のソースコードで構成されるので、3. の出力である *.o
は目にする機会が多いと思いますが、 1-3 は gcc
コマンドが内部的に処理してしまうので、 1 や 2 の結果は気にすることは少ないと思います。
この 1 や 2 の結果をファイルとして出力させるのが -save-temps
オプションです。
-save-temps オプション
Store the usual “temporary” intermediate files permanently; place them in the current directory and name them based on the source file. Thus, compiling foo.c with -c -save-temps produces files foo.i and foo.s, as well as foo.o. This creates a preprocessed foo.i output file even though the compiler now normally uses an integrated preprocessor.
このオプションをつけてコンパイルすると、例えば foo.c
(foo.cc
) というソースファイルに対して
- プリプロセッサ出力:
foo.i
(C の場合) /foo.ii
(C++ の場合) - アセンブリコード:
foo.s
を出力します。
マクロが実際にはどのように展開されているか見たい場合や、最適化の結果どのようなアセンブラコードが吐かれているのかをみたいときなどに役立ちます。
なお、 それぞれ gcc -E
や gcc -S
でも出力できますが、これらは *.o
を作らないので、大きなビルドの中に組み込むのは不便です。 -save-temps
なら、ビルド自体は通常通り行いつつ中間成果物を確認することができます。
-save-temps=obj
単に -save-temps
だと foo.i
/ foo.s
はカレントディレクトリに生成されますが、
-save-temps=obj
とすると foo.o
と同じディレクトリに生成されます。
ビルドシステムへの組み込み
このオプションを簡単に有効にできるよう、プロジェクトのビルドシステムに組み込んでおくとよいでしょう。
(オーバーヘッドはあるはずなので常に有効にしておくようなものではないかなと)
例えば make なら
ifneq ($(SAVETEMPS),)
CFLAGS += -save-temps=obj
endif
としておいて有効にしたいときには
$ make SAVETEMPS=1
とする、みたいな話です。
warning が変わる (ことがある)
-save-temps
を付けるとコンパイル時の warning の出方が変わる場合があります(-save-temps
をつけると warning が増える、またその逆)。
これは、gcc は通常はプリプロセス・コンパイルを一気に行うのに対して、 --save-temps
をつけると2段階で行うようになるためです。これについては別途書こうと思います。