There is the original file(in English) here.
最初,,,最後のページ,目次 に移動.

テキスト変形関数

 関数を使えばmakefileで処理する文字列で利用するコマンドやその実行対象のファイルをコンピュータに計算させることができるようになります。関数を使うには、関数の名前と関数に与える(引数という)付随文字列からなるファンクション・コール(関数の呼び出し; function call)を使います。関数の処理結果は変数の場合と全く同じように、makefileの関数を呼び出した部分に置き換えられます。

関数の呼び出し構文

ファンクションコールは変数の参照に似ていて、このようになっています。


$(関数 引数)

またはこうなります。


${関数 引数}

 この関数というのが関数名になり、makeに用意された数少ない名前のリストのうちの一つを使います。新しい関数は定義できません。

引数というのが関数の引数です。引数は関数名と一つ以上のスペースかタブで区切られており、複数の引数がある場合は引数同士をコンマで区切ります。このような空白やコンマは引数の値の一部にはなりません。ファンクションコールを囲むデリミタ(区切り文字)として括弧と大括弧のどちらを使ったにしろ、その文字自身を引数として一対になっている場合は使う事ができ、使ってないほうのデリミタは対になってなくても構いません。引数自身に別のファンクションコールや変数参照が含まれる場合、全ての参照に同じデリミタを使うのが賢い方法です。つまり`$(subst a,b,${x})'と書くのではなくて `$(subst a,b,$(x))'として下さい。そのほうがきれいですし、参照の終端を探すのに一つのデリミタを一致させるだけで済むからです。

 それぞれの引数にかかれた文字列は、関数に付随する引数の値を変数の代入とファンクションコールで作成してから処理されます。代入作業は引数が並ぶ順番で行います。

 コンマと、一致しない括弧と大括弧は引数の文字列として書くことができず、最初の引数の文字列として前置きの空白は書けません。これらの文字を引数の値に入力するには変数の代入を使います。次のように、最初にコンマと空白文字を隔離させて値としてcommaspaceというように定義した変数を使ってそういう文字が必要な場所でその変数を代用してください。


comma:= ,
empty:=
space:= $(empty) $(empty)
foo:= a b c
bar:= $(subst $(space),$(comma),$(foo))
# bar is now `a,b,c'.

 ここではsubst関数はfooの値の全ての空白をコンマに置換し、結果を関数のある場所に代入します。

文字列を代入・分析する関数

 ここに文字列を操作する関数を示します。

$(subst from,to,text)
 textという文章の本文の置換動作をしてくれます。つまり文章中にある全部のfromtoに置換します。置換結果はファンクションコールの場所に代入されます。たとえば、

$(subst ee,EE,feet on the street)

