自動化のための nmake 入門講座 -
自動化のための nmake 入門講座 -
基礎知識編
nmake を使ってみよう
make は,ある作業を自動化するためのツールです.make を利用するには,
- メイクファイルに作業内容を書く
- コマンドラインから make を実行
という手順を踏みます.ここでメイクファイルというのは作業内容が書かれたテキストファイルです.make は,メイクファイルの中身を参照してそこに書かれた一連のコマンドを実行します.メイクファイルは,通常 Makefile というファイル名を使います( makefile でもいいが,Makefile が僕の好み).実際にやってみましょう.まず, Makefile という名前のファイルを作成します.
all: echo Hello World!
このメイクファイルは,"Hello World!" という文字を echo コマンドを使って表示するという単純なものです.
ここで,注意しなければならないのは, 2行目の先頭と echo の間はタブ1文字である,ということです.nmake ではそれ以外の空白文字を使ってもエラーにならないようですが,通常はコマンドの前にタブ1文字を入れます.Makefile を作成し,次にそのファイルと同じディレクトリでコマンドラインから nmake とだけ入力し,実行します.すると,
c:\> nmake Microsoft (R) Program Maintenance Utility Version 1.60.5270 Copyright (c) Microsoft Corp 1988-1995. All rights reserved. echo Hello World! Hello World!
のように表示されるはずです( nmake へのパスを通しておくことを忘れずに). Microsoft の Copyright 表示が毎回でるのが嫌な人は,
c:\> nmake /NOLOGO
という風に /NOLOGO オプションをつければ出なくなります.さらに,実行結果で echo Hello World! とエコーバックされるのがじゃまな場合は,Makefile の echo コマンドの前に @ マークをつけ,
all: @echo Hello World!
とすれば Hello World! のみが表示されるようになります.
Emacs の便利コマンド
M-x compile コマンド
Meadow など Emacs 系のエディタを使っている人は,わざわざ MS-DOS プロンプトを開いてディレクトリを移動し, nmake を実行する必要はありません.make を実行するためのコマンド M-x compile が用意されています.M-x compile を実行すると,ミニバッファに Compile command: と実行するコマンドが何かを聞いてきますので,ここを nmake と修正しリターンキーを押せば Emacs 上で実行できて便利です.
この M-x compile コマンドは非常に便利なコマンドで,make に限らずシェル上で実行できるコマンドならなんでも OK です.例えば ruby のプログラムを書いていて,そのプログラムを実行したい場合, M-x compile コマンドを使います. Compile command: と聞いてきたときに,コマンドを ruby foo.rb のように指定するだけです.
もし,Compile command: の初期値を変えたければ,.emacs に
(setq compile-command "nmake /NOLOGO ")
と書けば OK です.
M-x next-error コマンド
M-x compile で実行し,エラーが発生した場合 M-x next-error コマンドでエラー行にジャンプすることができます.通常の設定では, C-x `
というキーにバインドされています(Ctrl キーと X を同時に押し,一旦離した後 シフトキーを押しながら ` です).このコマンドは非常に便利ですのでぜひ覚えておいてください.例えば,
all: @echo Hello World! !error エラー
というように Makefile の 4 行目にわざとエラーを書いておいて nmake を実行すると,
と *compilation* バッファに表示されます.ここで C-x ` と入力すると Makefile の 4 行目にあるエラー箇所に自動的にジャンプします.これは,Java などほかのプログラムのコンパイルエラー時にエラー箇所にジャンプしたいときや,grep コマンドで検索箇所にジャンプしたいときにも使えます.
nmake のコマンドラインオプション
Makefile 以外のファイルでメイクしたい ( -f )
make は実行時のカレントディレクトリにある Makefile (makefile) というファイル名をもつファイルをデフォルトのメイクファイルとして認識します.テストを行いたいときなど,他のメイクファイルを使って make を実行したい場合 -f オプションを使います.
c:\> nmake -f foo.mak
こうすれば,同じディレクトリの Makefile ではなく foo.mak をメイクファイルとして実行します.一般に メイクファイルの拡張子は .mak とするのが普通です.
どんなコマンドが実行されるのかだけ知りたい ( -n )
Makefile を書いた際,デバッグのために実際にどんなコマンドが実行されるかだけを知りたい場合があります.そういう場合は, -n オプションを使います.
c:\> nmake -n
こうすれば,実行されるコマンドを出力するだけでそれらのコマンドは実行されません.他人の書いた Makefile を自分で使う場合,何が起こるのか知りたいときにも便利です.
強制的にメイクしたい ( -a )
make は,ファイルの更新日時を自動的に調べ,実行する必要がないコマンドは実行せず必要なコマンドのみを実行します(後で詳しく説明します).そういう機能は普段は便利なのですが,その親切な機能を無視してすべてのコマンドを強制的に実行したい場合があります.そのためには, -a オプションを使います.
c:\> nmake -a
メイクファイルの書き方
ターゲット
メイクファイルは,基本的には次のような構造になっています.
[作りたいファイル名]: [そのファイルを作るためのコマンドライン]
[作りたいファイル名] のことを make では ターゲット と呼びます.[そのファイルを作るためのコマンドライン] の手前には,タブ1文字を入れることに注意してください.例えば, "Hello World!" という文字が入った hello.txt というファイルを作るメイクファイルは以下のようになります.
hello.txt: echo Hello World > hello.txt
[そのファイルを作るためのコマンドライン] は,複数行書きこんでもかまいません.hello.txt というファイルを, Hello と World の 2行からなるテキストファイルとして作成する場合は,次のようにします.
hello.txt: echo Hello > hello.txt echo World >> hello.txt
このとき,2行目以降にも行頭にタブ1文字いれることに注意してください.
タスク
また,ターゲットとして,実際に存在しないファイル名を指定することができます.これは, 擬似ターゲットと呼んだり,ダミーターゲットと呼ばれたりしますが,統一された用語はないようです.そこで,ここでは便宜上 タスク または タスクターゲット と呼ぶことにしましょう(これと対応させるため,ファイルをファイルターゲットと呼ぶことにします).make を単にある特定のファイルを作る目的ではなく,作業を行うコマンドとして利用したい場合に用いられます.
[実行したいタスク名]: [そのタスクを行うためのコマンドライン]
やはり [そのタスクを行うためのコマンド] の手前にもタブ1文字を入れることに注意してください.ここで,[実行したいタスク名] にはそれと同名のファイル名が存在しないよう注意する必要があります.ファイル名がありそうなものをタスクの名前として採用すると混乱のもとになりますので,そうしないようにしましょう.
タスクターゲットの例として,そのディレクトリの .class という拡張子がついたファイルをすべて削除する clean ターゲットを書いてみましょう.
clean: del *.class
複数のターゲット
メイクファイルには,複数のターゲットを含めてかまいません.
hello.txt: echo Hello World > hello.txt clean: del *.class
この場合には,nmake を実行するときに ターゲット名を指定するようにします.指定しなかった場合は,一番最初に書かれたターゲット(上の例では hello.txt )が実行されます.したがって, このメイクファイルで clean ターゲットを実行するためには,
c:\> nmake clean
とすれば OK です. hello.txt の場合は,
c:\> nmake hello.txt
または
c:\> nmake
ということになります.さらに, clean と hello.txt を同時に行いたい場合は,
c:\> nmake clean hello.txt
と複数のターゲットを指定します.
依存ターゲット
ここで改めて Makefile の構造をみるために,Document Object Model を書いてみましょう.
このように,Makefile は複数のターゲットを持ち,個々のターゲットは実際のファイルだったり,実行したいタスクだったりします.ターゲットの部分をもう少し詳しく見てみましょう.
ターゲットは,それを実現するためのコマンドラインを持っています.また,これ以外にも 依存ターゲット を持っています.
依存ターゲットとは,そのターゲットを作るために必要なターゲット(部品)のことです.targetA というターゲットを作るために targetB という部品が必要な場合,メイクファイルには次のように書きます.
targetA: targetB [targetA のコマンドライン]
上のように書かれている場合,「 targetA の依存ターゲットは targetB である」ということを表しています.このとき,
c:\> nmake targetA
を実行するとどうなるか説明しましょう.
- targetA と targetB がファイルターゲットの場合
このとき, nmake は Makefile と同じディレクトリにある targetA と targetB というファイルの更新日時を調べます.もし,targetA の更新日時が targetB の更新日時より古い場合,[targetA のコマンドライン] を実行します.そうでない場合は,何もせず「'targetA' は更新する必要がありません。」というメッセージを表示して終了します.
- targetA がタスクターゲット, targetB がファイルターゲットの場合
このとき, nmake は 必ず [targetA のコマンドライン] を実行します.
- targetA がファイルターゲット, targetB がタスクターゲットの場合
このとき, nmake は targetB のターゲットがメイクファイル中に書かれていないかどうか調べます.もし書かれてない場合,「NMAKE : fatal error U1073: 'targetB' のビルド方法が指定されていません。」というエラーメッセージを表示します.もし,メイクファイル中に
targetB: [targetB のコマンドライン]
があれば,[targetB のコマンドライン] を実行した後 [targetA のコマンドライン] を実行します.
-
targetA と targetB がタスクターゲットの場合
この場合は 「 targetA がファイルターゲット, targetB がタスクターゲットの場合」 と同じです.[targetB のコマンドライン] を実行した後 [targetA のコマンドライン] を実行します.
ポイントとなるのは,ファイルターゲットの場合に実際のファイルの更新日時を比較している,というところです.もし更新日時が依存ターゲットより新しいならば, nmake は何しません.ファイルやタスクの依存関係を記述し,適切な順番でコマンドを実行できるところが nmake の優れたところです.