2009/12/11

短期集中連載 第2弾 『Makefile』

皆さんスクリプトファイルについては大体理解できたと思うので、
今日はMakefileについて書きたいと思います。

≪Makefileとは≫
 結論から言うと、Makefileはたくさんのファイルのコンパイル方法を詰め込んだものです。
スクリプトファイルにもコンパイル方法を詰め込むことができますが、
Makefileの便利なとこは余計な処理をしないでくれることです。

例 ファイル main.f, subroutine1f, subroutine2
   の用に沢山のファイルから成る実行ファイルをコンパイルする場合、
   通常は

   g77 -c subroutine2.f
g77 -c subroutine1.f
g77 -c main.f
g77 -o main.exe subroutine2.o subroutine1.o main.o

   とします。スクリプトファイルでまとめておくと、
   subroutine2.f だけを変更したときもこの4個のコマンドを実行することになります。
プログラムが小さい時はこれでいいかもしれませんが、数値計算で大きなプログラムを
   コンパイルするときは毎回時間がかかって面倒です。
   しかし、Makefileであれば

   g77 -c subroutine2.f
g77 -o main.exe subroutine2.o subroutine1.o main.o

   だけを抜き出してくれます。

と便利なMakefileです。ではその書き方の基本を次で説明します。

/*-------------------------------------------------------------------------------*/
≪Makefileの最小単位≫
 さっきのプログラムを例にします。

ファイル    main.f, subroutine1f, subroutine2
実行ファイル main.exe

このときMakefileはこうなります。

#-----------------------------------------------#
main.exe : subroutine2.o subroutine1.o main.o
g77 -o subroutine2.o subroutine1.o main.o

subroutine2.o : subroutine2.f
g77 -c subroutine2.f

subroutine1.o : subroutine1.f
g77 -c subroutine1.f

main.o : main.f
g77 -c main.f
#------------------------------------------------#

見ると何となくわかると思いますが、説明します。

まず、文章の単位として2行ごとになっています。
Makefileは基本的にこの2行を作っていくことで作成します。

では、2行を日本語にしてみましょう。

(①作成ファイル名): (②材料ファイル名)
<*タブ>(③材料ファイルから作成ファイルを作るコマンド)
  ↑
スペースではない、必ずタブにする。

③について
  まずは③から説明します。ここには自分でコマンドを打つ時の文字を並べます。
  sample.f から sample.o を作る時は

  g77 -c sample.f

  としますね。これをそのまま打ち込みます。
①について
  次は①です。ここには③のコマンドで作成されるファイル名を記述します。
  上の例のsample.f ならば sample.o です。
②について
  最後に②です。ここには③のコマンドで使うファイル名を入れます。
  上の例の sample.f ならば sample.f なります。

以上①、②、③を入れていけばMakefileの最小単位について作成することができます。

/*-------------------------------------------------------------------------------*/
≪Makefileの仕組み≫
ここまでで、Makefileの最小単位について説明しました。
Makefileはこの最小単位となる2行を並べるだけなのか?
という問いに対する答えは“否”です。

では最小単位の2行をどうやって並べて行けばいいのか説明します。
さっきの例で気づいてる人もいると思いますが、ルールは
実行コマンドを逆から書いていく”です。
つまり、リンクコマンドは最後にやるから一番上に書く。
subroutine2.f, subroutine1.f, main.f のコンパイルは最初にやるから
下に書く。となります。
詳しくはmain.f とsubrouine2.f, subroutine1.f の依存関係などもありますが、
今は逆からコマンドを構成していくと覚えておけば問題ないでしょう。

さて、具体的なMakefileの動きを簡単に説明します。
さっきのMakefileはこうでした。(行番号は説明のためにつけました。)

   #-----------------------------------------------#
1 :main.exe : subroutine2.o subroutine1.o main.o
2 : g77 -o subroutine2.o subroutine1.o main.o
3 :
4 :subroutine2.o : subroutine2.f
5 : g77 -c subroutine2.f
6 :
7 :subroutine1.o : subroutine1.f
8 : g77 -c subroutine1.f
9 :
10:main.o : main.f
11: g77 -c main.f
   #------------------------------------------------#

(1) Makefileは1行目のmain.exe を作る材料ファイルsubroutine2.oを
現在のディレクトリで探します。
   コンパイルされてないならどのオブジェクトファイルもありません。
   (ファイルがあれば次のsubrouine1.o を探します。)

(2) Makefileは材料ファイルsubroutine2.o を作ろうとします。
   そのために3行目以降で作成ファイル名がsubroutine2.o となっている行を探します。
   (この場合4行目です。)

(3) 4行目にsubrouitne2.o が作成ファイル名になっていたので、
   Makefileは5行目のコマンドを実行します。
   これでsubrouitne2.oが作られます。

(4) subrouitne1.o について同じ手順を繰り返す。

(5) main.o について同じ手順を繰り返す。

(6) 1行目の材料ファイルがそろったので、
   2行目のコマンドを実行してmain.exe ができます。

以上がMakefileの動きです。

/*-------------------------------------------------------------------------------*/
≪まとめ≫
 ここまでの説明ではMakefileの有用性がわからないという人もいると思います。
なれないとスクリプトのほうが簡単にかけるので、それでいいじゃないかと思うかもしれません。
しかし、書いた内容はMakefileの入口の部分です。
ここでは書きませんでしたが、マクロサフィックスといったさらに便利な機能がMakefileにはあります。
これらの機能を使うと膨大なファイルを一気に処理できる、コンパイル環境に合わせて書き換えが簡単になる、などMakefileの大切さがわかると思います。TASやGAが簡単にコンパイルできるのはMakefileのおかげなのです。


これで金崎研究室の学生はMakefileについてわかったと思います。
油断しないでください。

0 件のコメント:

コメントを投稿