はじめに
Fortran 90 がこの世に出てからずいぶん経つけど、make のデフォルトルールはモダンな Fortran に対応してないよね。だったら自分で書くしかないんだけど、みたところあまり情報が出回ってないみたい。
いつもながら今さら感があるのだけれどちょっと整理してみようか。
Fortran のモジュール
Fortran に触れたことない人向けに簡単に説明しておくと、Fortran 90 以降のモダンな Fortran (FORTRAN 77 などと区別するために1文字目のみ大文字で書く) では「モジュール」っていうものが導入された。
モジュールの詳しい説明は省くけど、分割コンパイルと関連させて使うことが多くて、例えば submod というモジュールを submod.f90 で定義して別のファイル main.f90 のルーチンから submod に定義されたサブルーチンや変数を参照したりする。
そして submod.f90 をコンパイルするとオブジェクトファイル submod.o と、モジュール中間ファイル submod.mod ていうのができるんだ。submod.mod っていうのは乱暴に言うと C でいうヘッダファイルみたいな役割をするもんだと思ってほしい。
で、main.f90 をコンパイルするときには submod.mod が必要になるっていうわけだ。ルーチンとかの実体がある submod.o はなくてもコンパイルできる (もちろん実行ファイルを作るときには必要)。
submod.f90 が修正されてもそのインターフェースに変更がなければ submod.mod は変わらない。だからそれを参照する main.f90 も再コンパイルの必要がないってわけだ。FORTRAN 77 の時代とは打って変わって Fortran もモダンになったね。
Makefile に対する要件
make のデフォルトルールに Fortran 90 用の定義を追加して、プロジェクトの固有の記述量は減らしたいところ。
先の例でいうと submod.o とsubmod.mod は submod.f90 から作られる。だからそういうルールを書けばいい…って言いたいところだけどそうは問屋が卸さない。
submod.mod: submod.f90
gfortran -c $<
依存関係的にはそうなんだけど、submod.mod は submod.f90 を再コンパイルしても更新されるとは限らない。内容に変更なければ更新されないんだ。上のように単純に submod.mod を submod.f90 に依存させると submod.mod が更新されずに submod.f90 より古いファイルの状態になって、make を実行するたびにコンパイルが実行されてしまう場合が発生する。
そこでちょっと工夫が必要になる。
submod.o: submod.f90
gfortran -c $<
submod.mod: submod.f90 submod.o
@:
submod.f90 から submod.o を作成するルールは通常のものだから説明は不要だろう。
ここで重要なのは submod.mod と submod.o のルール。: は何もしないコマンド。末尾に挙げた参考リンクだと true を使ってたりするけれどここでは Windows でも使える : にした。
この submod.mod のルールでは submod.mod が生成されないのだけれど、もう一つの submod.o を作成するときに submod.mod が生成される。じゃあ submod.mod のルールは要らないんじゃないかと思うかもしれないけれどそうではない。
下の例を見てほしい。
main.o: main.f90 submod.mod
gfortran -c $<
main.o は main.f90 と submod.mod に依存するのでこのような記述になる。
ここで submod.mod のルールがないと submod.mod が見つからなくて make が終了してしまう。先のルールにより submod.o が参照され、submod.f90 のコンパイルが実行される (そして submod.mod も生成される)。
デフォルトルール
Makefile はできるだけデフォルトルールを有効活用するようにしたほうが記述量も減り管理のミスもなくなる。デフォルトルールが存在しない場合は可能であればデフォルトルールを追加する形で設定するとよい。
gmake のデフォルトルールは -p オプションで確認できる。FORTRAN 77 用のデフォルトルールが存在するのでそれを参考に定義するのがよいだろう。
先の .mod のルールも反映させると下のようになる。
FC = gfortran
.SUFFIXES: .f90
%.o: %.f90
$(COMPILE.f) $(OUTPUT_OPTION) $<
%.mod: %.f90 %.o
@:
こうしておくとプロジェクト固有の定義は下のように書ける。
TARGET = sample
OBJS = main.o submod.o
$(TARGET): $(OBJS)
$(LINK.f) $^ $(LOADLIBES) $(LDLIBS) -o $@
main.o: submod.mod
main.o と submod.mod の依存関係がシンプルに記述できてるのがわかるだろうか。
まとめ
まとめると下のようになる。もちろんデフォルトルールを別ファイルにしてインクルードしてもよい。
FC = gfortran
TARGET = sample
OBJS = main.o submod.o
.SUFFIXES: .f90
%.o: %.f90
$(COMPILE.f) $(OUTPUT_OPTION) $<
%.mod: %.f90 %.o
@:
$(TARGET): $(OBJS)
$(LINK.f) $^ $(LOADLIBES) $(LDLIBS) -o $@
main.o: submod.mod
おわりに
Makefile で Fortran の .mod ファイルを扱うこの手法は自分の発案ではないのだけれど、ネットにまとまった情報が少なかったり記述にミスがあったりしてるので混乱するよねーって思った。
単に需要がないだけかもしれないけど Fortran でプログラムを組む際の助けになればいいんじゃないかな?
参考
http://d.hatena.ne.jp/pyridoxin/20110726/1311691190
http://lagrange.mechse.illinois.edu/f90_mod_deps/