make はプログラムのコンパイル・リンク・インストール作業を自動化してくれるコマンドです. 事前に make の動作手順を記述した Makefile というファイルを用意しておけば, ユーザは以下のようなコマンドを入力するだけで必要な作業を終えることができます.
$ make $ make install (引数に何を与えるかは Makefile の記述によります)
make は Makefile の記述を参照し, プログラムを構成するどのファイルが再コンパイルを必要としているかを決定します. 一部のファイルに修正が必要となった場合, make を使えば全てのファイルを再コンパイルする手間を省くことができます. このような特徴から 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.2.1 Built for x86_64-pc-linux-gnu Copyright (C) 1988-2016 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.
以下では実際に簡単な 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
コンポーネントとは, ターゲットに指定した「目標物」 (たとえば実行ファイル)を構成する他のファイル群のことを指します. ターゲットとコンポーネントとの関係性を「依存関係」と呼びます. 上記の簡単な例の場合, ターゲットである実行ファイル 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 つのプログラムファイル example.f90 と sub.f90 からなる少し複雑なプログラムを例にします.
example.f90program example use sub print *, "Hello INEX" print *, "Pi=", pi end program example
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 も再度作成されます.
[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 は以下のような組み込み変数を用意しています.
変数 | 内容 |
---|---|
$@ | ターゲットのファイル名 |
$< | 最初の依存関係の名前 |
$? | ターゲットより新しい全ての依存関係 |
$^ | 全ての依存関係 |
これらの組み込み変数を使うと, 先の 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 $<
パラメータ | 意味 |
---|---|
-f makefilename | Makefile の代わりに指定した makefilename を使う. |
-n | 無実行モード. 記載されたコマンドを表示だけして実行しない. |
-s | サイレントモード. make が実行するいかなるコマンドも表示しない. |