はじめに
Makefile を使うなら,コンパイルオプション(ifort -c hoge.f90
)で中間ファイルを作っておくと便利ですが,.f90ファイルが10個を超えたくらいから,hoge.o とか hoge.mod みたいな中間ファイルだらけになって正直うっとうしい.依存関係も調べてファイル出力しておくコンパイルオプション(ifort -fpp -gen-dep=hoge.d hoge.f90
) とかまで付けてると,もう発狂しちゃいそう.
こういう煩わしい状況をどうにか解消できないかとググりにググったら,Cについては,いい感じの解決策 (シンプルで応用の効くmakefileとその解説) が見つかりました.これを参考に,中間ファイルは ./obj
ディレクトリに押し込んでしまおう,というのがやりたいこと.(ちなみに Fortran 用の Makefile の書き方 も参考にしました.)
ディレクトリ構造
基本的なディレクトリ構造はリンク元と同じ.ただし,./lib
ディレクトリというのを付け加えて,そこにはモジュールだけのファイル(メインのProgramを含まないソースコード)を集めてます.
example
|-- makefile
|-- bin <- (EXEDIR)
| `-- example <- (TARGET) 実行ファイル
|-- dat
| `-- 2016/12/17/ <- ここで ../../bin/example1 とかを実行すれば幸せになれる
|-- lib <- (LIBDIR) モジュールファイル用ディレクトリ
| `-- module_a.f90 <- (LIBS)
|-- obj <- (OBJDIR) 中間ファイル生成先ディレクトリ
| |-- module_a.d <- (DEPENDS) 依存関係ファイル
| |-- mod_a.mod <- (MODULES) ヘッダ(?)ファイル
| |-- mod_b.mod
| `-- module_a.o <- (OBJECTS) オブジェクトファイル
`-- src <- (SRCDIR) メインプログラムディレクトリ
|-- example1.f90
`-- example2.f90
Makefile
###############################################################################
# make ... generate executable for the REAL sequential version #
# make clean ... delete unnecessary files #
###############################################################################
include $(wildcard make.d/*)
#
FC = ifort
DEPS = -fpp -gen-dep=$(@:%.o=%.d)
FLIB = -mkl
FOPT = -openmp
FOPT += -ipo
#FOPT += -mcmodel=medium -xHOST -O2 -ipo -no-prec-div
#FOPT += -heap-arrays 10240
#FOPT += -fstack-protector-all
FDBG = -traceback -g -debug extended
#FDBG += -O0 -fno-eliminate-unused-debug-types
#FDBG += -check all
#FDBG += -warn all
#FDBG += -fpe0 -ffpe-trap=invalid,zero,overflow
#FDBG += -opt-report
#FPRP = -Dverbose=1
###############################################################################
SRCDIR = ./src
ifeq "$(strip $(SRCDIR))" ""
SRCDIR = .
endif
OBJDIR = ./obj
ifeq "$(strip $(OBJDIR))" ""
OBJDIR = .
else
FMOD = -module $(OBJDIR)
endif
LIBDIR = ./lib
INCDIR =
ifeq "$(strip $(INCDIR))" ""
else
FLIB += -I $(INCDIR)
FMOD += -module $(INCDIR)
endif
EXEDIR = ./bin
###############################################################################
TARGET = $(notdir $(SOURCES:%.f90=%))
SOURCES = $(wildcard $(SRCDIR)/*.f90)
LIBS = $(wildcard $(LIBDIR)/*.f90)
OBJECTS = $(addprefix $(OBJDIR)/, $(notdir $(LIBS:%.f90=%.o)))
MODULES = $(wildcard $(OBJDIR)/*.mod)
DEPENDS = $(OBJECTS:.o=.d)
-include $(DEPENDS)
.SUFFIXES: .f90
.PHONY : clean all
###############################################################################
$(TARGET): $(OBJECTS)
$(FC) $(FLIB) $(FOPT) $(FMOD) $(FDBG) $(FPRP) -o $(EXEDIR)/$@ $^ \
$(SRCDIR)/$@.f90
$(OBJDIR)/%.o: $(LIBDIR)/%.f90
# -mkdir -p $(OBJDIR)
$(FC) $(FLIB) $(FOPT) $(FMOD) $(FDBG) $(FPRP) $(DEPS) -o $@ -c $<
all: clean $(TARGET)
clean:
-rm -f $(OBJECTS) $(MODULES) $(DEPENDS) $(addprefix $(EXEDIR)/, $(TARGET))
%.mod: %.f90 %.o
@:
雑な解説
だいたい make example1
とか,make example2
すれば済む.適時 make clean
とか.
DEPS = -fpp -gen-dep=$(@:%.o=%.d)
: 最初のオプションで,fortranプリプロセッサ(fortran-pre-processor)を有効化させる.これについては,たとえば fortranデバッグにプリプロセッサー とか参考に.二つ目のオプションで,オブジェクトファイル(中間ファイル)の依存関係を同じファイル名で拡張子だけ .d に変えたファイルに書き出させる.
他のオプションについては解説なくても何とかなると思ってます.
注意点
./lib
の下にあるファイルを,名前順に片っ端からコンパイルしていくので,たとえば,a.f90
が,b.f90
に含まれるモジュールを利用する場合,エラーで死にます.たぶん上手くやれば死なずにやってくれるんだと思いますが,ぼくは基本のモジュールファイル群には,000_hoge.f90
とか,001_hage.f90
とかいう具合に prefix を付けて回避しています.001_*.f90
は 000_*.f90
に依存する,みたいな.(何かもっとうまい解決策をお尻の方は教えてくだしあ)
余談
pmake example
とか打てば,このディレクトリ構造が生成されるシェルも作っておくのも良さげ.(pmake
のpはパッケージのp,的な)