3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Fortran用のMakefileについて

Last updated at Posted at 2024-06-19

はじめに

個別の状態にあまり依存しないMakefileを考えてみた。

構成

sample/
 ├ bin/
 ├ src/
   ├ makefile
   ├ main.f90
   ├ mod_a.f90   
  └ mod_b.f90
main.f90
program main
    use, intrinsic :: iso_fortran_env, only: real64, int32
    use mod_a, only: sub_a
    use mod_b, only: sub_b
    implicit none
    real(real64) :: a
    integer(int32) :: i

    i = 10
    a = 0.1_real64

    print *, i, a
    call sub_a()
    call sub_b()
    
end program main
mod_a.f90
module mod_a
    use, intrinsic :: iso_fortran_env, only: real64
    implicit none
    private
    public :: sub_a
    real(real64), parameter :: pi = 4.0_real64*atan(1.0_real64)
    
contains
    subroutine sub_a()
        print *, 'pi=', pi
    end subroutine sub_a
end module mod_a
mod_b.f90
module mod_b
    use, intrinsic :: iso_fortran_env, only: real64
    implicit none
    private
    public :: sub_b
    real(real64), parameter :: pi = 4.0_real64*atan(1.0_real64)
    
contains
    subroutine sub_b()
        print *, 'pi=', pi
    end subroutine sub_b
end module mod_b

※モジュールが入っているファイルは

  • モジュールを一つとする
  • module名とファイル名を同じにする

という条件にする。

makefile

makefile
# Usage:

# for release
# make
# for debug
# make DEBUG=1

# install and clean
# make install
# make clean-all

FC := gfortran
FFLAGS := -Wall -Wno-maybe-uninitialized
FFLAGS_FOR_RELEASE := -O3
FFLAGS_FOR_DEBUG := -g -O0
LDFLAGS :=

ifeq ($(DEBUG), 1)
    FFLAGS += $(FFLAGS_FOR_DEBUG)
else
    FFLAGS += $(FFLAGS_FOR_RELEASE)
endif

SOURCES := $(wildcard *.f90)
OBJS := $(SOURCES:.f90=.o)
PROGRAMS := main

.PHONY: all install clean clean-all
all: $(PROGRAMS)
	@:

$(PROGRAMS): $(OBJS)
	$(FC) $(FFLAGS) -o $@ $^ $(LDFLAGS)

%.o: %.f90
	$(FC) $(FFLAGS) -c $<

%.mod: %.o
	@:

# 個別設定(modファイルを追加)
main.o: mod_a.mod mod_b.mod

install: all
	install $(PROGRAMS) ../bin

clean:
	rm -f *.o *.mod

clean-all: clean
	rm -f $(PROGRAMS)

解説

変数の代入について

=を使用するとRecursively expanded variable(再帰展開変数)となり使用する時入れ子になっている変数を展開する。
=:を使用するとSimply expanded variables(単純展開変数)となり代入の際にすべて展開されてから入力される。
基本的に上から順に入力していくように作られている場合は単純展開変数を使用する。

release or debug

makeまたはmake DEBUG=1により変数FFLAGSに入る内容が変わる。
make DEBUG=1とすると、makefileの変数DEBUGが上書きされる。

ifeq ($(DEBUG), 1)
    FFLAGS += $(FFLAGS_FOR_DEBUG)
else
    FFLAGS += $(FFLAGS_FOR_RELEASE)
endif

この分岐により入力されるものが変化する。

パターンルール

%.o: %.f90
	$(FC) $(FFLAGS) -c $<

f90ファイルからoファイルを作る時のルールとなる。

※ちなみに同様のルールにサフィックスルールがあるが、互換性のために残している古い書き方で可読性も悪いので使用しない。

.f90.o:
    $(FC) $(FFLAGS) -c $<

一つのターゲットに対して、複数のルールを設定する

# 個別設定(modファイルを追加)
main.o: mod_a.mod mod_b.mod

%.o: %.f90
	$(FC) $(FFLAGS) -c $<

このようにmain.oを作る場合は、この2つを組み合わせてmain.f90,mod_a.mod,mod_b.modを材料に$(FC) $(FFLAGS) -c $<を実行することができる。
基本はパターンルールで個別で必要なものがあればこのように追加する。

%.mod: %.o パターンルールについて

コンパイルする順番を制御するために置いている。
main.oを作るにはmod_a.mod mod_b.modファイルが必要でそれはmod_a.o mod_b.oファイルの作成と同時に作れられる。
main.f90をコンパイルする前にmod_a.f90 mod_b.f90をコンパイルする必要がある。

このルールを加えると、次のような制御になり順番が確保される。

  1. main.omain.f90 mod_a.mod mod_b.modに依存する
  2. mod_a.modmod_a.oに依存する
  3. mod_b.modmod_b.oに依存する
  4. mod_a.omod_a.f90に依存する
  5. mod_b.omod_b.f90に依存する

main.o->main.f90 mod_a.mod mod_b.mod->mod_a.o mod_b.o->mod_a.f90 mod_b.f90の順になる。

もう一つの書き方(makefile)

先ほどは、
モジュールが入っているファイルは

  • モジュールを一つとする
  • module名とファイル名を同じにする

という条件のもとに作成されていたが、そうではないパターンもあるかと思う。それでも耐えうる書き方に変更する。
https://fortran-lang.org/en/learn/building_programs/project_make/に書かれているものを参考にした。

makefile
# Usage:

# for release
# make
# for debug
# make DEBUG=1

# install and clean
# make install
# make clean-all

FC := gfortran
FFLAGS := -Wall -Wno-maybe-uninitialized
FFLAGS_FOR_RELEASE := -O3
FFLAGS_FOR_DEBUG := -g -O0
LDFLAGS :=

ifeq ($(DEBUG), 1)
    FFLAGS += $(FFLAGS_FOR_DEBUG)
else
    FFLAGS += $(FFLAGS_FOR_RELEASE)
endif

SOURCES := $(wildcard *.f90)
OBJS := $(SOURCES:.f90=.o)
PROGRAMS := main

.PHONY: all install clean clean-all
all: $(PROGRAMS)
	@:

$(PROGRAMS): $(OBJS)
	$(FC) $(FFLAGS) -o $@ $^ $(LDFLAGS)

%.o: %.f90
	$(FC) $(FFLAGS) -c $<

# 依存関係をすべて書き出す
mod_a.mod: mod_a.o
mod_b.mod: mod_b.o
main.o: mod_a.mod
main.o: mod_b.mod

install: all
	install $(PROGRAMS) ../bin

clean:
	rm -f *.o *.mod

clean-all: clean
	rm -f $(PROGRAMS)

モジュールを生み出す側はモジュール名.mod: ファイル名(.f90->.o)として記入し
利用する側はファイル名(.f90->.o): モジュール名.modと記入する。
機械的に書けるのでこちらのほうがよさそう。

参考文献

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?