速習 makefileの作り方
Linuxにはmakeという便利な機能があります。
通常ですとプログラムをコンパイルする時は、コンパイルする度にコマンドラインにコンパイラ名とソースファイル名とコンパイルオプションと・・・と大変めんどうなのです。
さらに、ある一つのソースファイルを書き換えたとき、すべてをもう一回プログラムをすべてコンパイルし直すのは面倒です。
これを"make"のコマンド一発でやってのけてくれます。
makeを使えば、コマンドラインに面倒くさいオプションを書く必要もなし、更新されたファイルだけを選択的に選んでコンパイルしてくれるので、書き直した時のコンパイル時間の短縮にもなります。
このmakefileの作り方は全く難しいものではなく、一度作ってしまえばあとは使い回すことができます。
今回はFortran90のプログラムの場合を考えますが、C言語にも簡単に応用することができます。
復習 ソースコードから実行プログラムになるまで
この項はプログラミングをある程度慣れ親しんでいる方には常識だと思いますので読み飛ばしてください。
プログラムを書いたコードは、機械語に翻訳しないとコンピュータは理解できません。
Fortran90で書いたコードを機械が読めるように翻訳してやる、これがコンパイルです。
コンパイルをするとオブジェクトファイル(拡張子.o)が完成します。
ところで、ソースコードの書かれたファイルは、普通は一つではありません。
先人の作った便利なプログラム群であるライブラリを読み込む必要も出てきます。
すなわち、それぞれのファイルをコンパイルした後、一つにまとめて実行プログラムにする必要があり、これがリンクです。
実行プログラムは、Windowsですと拡張子として.exeがついたりしますが、特に明示する必要はありません。
すなわち、あなたの書いたソースコードは
コンパイル->リンク
の過程を経て、実行プログラムとなります。
以上の過程をまとめてビルドと呼んだりします。
準備
ソースファイルが
main.f90
interface.f90
globals.f90
sub1.f90
sub2.f90
というファイルに分けて書かれているとします。
interface.f90にはインターフェイスモジュールinteface_modが、globals.f90にはグローバル変数モジュールglobalsが書かれているとしましょう。
また、プログラムにはライブラリとしてLAPACK(あるいはIntel MKL)とOpenMPが使われているとします
実行ファイル名は
sample
というにしようと思います。
makefileの準備
ソースコードのあるフォルダに makefile という名前のファイルを作ります。
Linuxのディストリビューションによってはファイル名を make とか Makefile とかにしないといけないものもあるみたいです。
makefileをgeditでもEmacsでもなんでもいいから開いて、次の様に入力します。
TARGET = sample OBJECTS = globals.o interface.o main.o \ sub1.o sub2.o MOD_FILES = globals.mod interface_mod.mod #FC = gfortran FC = ifort FFLAGS = LDFLAGS = # for gfortran ifeq (${FC},gfortran) FFLAGS += -fimplicit-none -fbounds-check LDFLAGS += -fopenmp -llapack -lblas endif # for ifort ifeq (${FC},ifort) MKLROOT = /opt/intel/composer_xe_2011_sp1.7.256/mkl FFLAGS += -I${MKLROOT}/include/ia32 -I${MKLROOT}/include LDFLAGS += -L${MKLROOT}/lib/ia32 ${MKLROOT}/lib/ia32/libmkl_blas95.a LDFLAGS += ${MKLROOT}/lib/ia32/libmkl_lapack95.a LDFLAGS += -lmkl_intel -lmkl_intel_thread -lmkl_core -openmp -lpthread -lm endif .SUFFIXES : .o .f90 .f90.o: ${FC} -c $< ${TARGET} : ${OBJECTS} ${FC} -o $@ ${OBJECTS} ${LDFLAGS} ${FFLAGS} .PHONY: clean clean: ${RM} ${TARGET} ${OBJECTS} ${MOD_FILES}
文頭に空白がある場合は、スペースキーで空白を作るのではなく、Tabキーで作ることに注意してください。
端末を開いてmakefileのあるフォルダに移動し
$ make
で、プログラムがビルドされます。
また
$ ./sample
でプログラムが実行されます。
ソースコード以外のプログラムのコンパイルの途中に生成されるファイルたちをすべて消したいときは
$ make clean
で削除できます。
makefileの解説
順番に解説していきましょう。
TARGET = sample OBJECTS = globals.o interface.o main.o \ sub1.o sub2.o MOD_FILES = globals.mod interface_mod.mod #FC = gfortran FC = ifort FFLAGS = LDFLAGS =
例えば、一番上の TARGET = sample というのは、 TARGET という変数に'sample'という文字列を入れろという意味です。
呼び出す場合は ${TARGET} か $(TARGET) と書きます。
文末にある\マークは改行を意味し、一つの文が長くなりすぎる場合に使います。
また、#はコメント文を表し、その行で#よりも後ろにある文は無視されます。
FCにはコンパイラの種類を入れています。
# for gfortran ifeq (${FC},gfortran) FFLAGS += -fimplicit-none -fbounds-check LDFLAGS += -fopenmp -llapack -lblas endif
gfortranを使う場合です。
FFLAGSにはコンパイル時のオプションやインクルードファイルのパス設定が入ります。
LDFLAGSにはリンク時のオプションやライブラリのパス設定が入ります。
-fimplicit-noneは、ソースコードに出てくる関数にすべてimplicit noneを指定するオプションです。
implicit noneのつけ忘れに効果的です。
また、-fbounds-checkはデバッグ用のオプションで、配列の領域外を参照してないかチェックします。
例えば dimension a(3) で配列aを定義したのに a(4) を使ってないかをチェックします。
デバッグ用のオプションをつけると実行速度がやや落ちるので、実際の計算の際はこのオプションを落としましょう。
デバッグ用のオプションについては以下のページが参考になります。
http://www.rcs.arch.t.u-tokyo.ac.jp/kusuhara/fswiki/wiki.cgi?page=Fortran%A5%C7%A5%D0%A5%C3%A5%B0%CD%D1%A5%AA%A5%D7%A5%B7%A5%E7%A5%F3
# for ifort ifeq (${FC},ifort) MKLROOT = /opt/intel/composer_xe_2011_sp1.7.256/mkl FFLAGS += -I${MKLROOT}/include/ia32 -I${MKLROOT}/include FFLAGS += -lmkl_intel -lmkl_intel_thread -lmkl_core -openmp -lpthread -lm LDFRAGS += -L${MKLROOT}/lib/ia32 ${MKLROOT}/lib/ia32/libmkl_blas95.a LDFLAGS += ${MKLROOT}/lib/ia32/libmkl_lapack95.a LDFLAGS += -lmkl_intel -lmkl_intel_thread -lmkl_core -openmp -lpthread -lm endif
今度はIntel Fortran Compilerを使う場合です。
MKL(Math Kernel Library)の場所は人によって違うので確認しておきましょう。
MKLを使う場合のコンパイルオプションの付け方は、以下のページで質問に答えていけば教えてくれます。
Intel® Math Kernel Library Link Line Advisor | Intel® Software
.SUFFIXES : .o .f90 .f90.o: ${FC} -c $<
一行目でサフィックスルール摘要対象の拡張子を指定します。
サフィックスとは拡張子のことです。
'.SUFFIXES : .o .f90' は、.oを作るときは必ず.f90から作られるよ、という意味です。
三行目がmakeがコマンドラインに代わりに入れてくれる行です。
$<は、前回に.oファイルを作ってから、現在にソースコードが更新されている.f90の拡張子のファイルだけを選択的に選んで挿入してくれる記号です。
${TARGET} : ${OBJECTS} ${FC} -o $@ ${OBJECTS} ${LDFLAGS} ${FFLAGS}
今度は一行目が${OBJECTS}から${TARGET}を作るよ、という意味です。
$@はターゲットファイル名(:の左側のファイル名)が入ります。
最後に、プログラムをビルドする時にできたファイルたちを一掃するマクロを書いておきます。
.PHONY: clean clean: ${RM} ${TARGET} ${OBJECTS} ${MOD_FILES}
こうすると
$ make clean
と入力することで、${TARGET} ${OBJECTS} ${MOD_FILES}のファイルが消えます。
${RM}は定義済みのマクロで、'rm -f'を表します。
Linuxのディストリビューションによっては${RM}が使えない場合もありますので、このときは rm -f に置き換えてください。