自動化のための nmake 入門講座 - 基本的なパターン
自動化のための nmake 入門講座 -
基本的なパターン
Makefile
あなたは,あるディレクトリ上で開発作業を行っています.複雑な作業内容をわかりやすく一つにまとめておくにはどうすればいいでしょうか?
IDE(統合開発環境)を使わないコマンドラインベースの開発作業を行っている場合を考えましょう.
一般に開発者は,複雑なコマンド群を駆使して開発作業をしています.コンパイルしたり,プログラムを実行したり,バックアップを取ったり,リビルドを行うために,そのマシン環境に依存した複雑なコマンドを実行しなければなりません.Java のソースファイルをコンパイルするという単純な作業でも,必要なライブラリを指定し,クラスパスを設定する必要がありますし,SQLファイルを実行する際にも必要なユーザ名とパスワードを指定し,データベースに接続して実行しなければなりません.
こういった作業を自動化せず,個々の開発者が直接コマンドを入力して実行するのは,その担当者以外誰もメンテナンスできない環境を作り出してしまうことになります.プログラムのソースコードを他人が見てわかりやすくしておくことと同様,他の人が作業を行う場合にも,自分が普段どういうコマンドを実行していたのかという情報を明らかにしておく必要があります.また,そういう手がかりがなければ,将来自分がやっていた作業を再開する場合にも困ることになるでしょう.
Readme ファイルを作ることも必要かもしれません.しかし,Readme ファイルは実作業と独立したものなので,その開発者があるタイミングで(例えば引き継ぎ作業で)作成しようと思わない限り作ることはないだろうし,実作業と Readme ファイルのずれが生じてくるのは避けられないでしょう.
また,個々の複雑なコマンドを個別にバッチファイルあるいはシェルスクリプトにして残しておくということもできますが,こういう開発で必要ないろいろな作業は,一箇所にまとめておく方がわかりやすくなります.少なくとも開発作業のエントリーポイントと言えるファイルを用意しておいたほうがいいでしょう.
したがって,
そのディレクトリ上に Makefile を作成します.Makefile には,普段自分が行っている開発作業を書いておき,他の人が同じ作業をできるような手がかりを残しておきます.
IDE 環境は初心者にはわかりやすいかもしれませんが,個々の環境に合わせてカスタマイズすることは難しい場合が多いです.Makefile を書いておけば,自分の環境にあった便利なコマンドを作成しカスタマイズすることができます.Makefile は開発環境のプラットホームといえるでしょう.
意図を明らかにするタスク名
- あなたは,開発作業で複雑なコマンドを何度も入力し実行しています.このコマンドを簡単に実行できないでしょうか?
Makefile を作る最初の動機として挙げられるのは,自分が複雑なコマンドを何度も入力していることに気づいたときです.こういったコマンドを簡単に実行できなければ,開発に必要なリズムを得ることができません.生産性を上げるかどうかは,このリズムに乗って開発を進められるかどうかにかかっています.そのためにも自分の開発環境はできるかぎり整えておくことです.そうすれば,開発そのものに集中することができ,開発効率は飛躍的によくなっていくでしょう.
また,複雑なコマンドを入力していても,そのコマンドが何を意図しているものなのか,他人にはわかりにくい場合があります.バックアップをとるのが目的なのか,単体テストするのが目的なのか,リポジトリから最新版をとってきてリリース用にビルドする作業なのか,そのコマンドをちょっと見ただけではなかなかわかりません.
したがって,
一連のコマンドの意図を明らかにするようなタスク名をつけ,Makefile 内にタスクターゲットとして追加します.
タスクターゲットの名前を考え,Makefile に次の項目を付け加えます.
[タスク名]: タスクを行うためのコマンドライン
実際に実行するには次のようにします.
c:\> nmake [タスク名]
バックアップを取るのが目的なら backup ,単体テストを行うのが目的なら test という意図を表すターゲットを Makefile に追加しましょう.
backup: バックアップを行うためのコマンドライン test: 単体テストを行うためのコマンドライン
これらの作業を行うには,次のようにコマンドラインから入力して実行します.
c:\> nmake backup c:\> nmake test
all ターゲット
- Makefile に複数の作業内容をターゲットとして表しています.しかし,ターゲットの並べ方が複雑でわかりにくくなってきました.どうすればわかりやすくなるでしょうか?
Makefile は,ターゲット宣言のほかに マクロ定義,サフィックスルール,プリプロセッサ指令等が入り乱れ複雑で非常にわかりにくいものになりがちです.少なくとも Makefile の利用者にとっては,デフォルトで実行されるターゲットが何なのか,すぐわかるような構成にしておく必要があります.nmake は自動化が目的のため,何も理解せずそのまま実行すると危険です.筆者の場合は,防衛策として,実際にどういう動作をするのか見るため
c:\> nmake -n
と n オプションをつけて実行します.こうすると,どんなコマンドが実行されるか標準出力に表示されます(表示されるだけで,実行はされません).いずれにせよ,デフォルトのターゲットがどこなのか Makefile を見て明確にしておくことは重要でしょう.
したがって,
Makfile ファイルの一番最初のターゲットとして all という名前のタスクターゲットを宣言し,デフォルトで実行したいターゲット(デフォルトターゲット)を all ターゲットの依存ターゲットとします.
Makefile の一番最初に出てくるターゲットは,
all: [デフォルトターゲット名]
とします.こうすると, Makefile を読む人がどこを手がかりにして解析していけばよいのかがわかります.プログラム開発をしているときは,プログラムそのものがデフォルトターゲットになりますが,適切な デフォルトターゲットがない場合は,何も依存ターゲットを書かないか,help ターゲット にしてみるのがいいでしょう.
help ターゲット
- Makefile に複数の作業内容をターゲットとして表しています.しかし,各ターゲットがどういう意味なのか,複雑でわかりにくくなっています.どうすれば他人にもわかりやすくなるでしょうか?
Makefile は作成者以外どうやって使うのかわからない,という状況になることがよくあります.それは,Makefile の文法が単純で,同じことをするにも人によって書き方がまちまちなのが原因でしょう.
開発者のすべてが make について詳しいわけではないし,多くの開発者は,Makefile の中身を解析するようなことはしません.Makefile の複雑な構成を理解するよりも,まず開発ツールとして利用したいのです.だから,たとえ Makefile の構成がわからなくても,この Makefile にどういうターゲットが用意されており,どのターゲットを指定すればどういうことが起こるのか,すぐにわかる仕組みを用意しておくことが必要です.親切なソフトウェアやツールにヘルプ機能が用意されているのと同様,あなたが書く Makefile にもヘルプ機能を追加することを忘れてはいけません.
したがって,
Makefile のターゲットとして help ターゲットを宣言し,そのターゲットを指定すれば,Makefile で用意されているすべてのターゲット一覧とその機能を標準出力に表示させるようにします.
例えば,
c:\> nmake help
と実行した場合,標準出力に以下のような表示がでるようにします.
NMAKE backup - バックアップを行います. NMAKE test - 単体テストを行います.
ここで,Makefile の書き方を解説しましょう.まず,誰もが思いつくであろう標準出力に表示させる方法は, echo コマンドを使うものです:
help: @echo NMAKE backup @echo - バックアップを行います. @echo NMAKE test @echo - 単体テストを行います.
(注: echo コマンドの手前に @ がついているのは,make を実行したとき コマンドラインそのものをエコー表示しない,という make の機能です)
しかし,nmake に限定すれば 上の方法よりももっと簡単な方法があります.それは,インラインファイル を使った方法です.この機能を使えば,
help: @type << NMAKE backup - バックアップを行います. NMAKE test - 単体テストを行います. <<
というふうに書けます(注: type コマンド手前の @ は,やはりエコーバックを防ぐために書かれています).
インラインファイルとは,<< の次の行から,行頭に << が出てくる手前の行までの部分が書かれたファイルを nmake が一時的に作成し,そのファイル名をそのまま type コマンドに送る,という nmake 独自の機能です.これは,非常に便利な機能で,筆者が Cygwin の make ではなく nmake を使い続けている理由の一つになっています.
さらに,上記の help ターゲットを次のように改善することもできます.
backup: バックアップを行うためのコマンドライン backup.help: @type << NMAKE backup - バックアップを行います. << HELP_TARGETS = $(HELP_TARGETS) backup.help test: 単体テストを行うためのコマンドライン test.help: @type << NMAKE test - 単体テストを行います. << HELP_TARGETS = $(HELP_TARGETS) test.help help: $(HELP_TARGETS)
このように,HELP_TARGETS マクロを使って help ターゲットを backup.help と test.help に依存させ,各ターゲットの説明は 個別に書いていくほうが Makefile としてはわかりやすくなるでしょう.この backup.help と test.help には タスク拡張子 のパターンが使われています.
次の nmake の特殊マクロを使えば,もっとよくなります.
マクロの表記 意味 $(MAKE) nmake プログラム名.NMAKE に展開される. $* ターゲットの拡張子を除いた部分.backup.help がターゲットなら backup と展開される.
以上をまとめると,筆者が推奨する help ターゲットの書き方は,以下のようになります.
backup: バックアップを行うためのコマンドライン backup.help: @type << $(MAKE) $* - バックアップを行います. << HELP_TARGETS = $(HELP_TARGETS) backup.help test: 単体テストを行うためのコマンドライン test.help: @type << $(MAKE) $* - 単体テストを行います. << HELP_TARGETS = $(HELP_TARGETS) test.help help: $(HELP_TARGETS)
以下は,パターン候補です.とりあえず無視してください.
clean ターゲット
build ターゲット
rebuild ターゲット
-o オプション
GUI アプリのコマンドライン化
- あなたは,タスクターゲットを書いています.しかし,そのタスクには GUI を使ったマウスによる作業が含まれています.どうしたらよいでしょうか?