…とすると、`fEEt on the strEEt'という文字列が代入されます。
$(patsubst pattern,replacement,text)
 text(文章)の中の空白で区切られた単語の中からpattern(型)に一致するものをreplacement(代用文字列)に置換してくれます。patternにはワイルドカードとして処理される`%'を一つ含めることができ、ワイルドカードは一単語中の何文字の文字列にも一致します。replacementにも`%'を一つ含めることができ、こちらの`%'patternの中で`%'に相当する部分の文字列に置き換えられます。  patsubst関数実行における`%'はバックスラッシュ(`\')で引用化できます。`%'文字を引用させる目的ではないバックスラッシュはもう一つのバックスラッシュでそれ自身を引用できます。`%'や自身を引用させるためのバックスラッシュはファイル名の比較や代入させる語幹(stem)に使われる前に型から削除されます。`%'の引用とは関係ないバックスラッシュはこのことに関係なく動作します。例えば`the\%weird\\%pattern\\'という型では、`the%weird\'のあとに有効な`%'文字があり、その後に`pattern\\'が続きます。最後の二つのバックスラッシュは`%'に影響しないのでそのまま残ります。単語間の空白部分は一つの空白文字に収縮され、前後の空白部分は廃棄されます。 例えば、

$(patsubst %.c,%.o,x.c.c bar.c)

…とすると、`x.c.o bar.o'という値が生成されます。 patsubst関数の効果を得るには代用参照(代用参照の項を参照)を使うほうが簡単です。

$(var:pattern=replacement)

…は、下と同等です。

$(patsubst pattern,replacement,$(var))

 もう一つの手っ取り早い方法を使えばpatsubstの最も一般的な利用法の一つであるファイル名の最後にある語尾(サフィックス;suffix)の置換という作業を簡単に行えます。

$(var:suffix=replacement)

…は、下のものと同等です。

$(patsubst %suffix,%replacement,$(var))

 例えば、次のようなオブジェクトファイルのリストがあるとします。

objects = foo.o bar.o baz.o

 相当するソースファイルのリストを取得するにはこうやれば間単に取得できます。

$(objects:.o=.c)

…は、一般形である次のものの代わりです。

$(patsubst %.o,%.c,$(objects))

$(strip string)
 stringの前後の空白部分を削除し、文字列の内部にある一つ以上の空白文字(whitespace characters)を一文字のスペース(a single space)に置換してくれます。だから`$(strip a b c )'の結果は`a b c'になります。 stripという関数は条件分岐と一緒に使うととても便利です。`'という空っぽの文字列をifeqifneqを使って何かと比較させる場合、普通は空白文字からなる文字列も空っぽの文字列として扱わせたいはずだからです(Makefilesの条件分岐部分の項を参照)。 だから、以下は望んだ結果にはならないかもしれません。

.PHONY: all
ifneq   "$(needs_made)" ""
all: $(needs_made)
else
all:;@echo 'Nothing to make!'
endif

 ifneqディレクティヴの`$(needs_made)'という変数参照を`$(strip $(needs_made))'というファンクションコールに置き換えればもっと信用できるスクリプトになります。
$(findstring find,in)
 infindが含まれるかを探してくれます。見つかれば値はfindになり、そうでなければ値は空っぽになります。文字列中に指定文字列があるかどうかを調べるにはこの関数を条件分岐の中で使います。だから次の二つの例では、

$(findstring a,a b c)
$(findstring a,b c)

`a'という値と(空っぽの文字列である)`'をそれぞれ生成します。findstringの実用法についてはフラグを調べるための条件分岐の項を見てください。
$(filter pattern...,text)
text中にあるpatternの単語に一致しない全ての空白で区切られた単語を削除して、一致する単語だけを返します。型(pattern)は前述のpatsubst関数で使った型と同様に`%'を使って書きます。filter関数は変数中にあるタイプの違う(ファイル名のような)文字列を締め出すのに使えます。 例えば、

sources := foo.c bar.c baz.s ugh.h
foo: $(sources)
        cc $(filter %.c %.s,$(sources)) -o foo

…とすると、`foo'`foo.c'`bar.c'`baz.s'`ugh.h'に依存して構成されるが、`foo.c'`bar.c'`baz.s'だけがコンパイラへのコマンドに指定されなければならない、という意味になります。
$(filter-out pattern...,text)
text中にあるpatternの単語に一致する全ての空白で区切られた単語を削除して、一致しない単語だけを返します。この関数はfilter関数の正反対になります。例えば、

objects=main1.o foo.o main2.o bar.o
mains=main1.o main2.o

…と与えておくと、以下のものは`mains'にない全てのオブジェクトファイルを含めたリストを生成します。

$(filter-out $(mains),$(objects))

$(sort list)
 listの単語を辞書順にソートして重複単語を削除します。出力は一つのスペースで区切られた単語のリストになります。だから、

$(sort foo bar lose)

…とすると`bar foo lose'という値を返します。  sortはついでに重複文字列を削除してくれるので、順番をソートするのに関係ない場合でもこの目的で使うこともできます。

 次に示すのはsubstpatsubstの実用例です。makeに依存関係を探させるディレクトリのリストを指定するのにmakefileでVPATH変数を使うと仮定します(VPATH: 全依存関係をPATHから探すの項を参照)。この例ではディレクトリのものと同じリストの中からCコンパイラにヘッダファイルを探させる方法を示しています。

 VPATHの値は`src:../headers'のようにコロンで区切られたディレクトリのリストです。はじめにコロンをスペースに変更するのにsubst関数を使います。


$(subst :, ,$(VPATH))

 これで`src ../headers'が生成されます。それから、各ディレクトリ名に`-I'フラグをつけるのにpatsubstを使います。この結果は次のようにCFLAGSという変数の値に追加して、自動的にCコンパイラに渡させることができます。


override CFLAGS += $(patsubst %,-I%,$(subst :, ,$(VPATH)))

 `-Isrc -I../headers'という文字列がこの前にCFLAGSに与えた値に追加されます。CFLAGSがコマンド引数で指定された場合も新しい値を使わせるのにoverrideディレクティヴを利用しています(override ディレクティヴの項を参照)。

ファイル名のための関数

 ビルトイン拡張関数のいくつかはファイル名の分析やファイル名のリストに特に関係しています。

 以下に示す関数はそれぞれ特定のファイル名変形を提供します。どの関数の引数も空白で区切られたファイル名の連続したものとして扱います。(前後の空白部分は無視されます。)連続するどのファイル名も同じ方法で変形されて、結果はファイル名の間にスペースを一つ挟んで鎖のように順番に並べたものになります。

$(dir names...)
 namesの中のそれぞれのファイル名のディレクトリ部分を抽出します。ファイル名のディレクトリ部分は最後のスラッシュより上の部分(にスラッシュを含んだもの)になります。ファイル名にスラッシュが含まれない場合はディレクトリ部分は`./'という文字列になります。例えば、

$(dir src/foo.c hacks)

…とすると結果は`src/ ./'になります。
$(notdir names...)
 namesの中のそれぞれのファイル名のディレクトリ部分以外を抽出します。ファイル名にスラッシュがなければ、変更なくそのままになります。また、最後にスラッシュがあるものは結果から削除されます。 ファイル名がスラッシュで終わるものは空っぽの文字列になりますが、引数として持つ空白で分けられたファイル名の数が必ずしも同じにならないため、これは不適切な方法ですが、他に妥当な選択肢が見つからないためこうしています。 例えば、

$(notdir src/foo.c hacks)

…とすると結果は`foo.c hacks'になります。
$(suffix names...)
 namesの中のそれぞれのファイル名のサフィックス部分(訳注:Windowsでいう拡張子部分)を抽出します。ファイル名にピリオドを含んでいれば、サフィックス(語尾)は常に最後のピリオドから始まり、そうでなければサフィックスは空っぽの文字列になります。このことはnamesがピリオドを含んでいなければたびたび結果が空白になったり、namesが複数のファイル名の時はもとより少ないファイル名になる可能性を示唆しています。 例えば、

$(suffix src/foo.c src-1.0/bar.c hacks)

…とすると、結果は`.c .c'になります。
$(basename names...)
 names内のファイル名の各々からサフィックス以外の部分を抽出します。ファイル名にピリオドがあればベース名(basename)は最後のピリオドの前の部分(で、ピリオドは含まないもの)になります。ディレクトリ部分のピリオドは無視されます。ピリオドがなければ、ベース名(basename)は完全なファイル名になります。 例えば、

$(basename src/foo.c src-1.0/bar hacks)

…とすると結果は`src/foo src-1.0/bar hacks'になります。
$(addsuffix suffix,names...)
 namesという引数は空白で区切られた名前のかたまりとして評価し、suffixは一つとして扱います。suffixの値は個々の名前の後ろにそれぞれ添えられて、名前の間を一つのスペースで繋いだもっと大きな名前を結果として返します。例えば、

$(addsuffix .c,foo bar)

…とすると結果は`foo.c bar.c'になります。
$(addprefix prefix,names...)
 namesという引数は空白で区切られた名前のかたまりとして評価し、prefixは一つとして扱います。prefixの値は個々の名前の前にそれぞれ前置きされて、名前の間を一つのスペースで繋いだもっと大きな名前を結果として返します。例えば、

$(addprefix src/,foo bar)

…とすると結果は`src/foo src/bar'になります。
$(join list1,list2)
 二つの引数の各単語同士を連結させます。(それぞれの引数から一つずつとった)二つの最初の単語が連結されて結果の最初の単語を形成して、二つの二番目の単語が結果の二番目の単語を形成して…というようになります。だから結果のn 番目の単語はそれぞれの引数のn 番目の単語からできます。もし一方の引数のほうが他方より単語数が多ければ、多い部分は変更がないまま結果にコピーされます。 例えば、`$(join a b,.c .o)'とすると`a.c b.o'になります。 リストの単語間の空白部分は保存されず、一つのスペースに置換されます。 この関数はdir関数とnotdir関数の結果をマージ(同化)して、二つの関数から作られたオリジナルのファイルリストを作成するのに使えます。
$(word n,text)
 textn番目の単語を返します。nの有効値は1から始まります。ntextの単語数より大きい場合は値は空っぽになります。例えば、

$(word 2, foo bar baz)

…とすると`bar'を返します。
$(wordlist s,e,text)
 textの中のsからeまでの(その番号自身を含めた)単語のリストを返します。seの有効値は1から始まります。stextの単語数より大きい場合は値は空っぽになり、etextの単語数より大きい場合はtextの終わりまでが返されます。seより大きければ、makeがこの二つを交換してくれます。例えば、

$(wordlist 2, 3, foo bar baz)

…とすると`bar baz'を返します。
$(words text)
 textの単語数を返します。だからtextの最後の単語は $(word $(words text),text)になります。
$(firstword names...)
 namesという引数は空白で区切られた名前のかたまりとして評価します。値はこのかたまりの一番最初の名前になり、残りの名前は無視されます。 例えば、

$(firstword foo bar)

…とすると結果は`foo'になります。$(firstword text)$(word 1,text)と同じですが、簡便性からfirstword関数を保持しています。
$(wildcard pattern)
 典型としてpatternは(シェルファイル名で使う型と同じような)ワイルドカードを含むファイル名の型です。wildcardの結果は型に一致する存在するファイル名が空白で分けられたリストになります。 これについてはファイル名にワイルドカードを利用するの項を見てください。

foreach 関数

 foreach関数は他の関数とは大きく違います。この関数は毎回代入が実行されるたびにテキストの一部分を繰り返し利用します。この機能はshシェルのforコマンドやCシェルcshforeachコマンドと似ています。

 foreach関数の構文は次に示すとおりです。


$(foreach var,list,text)

 varlistという最初の二つの引数は他の動作の前に展開されます。ここで注意しておいてほしいのは最後の引数textが同時に展開されないという事です。それで(変数参照が含まれていれば展開して変数名として)varという名前の変数にlistの値として展開された各単語を一つづつセットし、そのたびにtextを展開します。多分textにはその変数への参照を含めるので毎回展開内容が違います。

 textは結果としてlistの空白で区切られた単語の量と同じだけ展開されます。textの複数回の展開はスペースでつなげられ、それがforeachの実行結果になります。

 次の簡単な例では`files'という変数に`dirs'のリストにあるディレクトリの全ファイルのリストをセットします。


dirs := a b c d
files := $(foreach dir,$(dirs),$(wildcard $(dir)/*))

 ここでは`$(wildcard $(dir)/*)'textです。繰り返しの一巡目に`a'という値を見つけてそれをdirに与えて`$(wildcard a/*)'と同じ結果を生成し、二巡目には`$(wildcard b/*)'とした結果を、三巡目は`$(wildcard c/*)'とした結果を生成します。

 上の例は(`dirs'をセットする以外は)次のものと同じ結果になります。


files := $(wildcard a/* b/* c/* d/*)

 textが複雑になっても追加の変数に与えておけば読みやすくできます。


find_files = $(wildcard $(dir)/*)
dirs := a b c d
files := $(foreach dir,$(dirs),$(find_files))

 ここではこの方法に則ってfind_filesという変数を使いました。変数の値がforeachの制御下で再展開されるべき実際のファンクションコールを含んでいるので再帰展開変数を定義するために`='を使います。単純展開変数ではfind_filesの定義時にwildcardを一度呼び出すだけになってしまうからです。

 foreach関数は永久にvarという変数に効果を及ぼしません。このためファンクションコール以後のその変数の値と味は前のものと同じになります。もう一つのlistから取り出すのに使われたものはforeach関数の実行中の一定時間だけ効力を持つだけです。foreachの実行中のvarという変数は単純展開変数です。foreachのファンクションコール以前にvarが定義されていなかった場合、コール後も定義されていない状態になります。 変数の二つの味の項を見てください。

 変数名に複雑な変数の表現を使うことになった場合、多くの変なものが有効な変数名になって、意図したものと違うことになりうるので気をつけておかねばなりません。例えば、


files := $(foreach Esta escrito en espanol!,b c ch,$(find_files))

…とするのはfind_filesの値が`Esta escrito en espanol!' (es un nombre bastante largo,no?)という名前の変数を参照しているときは便利かもしれませんが、失敗を起こしやすくなります。

origin 関数

 origin(起源)関数は変数の値を扱うものではない、という点で他の多くの関数と違っています。つまり変数について何らかのことを知るためのものです。具体的にはどこから生じたかを教えてくれます。

 origin関数の構文は次のものです。


$(origin variable)

 variableは調べる変数の参照ではなくて変数の名前であることに注意しておいてください。だから通常は書くときに`$'とか括弧を使わないでしょう。(とはいえ対象とする名前を一定にさせない場合は変数参照を使っても構いません。)

 variableという変数がどういう風に定義されたかを知らせる文字列がこの関数の結果になります。次のようなものです。

`undefined'
 variableが全く定義されていない場合。
`default'
 CCなどのようにvariableがデフォルト定義だった場合。これについては暗黙ルールで使われる変数の項を見てください。
注意:デフォルトの変数を再定義していた場合、origin関数は後の定義の起源を調べて返します。
`environment'
 variableが環境変数として定義されていて、かつ`-e'オプションがオンになっていない場合(オプション要約の項を参照)。
`environment override'
 variableが環境変数として定義されていて、かつ`-e'オプションがオンになっている場合(オプション要約の項を参照)。
`file'
 variableがmakefile内で定義されていた場合。
`command line'
 variableがコマンドラインで定義されていた場合。
`override'
 variableがmakefile内のoverrideディレクティヴで定義されていた場合(override ディレクティヴの項を参照)。
`automatic'
variableが各ルールのコマンド実行のために定義された自動変数だった場合(自動変数の項を参照)。

 この情報は(好奇心目的以外には)主に変数の値が信用に足るものかどうかを決めるのに便利です。例えば仮に`foo'というmakefileがあってその中で`bar'という別のmakefileをインクルードしているとします。そして、`make -f bar'と実行した場合、環境変数にbletchという変数があっても`bar'でその変数を定義させたい。でも`foo'`bar'をインクルードする前にbletchが定義された場合はそれを`bar'で上書きさせたくない。こういう希望は`foo'overrideディレクティヴを使って、その定義が後の`bar'での定義よりも優位であると定めれば実現できます。しかし不幸にもoverrideディレクティヴはコマンドライン上の定義をも上書きしてしまいます。だから`bar'に次のものをインクルードします。


ifdef bletch
ifeq "$(origin bletch)" "environment"
bletch = barf, gag, etc.
endif
endif

 bletchが環境で定義されていれば、再定義し直します。

 `-e'の影響下において環境で定義されていても前のbletchの定義を上書きさせたい、という場合は、代わりにこう書くこともできます。


ifneq "$(findstring environment,$(origin bletch))" ""
bletch = barf, gag, etc.
endif

 この場合`$(origin bletch)'`environment'`environment override'を返せば再定義が行われます。 文字列を代入・分析する関数の項を見て下さい。

shell 関数

 shell関数はmakeの外界と接触するという点でwildcard関数(wildcardという関数の項を参照)だけは似ていますが、他の関数とは毛色が違います。

 shell関数はバッククォート(``')が多くのシェルで果たすコマンドの拡張(command expansion)と同じ機能を持ちます。つまり、引数を一つとってシェルコマンドとし、そのコマンドの出力を返します。このとき、関数のあった部分に代入させる前にmakeが結果に対して行う事は、ただキャリッジリターン(行の先頭に移動)とニューライン(改行)のペア、またはニューライン単体、を、空白文字一つに変換する事と、ついでに(キャリッジリターンと)ニューラインが結果の最後についていればそれを削除するという事だけです。

 shell関数を使って呼び出されるコマンドは、ファンクションコール展開時に実行され、それは多くの場合makefileが読み込まれた時です。例外として、ルールのコマンド内のファンクションコールはそのコマンドの実行時に展開され、これは他のものと同様にshellのファンクションコールにも適用されることです。

 ここにshell関数の利用例をいくつか示します。


contents := $(shell cat foo)

…とすると、contents`foo'の中身の各行を(ニューラインではなく)空白で区切ったものをセットします。


files := $(shell echo *.c)

…とすると、files`*.c'の展開結果をセットします。makeがとんでもなくおかしなシェルを使っているのでなければこの結果は`$(wildcard *.c)'と同じになります。(訳注:MS-DOS/MS-Windowsのcommand.com/cmd.exeをシェルにした場合はこうなりません。)


最初,,,最後のページ,目次 に移動.