付録 2: make と Makefile

  1. DCPAM5 を走らせよう
  2. 発展編: 更にDCPAMを使うには
  3. 付録1: gpview の使い方
  4. 付録2: make と Makefile
  5. 付録3: ターミナルプレクサ
  6. 付録4: DCPAM に必要な資源をインストールする方法
  7. 付録5: DCPAM をビルドしているとき裏で行われていること

[A2.1] make と Makefile

make はプログラムのコンパイル・リンク・インストール作業を自動化してくれるコマンドです. 事前に make の動作手順を記述した Makefile というファイルを用意しておけば, ユーザは以下のようなコマンドを入力するだけで必要な作業を終えることができます.

$ make 
$ make install (引数に何を与えるかは Makefile の記述によります)

make は Makefile の記述を参照し, プログラムを構成するどのファイルが再コンパイルを必要としているかを決定します. 一部のファイルに修正が必要となった場合, make を使えば全てのファイルを再コンパイルする手間を省くことができます. このような特徴から make はプログラムの開発を支援するツールとしても利用されます.

[A2.2] make の種類

make にはいろいろな種類があります. 一番原始的な System V make をはじめ, nmake, BSD make, Sun OS make, SGI make, GNU make などです. 自分の使っているシステムにおける make の種類が知りたい場合, 次のようなコマンドを使います.

$ make -v

情報実験機には GNU Make がインストールされています. 実際に以下のコマンドを入力し, その出力を確認してみましょう.

$ make -v
GNU Make 4.1
Built for x86_64-pc-linux-gnu
Copyright (C) 1988-2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later < http://gnu.org/licenses/gpl.html >
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

[A2.3] 簡単な例

以下では実際に簡単な Fortran90 プログラムを作成し, それを make を用いてコンパイルしてみましょう. まずエディタを用いて以下のようなプログラム (example.f90) を作成します.

program example
  print *, "Hello INEX"
end program example

次に make の動作手順を記述する Makefile を作成します. Makefile は以下のような構造を持ちます.

ターゲット: コンポーネント
           コマンド
           コマンド
           ...

2 行目以降の行頭の空白はタブです. ターゲット部分には作成される実行ファイル名, コマンド部分には実際に実行される命令を記述します (コンポーネントについては後述します). 今回作成する Makefile の場合には以下のようになります.

a.out:
        gfortran example.f90 

作成した example.f90, Makefile を同じディレクトリ内に置いて, そのディレクトリにおいて make を実行してみてください. make は引数を指定しない場合は Makefile 内の一番先頭のターゲットを作成するコマンドを実行するので, 以下のような出力が表示され実行ファイル a.out が作成されます.

$  make 
gfortran -o example example.f90 
$ ls
Makefile  example  example.f90

a.out が作成されたら実行してみてください.

$ ./a.out 
Hello INEX

[A2.4] コンポーネントと依存関係

コンポーネントが 1 つの場合

コンポーネントとは, ターゲットに指定した「目標物」 (たとえば実行ファイル)を構成する他のファイル群のことを指します. ターゲットとコンポーネントとの関係性を「依存関係」と呼びます. 上記の簡単な例の場合, ターゲットである実行ファイル example が依存するのは プログラムファイル example.f90 です. したがって Makefile には次のように記述します.

a.out: example.f90
        gfortran example.f90 

これで make は実行ファイル a.out とそれが依存するプログラムファイル example.f90 を比較し, example.f90 が a.out より新しい場合だけコマンドを実行するようになります. ファイルの新旧はタイムスタンプで判断されます.

$ ls -l a.out example.f90
-rwxr-xr-x 1 inex inex 8056  7月  5 16:37 a.out*
-rw-r--r-- 1 inex inex   62  7月  5 16:36 example.f90

この状態で make を実行しても実行ファイル a.out の作成は行われません.

$ make
make: 'a.out' is up to date.  

そこでプログラムファイル example.f90 を touch コマンドで更新してみます.

$ touch example.f90
$ ls -l a.out example.f90
-rwxr-xr-x 1 inex inex 8056  7月  5 16:37 a.out*
-rw-r--r-- 1 inex inex   62  7月  5 16:36 example.f90

これでプログラムファイル example.f90 が実行ファイル a.out より新しくなりました. この状態で make を実行すると, 実行ファイル a.out の作成が行われるようになります.

$ make
gfortran example.f90

このしくみがあるおかげで冒頭で述べたように 「一部のファイルに修正が必要となった場合, make を使えば全てのファイルを再コンパイルする手間を省くことができる」ようになります.

[2.4.2] コンポーネントが複数あるの場合

では次に以下のような 2 つのプログラムファイル example.f90 と sub.f90 からなる少し複雑なプログラムを例にします.

example.f90
program example
  use sub

  print *, "Hello INEX"
  print *, "Pi=", pi
end program example

sub.f90
module sub
  real,parameter :: pi = 3.141592e+0
end module sub

ここで example.f90 は sub.f90 に記載された変数 pi を参照していますので, example.f90 は sub.f90 に依存していることになります. この場合の Makefile は以下のようになります

a.out: sub.o example.f90
        gfortran -I./ sub.o example.f90

sub.o: sub.f90
        gfortran -c sub.f90

a.out のコンポーネントはプログラムファイル example.f90 とオブジェクトファイル sub.o です. オブジェクトファイル sub.o のコンポーネントはプログラムファイル sub.f90 です. したがって example.f90, sub.f90 のいずれかが更新されると a.out も再度作成されます.

[A2.5] make の変数

[2.4.2] に示した Makefile の例では, gfortran という文字列が 2 回現れています. プログラムにおいて同じ事を複数回記述するのはしばしば誤りの原因になります. このような場合には make の変数を利用するのが便利です. 変数は先頭のターゲットよりも前に VARIABLE = value という書式で定義し, $(VARIABLE) として引用します. 具体例は以下の通りです.

FC = gfortran

a.out: sub.o example.f90
        $(FC) -I./ sub.o example.f90

sub.o: sub.f90
        $(FC) -c sub.f90

この他にも make は以下のような組み込み変数を用意しています.

make の組み込み変数
変数 内容
$@ ターゲットのファイル名
$< 最初の依存関係の名前
$? ターゲットより新しい全ての依存関係
$^ 全ての依存関係

これらの組み込み変数を使うと, 先の Makefile はさらに一般的な形で記述されます.

FC = gfortran

a.out: sub.o example.f90
        $(FC) -I./ $^

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

さらにファイルサフィックス(接尾子)による略記を使うと以下のようになります.

FC = gfortran

a.out: sub.o example.f90
        $(FC) -I./  $^

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

[A2.6] make のオプション

make の実行時のオプションとして以下のようなものがあります.
make の実行時のオプション
パラメータ 意味
-f makefilename Makefile の代わりに指定した makefilename を使う.
-n 無実行モード. 記載されたコマンドを表示だけして実行しない.
-s サイレントモード. make が実行するいかなるコマンドも表示しない.

[A2.7] 参考文献


>> 次ページへ
情報実験第 11 回のページへ戻る

最終更新日: 2019/07/09 石渡 正樹 更新
Copyright © 2000-2019 inex