Makeまえがきその昔、Makefileの書き方という非常にわかりやすいMakefileの入門ページがあったのですが、seiichirou氏の卒業(?)とともにページが消えてしまいました。私も大変お世話になったページだった、というかこれからもお世話になりそうなので、そこでWebArchiveから引っ張りだしてきたものを、はてな記法で書き直したものがこの記事になります。自分用に書き直したのですが、せっかくなので公開してみます。以下の著作はseiichirou氏に帰属します*1。makeにかぎって説明します。makeって何?ソースファイルを分割して大規模なプログラムを作成していると、コマンドでコンパイルするのが面倒です。一部のソースファイルを書き換えただけなのに全部をコンパイルし直すのは時間の無駄です。そんな問題を解決するのがmakeです。Makefileと呼ばれるテキストファイルに必要なファイルと各ファイルのコンパイルのコマンド、ファイル間の依存関係を記します。“make”というコマンドを実行するだけで、自動的にコマンドを実行してコンパイルしてくれます。これだけではスクリプトと大差がないのですが、makeはMakefileに記された依存関係に基づいて更新されたファイルの内関連のあるものだけを更新することで、コンパイル時間を短くします。makeは特定のプログラミング言語に依存したものではありません。C言語のソースファイルのコンパイルにも使えますし、Verilog-HDLのシミュレーションにも使えますし、TeXのコンパイルにも使えます。実はmakeには色々種類があります。主なものをあげると以下の通りです。C++に搭載されているmakeです。Windows用です。C++にはプロジェクト管理機能があるのでnamkeのお世話になることはほぼないでしょう。お世話になるのは、公開されているソースファイルをコンパイルする場合だけでしょう。Compilerなどに入ってます。Windows用です。make用のMakefileがついていたりします。GNUの“make”はUNIX系では標準的なmakeです。makeには、Cygwinに付属のものか、MinGWのものがあります。makeの使い方を説明します。Solarisの“make”はSolarisに付属するmakeです。makeを使うそうです。World!それではメイクファイルを書いてみましょう。World!を使用します。0;}同じディレクトリに“Makefile”というファイルを作成して、以下の内容を記述してください。一行目はコメントです。“#”と書くとその行の“#”以降の文字列はコメントとなります。コマンドからmakeを実行すると以下のようにコンパイルしてくれます。hello.cこのあともう一度makeを実行してみましょう。更新済みですhello.cが更新されていない(helloの方がhello.cよりも日付が新しい)のでコンパイルされません。こんな感じで、必要な部分のみコンパイルしてくれます。Makefileとします。ファイル名を指定しない場合は、“GNUmakefile”、“makefile”、“Makefile”の順に検索します。依存関係行Makefileの基本的な構文は依存関係を表す依存関係行です。依存関係行はこんな感じです。依存ファイル名3コマンド行1コマンド行2コマンド行3ターゲット名は一般的に生成されるファイルのファイル名にします(そうでない場合については後述します)。ターゲット名の後に“:”を書いて、その後にスペース区切りで依存するファイルのファイル名を記述します。これらのファイルのうちどれか一つでも更新されるとコマンドが実行されます。ターゲット名とします。ターゲット名を省略すると、Mkefileの中で先頭のターゲットが実行されます。ターゲット名から始まる行の次の行から実行するコマンドを記述します。コマンドを記述する場合は必ず先頭にタブ文字を入れる必要があります。例として、C言語の分割コンパイルをしてみましょう。分割コンパイル用に以下のファイルを用意します。江田島平八である!!\r\n");}メイクファイルはこんな感じです。edajima.chello.cまたはedajami.cのいずれかを更新するとコンパイルし直してくれます。このままでは更新されてないファイルもコンパイルし直されてしまうので、少し変更します。edajima.oとなります。ここで、edajima.cを書き換えます。edajima.oとなって、edajima.oだけが更新されます。依存関係行を使った応用について説明します。プログラムをコンパイルすると中間ファイルなどができていちいち削除するのが面倒です。そこで、Makefileに以下の行をつけたします。edajima.oこうしてコマンドで以下のように実行します。edajima.o不要なファイルをすべて削除してくれます。“clean”は依存するファイルがなく、cleanというファイルを生成するわけでもなく、コマンドを実行するだけです。target”と呼びます。phonyターゲットを使用する場合、ターゲット名と同じ名前のファイルがあると変なことになります。更新済みですこれをさけるためにはMakefileを以下のように書き換えます。edajima.oこうするとcleanというファイルが存在していても問題ありません。依存関係行の応用その二もう一つの応用は、複数のプログラムを作成するときに役に立ちます。ここでは以下のソースファイルを追加します。0;}そしてMakefileを以下のようにします。raidenとなり、面倒です。そこで、ダミーの依存関係行を追加します。raiden.o先頭に追加した“all”がミソです。raiden.oとなってめでたく二つのプログラムを一度に作成することができました。依存関係行の応用その三C言語ではコンパイルしないけどソースファイルにインクルードされるヘッダーファイルが存在します。ヘッダーファイルが更新されたときにソースファイルをコンパイルし直すにはどうしたらよいのでしょうか?この問題を解決するには、同じターゲット名の依存関係行を追加します。以下のようなファイルを用意します。jaki.oとなります。ここで“jaki.h”を書き換えます。対して行うべき事はありません。いって更新してくれません。そこで、以下のように“Makefile”を書き換えます。jaki.h”という行がポイントです。jaki.oとなり、ちゃんと更新されます。マクロここから少し難しくなります。これまではMakefieにファイル名やコマンド名を直接書いていました。マクロを使うと直接書かなくてすみ、他への流用などが容易となります。マクロを定義するには以下のようにします。文字列マクロを参照するには、$(マクロ名)または${マクロ名}とします。実際に使ってみるとこんな感じです。$(objs)ここでは、オブジェクトファイル名を“objs”というマクロとして定義しています。edajima.o”に置換されます。makeでは、定義済マクロとして以下のものがあります。上記のプログラムの引数用のマクロもあります。YACCの引数これらのマクロは再定義可能です。$(objs)ここでは“CC”というマクロを“gcc”という文字列で再定義しています。“RM”というマクロをそのまま使用しています。内部マクロ前述のマクロは単純に文字列に置換するだけでしたが、内部マクロはもう少し複雑になります。こんな感じの内部マクロがあります。$(objs)ここでは“$@”という内部マクロを使用しています。これはターゲット名を表すものです。$(objs)と解釈されます。以下のものもあります。$<ここでは“$<”という内部マクロを使用しています。これは依存ファイルの先頭のファイル名を表すものです。hello.cと解釈されます。依存ファイル名のリストを表す“$^”という内部マクロもあります。内部マクロをまとめるとこんな感じです。わかんねマクロと内部マクロを駆使すると、Makefileはこんな感じになります。$(objs)サフィックスルールサフィックスルールとは、ファイル名の拡張子(サフィックス)ごとにルールを定義するものです。$<“.SUFFIXES”は依存関係行と同じ形ですが、意味が違います。サフィックスルールを適用する拡張子のリストを書きます。“.c.o”がサフィックスルールとなっており、拡張子が“.o”のファイルは拡張子を“.c”変えたファイルに依存していることを表します。変換方法はコマンドで表されています。ターゲット名が“hoge.o”ならばmakeはこのサフィックスルールより“hoge.c”に依存していると判断して、コマンドを実行し“hoge.o”を生成します。サフィックスルールを用いると、こんな感じで書けます。$(objs)ここまでくると、あとは“program”や“objs”を書き換えるだけでいくらでも流用ができます。ちなみに、ヘッダーファイルの依存関係だけは自分で記述しなければなりません。分割Makefileプログラムが複雑になって、ディレクトリごとにソースコードを分けるなどしていくと、一つのMakefileで管理するのは面倒になってきます。そんな時には、Makefileを分割することができます。subdirとします。C言語のヘッダーファイルの依存関係の自動解決C言語でプログラミングしている際に、ソースファイルが増えるとヘッダファイルの依存関係をいちいち記述するのは面倒です。色々な解決方法があるみたいですが、とりあえずこんなん考えてみました。depend.incgccのプリプロセッサであるcppとsedを組み合わせています。cppは指定したソースファイルの依存関係をmakeの形式で出力してくれるオプションを持っています。それを使って、全ソースファイルの依存関係を“depend.inc”に出力して、それをインクルードしています。depend”とコマンドを実行すればOKです。$(program)”とすることで、makeする際に毎回“depend.inc”を作成するようにしています。makeには他にも色々な機能があります。詳しくはWebのマニュアルを見てください。makeを発展させた、autoconf、automake、libtool、などもあります。これはOS間の差異を吸収するためのツールです。*1:ただ、これって著作権的にOKなのだろうか...誰か詳しい人教えてください。以前こんな記事を書きました。»プロフィールid:s-shinプログラマブルな人間になりたい。(1)リンクヘルプはてなブログお知らせはてなブログをはじめよう!s-shinさんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。