ソフトウェアまわりの備忘録

研究室で培ったソフトウェアの知識を貯めておく備忘録。

依存関係の自動解決(第二回)

前回の記事で書いたようにMakefile依存関係の自動解決について書いていきます。

必要最小限なソースファイルだけ再コンパイルすればいい

sample0.cpp、sample1.cpp、sample2.cpp、sample3.cppの4つのソースファイルがあるとします。そしてこれらの依存関係が

  • sample0: sample1 sample2
  • sample1: sample2

であるとします。このときsample1.cppを書き換えたとき、sample2.cppのみ再コンパイルが必要であってsample0およびsample1は再コンパイルの必要はありません。しかしこれらの依存関係を全てMakefile中に記述・反映するのは結構大変です。

コンパイラオプション「-MMD」により依存関係を記述したファイルを作成

詳細はMakeでヘッダファイルの依存関係に対応する - wagavulinの日記に書かれています。こちらにある通り最終的に

$ g++ -O2 -MMD -c sample0.cpp -o sample0.o

とオプションに「-MMD」をつければいい。このオプションは#includeしているヘッダーファイルの依存関係も解決してくれる。コンパイルが無事に終了すると同じ階層にsample0.dという依存関係が記述されたファイルが作成される。

参照ブログと内容が重複するので、簡単に説明するとこのオプションには「-M」「-MM」「-MD」「-MMD」があり、Mはシステムディレクリ(stdio.hなど)にあるヘッダーファイルの依存関係もチェックし(出力結果2参照)、MMはシステムディレクトリを除外してチェックする(出力結果1参照)。またDを使うと依存関係を記述したファイルを作成ししてくれる。システムディレクトリを含む依存ファイルを作る必要はなく、依存関係を記述したファイルの出力もして欲しいことから「-MMD」を使えばいいということになる。

ソースファイル:C++でhallo worldを表示
main.cpp

#include <iostream>
#include "header.h"

int main(void){
  std::cout<<"hallo world\n";
  return 0;
}

出力結果1:-MMDオプション
コンパイルコマンド

$ g++ -O2 -MMD -c main.cpp -o main.o

main.dの中身

main.o: main.cpp header.h

出力結果2:-MDオプション
コンパイルコマンド

$ g++ -O2 -MD -c main.cpp -o main.o

main.dの中身

main.o: main.cpp /usr/include/c++/4.6/iostream \
 /usr/include/c++/4.6/i686-linux-gnu/./bits/c++config.h \
 /usr/include/c++/4.6/i686-linux-gnu/./bits/os_defines.h \
(省略)
 /usr/include/c++/4.6/bits/istream.tcc header.h

作成した依存関係ファイルを使ってmakeする

次回のmake時にはこの依存関係ファイルを利用する。そのためには

-include main.d

として依存関係ファイルを取り込む。これはmakefile中のどこかに書いておけばよい。

MMDコマンドを導入したmakefile

前回の記事で載せたmakefileに追加

GCC    = g++
CFLAGS = -O2 -MMD -Wall -Wextra
SRCS   = main.cpp sample.cpp
TARGET = main
OBJS   = $(SRCS:.cpp=.o)
DEPS   = $(SRCS:.cpp=.d)

.cpp.o:
	$(GCC) $(CFLAGS) -c $< -o $@

$(TARGET): $(OBJS)
	$(GCC) $(CFLAGS) -o $@ $+

default: $(OBJS) $(TARGET)

clean:
	$(RM) $(OBJS) $(TARGET)

-include $(DEPS)

まずコンパイルオプションを表す変数CFLAGSに「-MMD」を追加。その後、依存関係がかかれたファイル*.dをインクルードするために末行に「-include $(DEPS)」を追加。変数DEPSの中身はmain.d sample.dを表すように上部に「DEPS=$(SRCS:.cpp=.d)」を定義する。次回は多段Makefileについて書きます。