前回から、Makefileで利用できる機能の一つとして「関数」の説明を始めた。あまり乱用しないほうがよいが、Makefileは関数を使うことでかなりプログラミング的な書き方ができ、便利な面もある。 今回は、ファイルパスの操作に関する関数を取り上げる。

なお、ファイル名の操作に関する関数は引数をパスを指定するのだが、このパスは空白区切りだと複数のパスが含まれていると判断される。前回紹介した文字列を操作する関数が、関数によっては引数の中身を「空白区切りのリスト」だと解釈していたのと同じだ。なお、パスリストの先頭と末尾の空白に関しては無視されるので注意しよう。

ファイルパスを操作する関数

GNU makeのMakefileではパスを操作する関数として次の関数を使用できる。

関数 シンタックス
dir $(dir パス…)
notdir $(notdir パス…)
suffix $(suffix パス…)
basename $(basename パス…)
addsuffix $(addsuffix サフィックス,パス…)
addprefix $(addprefix プレフィックス,パス…)
join $(join リスト,リスト)
wildcard $(wildcard パターン)
realpath $(realpath パス…)
abspath $(abspath パス…)

それぞれ機能をまとめると次のようになる。

関数 内容
dir 空白区切りのパスリストに含まれるパスのディレクトリ部分を抽出して置き換える。パスにスラッシュが含まれていない場合、ディレクトリとして「./」が使われる。実際のファイルシステムの状況は関係なく、文字列上としてのみ処理が行われる
notdir 空白区切りのパスリストに含まれるパスのファイル名部分を抽出して置き換える。パスにスラッシュが含まれていない場合、そのまま出力される。パスがスラッシュで終わる場合、空文字列になる。このため、リスト内の数が減ることがある。実際のファイルシステムの状況は関係なく、文字列上としてのみ処理が行われる
suffix 空白区切りのパスリストに含まれるパスのピリオドを含むサフィックスに置き換える。ファイル名に複数のピリオドが複数含まれている場合、最後のピリオド以降がサフィックスになる。ピリオドが含まれていない場合には空文字列になる。このため、リスト内の数が減ることがある。実際のファイルシステムの状況は関係なく、文字列上としてのみ処理が行われる
basename 空白区切りのパスリストに含まれるパスのピリオドを含むサフィックス以外に置き換えられる。ファイル名にピリオドが含まれていない場合にはそのまま置き換えられる。実際のファイルシステムの状況は関係なく、文字列上としてのみ処理が行われる
addsuffix 空白区切りのパスリストに含まれるパスにサフィックスを追加する。実際のファイルシステムの状況は関係なく、文字列上としてのみ処理が行われる
addprefix 空白区切りのパスリストに含まれるパスにプレフィックスを追加する。実際のファイルシステムの状況は関係なく、文字列上としてのみ処理が行われる
join 空白区切りのパスリストの含まれるパスを結合する。最初のリストの1つ目の単語を次のリストの1つ目の単語と結合、最初のリストの2つ目の単語を次のリストの2つ目の単語と結合、といったように結合する
wildcard ワイルドカードを含むファイル名パターンに合わせて空白区切りのパスリストに置き換える。ワイルドカード文字列は「∗」「?」「[文字]」。シェルのファイルグロブ展開とよく似ている
realpath 空白区切りのパスリストに含まれるパスを、realpath(3)で正規化した結果に置き換える。シンボリックリンクは解決される
abspath 空白区切りのパスリストに含まれているパスを、絶対パスに置き換える。シンボリックリンクは解決しない

wildcard、realpath、abspathという3つの関数は、実際のファイルシステムの状態を反映して機能する。これはシェルのグロブ展開やrealpath(1)コマンドなどに相当する機能なので、動作も想像しやすいはずだ。

dir、notdir、suffix、basename、addsuffix、addprefix、joinは実際のファイルシステムの状態には関係なく、ただ文字列としてパスを操作するので注意が必要となる。要するに「/」や「.」でしか判断を行わないので、実際にはディレクトリであっても、関数で処理するとファイルとして結果が得られるケースがあるということだ。文字列だけで判断している機能であることを押さえておこう。

dirとnotdirは、ディレクトリ部とそれ以外といった結果を、suffixとbasenameは拡張子とそれ以外といった結果を出す。これらは組み合わせて覚えておくと便利だ。addsuffixとaddprefixはそれぞれ拡張子や親パスを追加する指定で、joinはリストの結合である。joinはちょっとばかり特殊だと言えるだろう。