変数とは変数の値と呼ばれるデータの文字列に取って代わらせるのにmakefile内で定義する名前のことです。明示的に値を要求する事でターゲットや依存関係、コマンドなどのmakefileのさまざまな場所で代用できます。
(別のmake
では変数はマクロと呼ばれています。)
変数と関数はmakefileのどこにあっても読み込み時に展開されますが、例外として変数定義で`='とした右手(右辺)と、define
ディレクティヴを使った変数定義の本体(中身)では展開しません。
変数にはファイル名や、コンパイラや実行するプログラムに渡すオプション、ソースを探す対象のディレクトリ、出力ディレクトリ、その他どんなものでも、リストにして入れておき、変数名をその代表として使うことができます。
変数の名前は空白を前後につけず、`:',
`#', `='を含まない文字の並びであればどんなものでも構いませんが、英文字と数字と下線以外を含む変数名は将来的に特別な意味を持たせるつもりですし、環境を通してそういう文字列をサブのmake
に渡すことができないシェルもあるため、避けるべきです
(サブmake
に変数を伝えるの項を参照)。
変数名は小文字と大文字を区別します。つまり、`foo'と`FOO'と`Foo'という名前はそれぞれ全く違う変数を参照します。
変数名に大文字を使うのは伝統的な方法ですが、makefileの内部利用が目的の変数には小文字の変数名を使い、大文字の変数名は暗黙のルールを制御する媒介変数(parameters)やコマンドオプションで上書きすべき媒介変数(parameters)のためにとっておく事をお勧めします(変数の上書きの項を参照)。
たくさんの変数がありますが、その中には変数名がたった一文字の句読文字(a punctuation character)だけのものや、かなり多くの文字からできているものがあります。これらは自動変数というもので、それぞれに特別な用途があります。これについては自動変数の項を見てください。
変数の値に置き換えさせるようにするには、ドル記号の後に括弧か大括弧(ブレース;"{ }"の事)の中に変数を書きます。つまり、変数foo
の有効な参照は`$(foo)'と`${foo}'になります。この`$'にはこのように特別な意味があるため、ファイル名やコマンドに一文字のドル記号を使うには`$$'と書かなければなりません。
ターゲットや依存関係、コマンドや多くのディレクティヴ、さらには新しい変数の値など、どんな場所にでも変数参照を書くことができます。次に示すのはプログラム中の全オブジェクトを変数に格納する、というごくありふれた事の一例です。
objects = program.o foo.o utils.o program : $(objects) cc -o program $(objects) $(objects) : defs.h
変数参照は厳密には本文を置き換えることで機能しています。このため、
foo = c prog.o : prog.$(foo) $(foo)$(foo) -$(foo) prog.$(foo)
というルールは`prog.c'というCプログラムをコンパイルするのに使えます。変数値の前にある空白は変数の処理では無視するため、foo
は正確に`c'という値になります。(実際にはこんなやり方でmakefileを書かないように!)
ドル記号の後ろにドル記号と開き括弧("(")と開き大括弧("{")以外の文字を続けたものは単字変数の名前として扱います。このため、x
という変数を参照するのに`$x'とすることもできますが、自動変数を除く変数では極力こうする事は控えて下さい(自動変数の項を参照)。
GNU make
では変数に値を与える方法が二つあり、私たちはこれを変数の二つの味(flavors)と呼んでいます。この二つの味は定義方法と展開動作で区別します。
変数の一つ目の味は再帰展開変数(recursively expanded variable)です。`='を使う行(変数の準備の項を参照)で定義したものとdefine
ディレクティヴ(一字一句違わずに変数を定義するの項を参照)を使って定義したものがこの種の変数になります。指定した値は指定どおりに(一字一句同じに)格納され、値の中に別の変数への参照があろうと、(文字列を展開していく過程で)値に置き換える処理をするまでは参照が展開されません。この処理を指して再帰展開(recursive expansion)と呼んでいるのです。
例えば、
foo = $(bar) bar = $(ugh) ugh = Huh? all:;echo $(foo)
では、`$(foo)'が`$(bar)'を展開し、これがまた`$(ugh)'を展開してこれが`Huh?'を展開するため、最終的に`Huh?'をエコーすることになります。
この変数の味は、他のmake
が唯一サポートしている方の機能です。これは有利でもあり不利でもあることです。(大多数の方が言うであろう)有利な点とは、
CFLAGS = $(include_dirs) -O include_dirs = -Ifoo -Ibar
とすればやってほしいことをやってくれる事です。すなわち、`CFLAGS'がコマンドで展開された時に`-Ifoo -Ibar -O'を展開します。特に不利な点は、次のような場合、変数の終わりに何かを添える事ができない点です。
CFLAGS = $(CFLAGS) -O
こうすると変数を展開する時に無限ループになってしまいます。(実際にはmake
が無限ループを看破してエラーを報告してくれます。)
もうひとつ不利な点は、定義内に参照している関数(テキスト変形関数の項を参照)が展開時に毎回実行されてしまう事です。このためにmake
の動作が鈍る上、悪いことにいつ呼び出されて何度実行されるかという事さえ制御が簡単ではないため、wildcard
関数とshell
関数を使うととんでもない結果を招く事になります。
「単に変数を展開させる」というもうひとつの味を使えば再帰展開変数の不便極まりない所と先の問題を完全に避ける事ができます。
単純展開変数(Simply expanded variables)は`:='を使って定義します(変数の準備の項を参照)。 単純拡張変数では値は定義された時点で読み込まれて、別の変数にある参照も関数も全て一気に展開します。記述したテキストを展開した結果が単純展開変数の実際の値になります。この値には全く別の変数への参照が含まれず、この変数が定義された時にできたものを値として格納しています。そのため、
x := foo y := $(x) bar x := later
は、次のものと同等です。
y := foo bar x := later
単純変数を参照すると、値は一字一句同じに置き換えられ(代用され)ます。
次に示すのはもう少し複雑な例で、shell
関数とともに`:='を利用する方法を説明するものです。(shell
関数を見てください。) このサンプルはさらに階層が下がると変更されるMAKELEVEL
変数の利用法にもなっています。(サブmake
に変数を伝えるの項を見ればMAKELEVEL
についての情報があります。)
ifeq (0,${MAKELEVEL}) cur-dir := $(shell pwd) whoami := $(shell whoami) host-type := $(shell arch) MAKE := ${MAKE} host-type=${host-type} whoami=${whoami} endif
`:='のこういう使い方の有利な点は、典型的な`ディレクトリに入り込む'コマンドが以下のようになる事です。
${subdirs}: ${MAKE} cur-dir=${cur-dir}/$@ -C $@ all
単純展開変数は多くのプログラム言語の変数のように動作してくれるので、普通これを使えば複雑なmakefileプログラミングの流れが見え易くなります。これを使えば自分自身の値(や、任意の方法で展開を行う関数のどれかを使って処理した値)で変数を再定義したり、展開(を行う)変数をもっと有効に使う事が可能になります(テキスト変形関数の項を参照)。
先行空白(leading whitespace)を変数の値に入れておくのにこの変数を使う事もできます。先行空白文字は変数参照と関数呼び出しの代用の前に入力内容から廃棄されるものですが、これで以下のように先行スペースを変数参照で保護して変数の値にインクルードすることが可能になるのです。
nullstring := space := $(nullstring) # end of the line
ここではspace
変数の値は正確に一つのスペースになります。`# end of the line'というコメント部分は意思をはっきりさせるために書いています。後ろに続く空白文字は変数の値から取り除かれないので、(ずっと見づらくなりますが)行末に空白を置いても同じ効果があります。変数の値の最後に空白を置く場合、それをちゃんと明確にしておくために行末あたりにコメントをつけると良いです。反対に変数の値の最後に空白をつけたくない場合、絶対にこんな風に適当な空白の後にでたらめなコメントをつけないようにしなければなりません。
dir := /foo/bar # directory to put the frobs in
これではdir
という変数の値は(後ろに空白がくっついて)`/foo/bar 'というものになってしまい、意図しない結果を招く事になりかねません。(この定義を`$(dir)/file'というように使う事を考えてみれば、どうなるか想像できるでしょう!)
また別の動作をする変数用のオペレータに`?='というものがあります。まだ定義されていない場合だけ効果があるため、このオペレータを「条件分岐変数割り当てオペレータ(conditional variable assignment operator)」と言います。
FOO ?= bar
この命令文は次のもの全く同じです(origin
関数の項を参照)。
ifeq ($(origin FOO), undefined) FOO = bar endif
注意:値を空っぽにしてある変数でも定義されていると考えるので、`?='はそういう変数には値を代入しません。
この項では変数を参照するのにもっと自由な方法を採るのに便利な、高度な機能をいくつか説明します。
変数の値を変更してから代入するには代入参照(substitution reference)を使います。`$(var:a=b)' (または `${var:a=b}')という書式は、varという変数の値の中にある各単語の末尾にaがあればすべてbに置き換えた後、その結果の文字列を代入するという意味になります。
"単語の末尾"と言ったのは、aを置換するにはその後に空白が続くか、値の終端でなければならず、値の中でそれ以外の場所にあるaは変更されない、と言いたかったからです。
例えば、
foo := a.o b.o c.o bar := $(foo:.o=.c)
は、`bar'に`a.c b.c c.c'を入れることになります。変数の準備の項を見てください。
代入参照は実際には展開関数patsubst
の略語です(文字列を代用、分析する関数の項を参照)。代入参照をpatsubst
と同じような機能にしたのは他の製品のmake
との互換性のためです。
もう一つの形式で代入参照を使えばpatsubst
関数の力を最大限に活かせます。書式は`$(var:a=b)'と、前述のものと同様ですが、今度はaの中に`%'という文字が一文字入っていなければなりません。こうすると`$(patsubst a,b,$(var))'と同等になります。patsubst
関数については変数を代用、分析する関数の項で説明しています。
例えば、
foo := a.o b.o c.o bar := $(foo:%.o=%.c)
は、`bar'に`a.c b.c c.c'を与えます。
計算された変数名とは洗練されたmakefileプログラミングをする時にのみ必要とされる複雑な概念の事です。ドル記号を変数名にする事ができるのを知らないと変な結果を招く事になるのでこれを考えないほうがいいですが、何でも知りたがるタイプの方やこれがどう動くのかに深く興味を持っている方はこの文章を読み進めて下さい。
変数は変数名の中でも参照される事があります。これを計算された変数名(computed variable name)と呼んだり、入れ子式変数参照(nested variable reference)と呼んだりします。
例えば、
x = y y = z a := $($(x))
は、a
を`z'として定義します。なぜなら、`$($(x))'の中の`$(x)'に`y'が展開されるために`$($(x))'が`$(y)'を展開してまたそれが`z'を展開することになるからです。ここでは参照する変数名が前もって明示的に定まっておらず、その変数名は`$(x)'の展開で計算(処理)されて決まります。`$(x)'という参照ははここでは別の変数参照の入れ子になっています。
前の例は二階層の入れ子でしたが何階層でもできます。たとえば、次に示すのは三階層の例です。
x = y y = z z = u a := $($($(x)))
今回は一番内側の`$(x)'が`y'を展開して`$($(x))'が`$(y)'を展開することになり次にまた`z'が展開されて、最後には`$(z)'が`u'になります。
変数名で再帰展開変数の参照を使うと、よくやるやり方で参照が再展開できます。例えば、
x = $(y) y = z z = Hello a := $($(x))
は、a
を`Hello'と定義します。`$($(x))'が`$($(y))'になりそれが`$(z)'になり、それが`Hello'になるためです。
修正された参照と関数実行(see section テキスト修正関数)も他の参照と全く同じように入れ子式変数参照に含む事ができます。例えばsubst
関数(文字列を代入・分析する関数の項を参照)を使うなら次のようにします。
x = variable1 variable2 := Hello y = $(subst 1,2,$(x)) z = y a := $($($(z)))
は、最終的にa
を`Hello'と定義します。誰がこんなことに入れ子式に入り組んだ参照を書きたがるかは甚だ疑問ですが、とにかく次のように動作します。まず`$($($(z)))'が`$($(y))'を展開してから`$($(subst 1,2,$(x)))'になります。次にこれがx
から`variable1'という値を受け取って、代用作業で変形して`variable2'にして`$(variable2)'という一つの単純な変数参照を示す完全な文字列になるようにします。そして、最後に残る変数参照は`Hello'という値になります。
計算された変数名ではただ一つの変数参照だけで変数名を構成する必要はありません。定数(不変)式の文章と同じように複数の変数参照を格納する事が可能です。
例えば、
a_dirs := dira dirb 1_dirs := dir1 dir2 a_files := filea fileb 1_files := file1 file2 ifeq "$(use_a)" "yes" a1 := a else a1 := 1 endif ifeq "$(use_dirs)" "yes" df := dirs else df := files endif dirs := $($(a1)_$(df))
…とすると、dirs
の値をuse_a
とuse_dirs
の状態に応じてa_dirs
か1_dirs
かa_files
か1_files
のどれかと同じ値にします。
計算された変数名は代入参照でも利用できます。
a_objects := a.o b.o c.o 1_objects := 1.o 2.o 3.o sources := $($(a1)_objects:.o=.c)
…とすると、sources
をa1
の値に応じて`a.c b.c c.c'か`1.c 2.c 3.c'かのどちらかを値として定義します。
入れ子式変数参照のこういう利用方法での唯一の制約は、呼び出す関数の名前の一部としては指定できないという事です。これは関数名を識別する作業が入れ子参照の展開の前に行われるためです。
例えば、
ifdef do_sort func := sort else func := strip endif bar := a d b g q c foo := $($(func) $(bar))
…とすると、`a d b g q c'をsort
かstrip
かどちらかの関数の引数にしようとするのではなく、`sort a d b g q c'か`strip a d b g q c'かどちらかの変数の値を`foo'に与えようとします。機能の制約をなくす方が良いと思うなら、そうすることもできます。
次にあるように、変数割当ての左辺やdefine
ディレクティヴにおいても計算された変数名を利用できます。
dir = foo $(dir)_sources := $(wildcard $(dir)/*.c) define $(dir)_print lpr $($(dir)_sources) endef
この例では`dir'と`foo_sources'、`foo_print'という3つの変数を定義しています。
注意:入れ子式変数参照(nested variable references)と再帰展開変数(recursively expanded variables)(変数の二つの味の項を参照)はmakefileプログラミングをする時はどちらも複雑な方法で一緒に使いますが、全く別物です。
変数に値を与える方法は何種類かあります。
make
を実行するときには上書き値を使って指定できます。
変数の上書きの項を見てください。
make
の変数になります。
環境からの変数の項を見てください。
makefileで変数をセットするには、変数名で始まってその後に`='か`:='が続く行を書いてください。`='と`:='のどちらを書いても、同じ行のその次の部分が値になります。例えば、
objects = main.o foo.o bar.o utils.o
…とすると、objects
という変数名を定義します。変数名の前後と`='の直後の空白は無視されます。
`='で定義した変数は再帰展開変数です。 `:='で定義した変数は単純展開変数で、これで定義した変数では変数の定義が確立する前に先に展開されることになる変数参照(例…例えば自分と同名の変数参照)を含めることができます。変数の二つの味の項を見てください。
変数名には変数参照と関数を含めることもでき、そういう使われ方をした変数参照と関数は行読み込み時に実際に利用する変数名を知るために展開されます。
変数の値の長さに制限はなく、コンピュータのスワップ領域が許す限り指定できます。変数定義が長くなった時は、定義が見やすいようにバックスラッシュと改行を続けて書いたものを挟んで複数行に分けると良いです。こうするとmake
の働きに影響させずにmakefileを読みやすくすることができます。
セットしなかった変数名の大部分は空っぽの文字列が値とみなされます。一部の変数名は空っぽではなくてビルトインの初期値を持っていますが、そういう変数でも普通に値をセットできます(暗黙ルールに用いられる変数の項を参照)。一部の特別な変数はそれぞれのルールで新しい値が自動的にセットされ、こういう変数を自動変数といいます(自動変数の項を参照)。
今までにセットされていない場合だけ変数に値を与えたいのなら、`='の代わりに`?='という速記のオペレータを使うと実現できます。`FOO'という変数に対する以下の二つのセットの仕方は同じ意味になります(origin
関数の項を参照)。
FOO ?= bar
上が一つ目、下が二つ目です。
ifeq ($(origin FOO), undefined) FOO = bar endif
既に定義されている変数の中身をさらに追加すると都合が良い事が多々あります。次のように`+='を含む行を使えばこうすることができます。
objects += another.o
こうすると、objects
変数の値を保ちつつ、(空白を一つつけた後に)`another.o'というテキストを追加します。だから、
objects = main.o foo.o bar.o utils.o objects += another.o
…とするとobjects
を`main.o foo.o bar.o utils.o another.o'とセットします。
`+='の利用結果は以下と同じようになります。
objects = main.o foo.o bar.o utils.o objects := $(objects) another.o
ただし複雑な値を利用する時は`+='が重宝します。
当の変数が前に定義されていないものだった時は`+='は、再帰展開変数を定義する`='と全く同じような動作をします。ですが、前に定義がある場合、`+='の正確な動作はもともと定義した変数がどちらの味かで決まります。変数の二つの味については変数の二つの味の項に説明があります。
`+='で変数の値を追加すると、本質的にはmake
は変数の初期値に最初からそういうテキストがついていたかのように動作します。はじめに`:='で定義してある場合は単純展開変数になります。つまりその場合の動作は`+='が単純展開定義を追加して、`:='が動作する通りに、古い値を添える前に展開を行います(変数の準備の項に`:='の詳細な説明があります)。
実際、
variable := value variable += more
…とすると、下のものと正確に同一の動作になります。
variable := value variable := $(variable) more
一方`+='を充てる変数が、最初に単なる`='を使って再帰展開になるように定義したものだった場合はmake
の動作が少しだけ違うものになります。再帰展開変数を定義した時、make
はすぐにはセットした値を変数や関数の参照に対して展開しないことになっていました。その代わりに、新しい変数を参照するときはテキストの内容を一字一句同じに蓄え、変数や関数の参照を保持しておいて後で展開するようにするのです(変数の二つの味の項を参照)。再帰展開変数に`+='を使うと、make
がこの展開されていないテキストに、指定した新しいテキストを添付します。
variable = value variable += more
…というのは大体次のものと同等です。
temp = value variable = $(temp) more
ただし、当然ですがtemp
という変数を定義しなくても済みます。
これの価値は変数の古い値に変数参照が含まれていた場合に発揮されます。
このことを次の一般例から理解しましょう。
CFLAGS = $(includes) -O ... CFLAGS += -pg # enable profiling
最初の行ではincludes
という別の変数への参照をもつCFLAGS
変数を定義します。(CFLAGS
はCコンパイル作業用のルールで使われるものです。これについては暗黙ルールのカタログの項を見てください。)
`='を使ってCFLAGS
を再帰展開変数として定義すると、`$(includes) -O'はCFLAGS
の定義をmake
が処理する時には展開されません。このため、この段階で値に影響を与えるincludes
が定義されていなくても良く、CFLAGS
が参照されるまでに定義されてさえいれば良いのです。CFLAGS
に`+='を使わずに値を付加しようとするなら、このようになるでしょう。
CFLAGS := $(CFLAGS) -pg # enable profiling
かなり近くはあるのですが、まったく希望通りではありません。`:='を使うとCFLAGS
は単純展開変数として再定義されてしまい、make
は
変数を準備する前に`$(CFLAGS) -pg'というテキストを展開してしまいます。includes
がこの段階でまだ定義されていなければ` -O -pg'という結果を得ることになり、後の部分で定義したincludes
は全く効果を持たなくなります。逆に言えば`+='を使えば`$(includes) -O -pg'という展開されていない値をCFLAGS
にセットできるのです。こうしてincludes
への参照を保存しておくから、後のどんな場所でincludes
が定義されていても`$(CFLAGS)'のような参照でもその値が使えるのです。
override
ディレクティヴ
コマンド引数で変数をセットすると(変数の上書きの項を参照)、その場合もともとのmakefileの式は無視されます。コマンド引数でセットされていてもmakefileのほうを使いたい場合は以下の一文のようにoverride
ディレクティヴを使えばこれを実現できます。
override 変数 = 値
または、
override 変数 := 値
コマンド行で定義された変数に中身を上乗せしたい場合は、次の方法をとります。
override 変数 += 追加文
変数にテキストを上乗せするの項を見てください。
override
ディレクティヴはmakefileとコマンド引数間の争い(相互のやり取り)での段階的拡張(escalation)が目的で考えられたわけではありません。あくまでコマンド引数でユーザーが指定した値に追加して変更を加えるために発明された方法なのです。
例えば仮に`-g'スイッチをCコンパイラ実行時は必ず使いたいが、ユーザーにはいつもどおりのスイッチをコマンド引数に指定できるようにさせたいとします。次のようにoverride
ディレクトリを使えばこれが可能になります。
override CFLAGS += -g
override
ディレクティヴはdefine
ディレクティヴとも併用できます。次のものは期待どおりの動作をしてくれます。
override define foo bar endef
define
についての情報は次の項を見てください。
変数の値をセットするもう一つの方法としてdefine
ディレクティヴの利用があります。このディレクティヴは独特な構文を持っていて、値に改行文字を含めることができるのでコマンド連鎖の缶詰を定義するのに便利です(「コマンド連鎖の缶詰」を定義するの項を参照)。
define
ディレクティヴと同じ行には変数名が続くだけで他には何もなく、変数に与える値は後に続く行にあります。値の最後を示すものはendef
という単語だけからなる行です。define
は構文の違いは別として`='と同様に動作します。つまり、このディレクティヴは再帰展開変数を作成します(変数の二つの味の項を参照)。変数名には関数と変数の参照を含めることもでき、こうするとディレクティヴが読み込まれた時に実際に利用する変数名を知るために展開されます。
define two-lines echo foo echo $(bar) endef
普通の式では改行を値に含めることができませんが、define
では値の各行を区切っている改行は変数の一部になります(ただしendef
の前にある最後の改行と、それ自身は例外として値の一部にはなりません)。
先の例では機能としては次のものと同等です。
two-lines = echo foo; echo $(bar)
そうなるのはセミコロンで区切られた二つのコマンドは二つに分かれたシェルコマンドとたいへんよく似た動作をするからですが、注意しておいてほしいのは二行に分けるとmake
がシェルを二度起動させ、各行で独立した一つのサブシェルを実行するという意味になる点です。
これについてはコマンドの実行の項を見てください。
コマンド行での変数定義よりも優先でdefine
を使って変数定義をしたい場合は、define
ディレクティヴと一緒にoverride
ディレクティヴを使えば実現できます。
override define two-lines foo $(bar) endef
これについてはoverride
ディレクティヴの項を見てください。
make
における変数にはmake
が動作する環境からの変数も使えます。make
がはじめに起動したときに調べる環境変数はどれも同じ変数名と値を持ったmake
用の変数に変形されます。ただし、makefileでの明示的な式やコマンド引数を使うと環境の値を上書きします。(`-e'フラグを指定した場合は環境からの値がmakefileの式を上書きします。これについてはオプション要約の項を見てください。ただ、これはあまり良い習慣ではありません。)
このため、CFLAGS
変数を環境に準備しておけば好みのスイッチを大部分のmakefile内の全部のCコンパイル作業で使わせることができるようになります。makefile内で他の目的で使う事がありえないとわかっている変数は、標準として、または慣習的な目的で使っても差し支えありません。(ただし、これは総合的に見れば確実ではありません。なぜならCFLAGS
を明示的にセットしていて環境の値が影響しないmakefileもあるからです。)
make
が再帰呼び出しされると、外部呼び出しの変数定義は環境を通して内部呼び出しに渡されます(make
の再帰利用の項を参照)。デフォルトでは環境かコマンド行で与えられた変数だけが、再帰呼び出しされたmake
に渡されますが、export
ディレクティヴを使えば他の変数も渡せます。
これについてはサブmake
に変数を伝えるの項で明細に書かれています。
環境からの変数には別の使い方もありますがお薦めしません。制御外でセットアップされる環境変数に動作が依存してしまうと、同じmakefileでも異なるユーザーが使えば違った結果になってしまうため、これはmakefileを記述する上で賢い方法とはいえません。これは大部分のmakefileの根本的な目的に反するものだからです。
このような問題は特にSHELL
という変数であり得る事でしょう。この変数は通常、ユーザーが選んだ対話型シェルを指定するために環境に存在しています。make
にこの選択肢を作用させるのは非常に望ましくない事と思います。だからmake
では動作環境の値を無視します(が、MS-DOSとMS-Windowsでは例外としてSHELL
が普通指定されていません。これについてはコマンドの実行の項を見てください)。
make
の変数値はどこで評価されるかを(、当然ですが、置き換え時以外は)どの変数も考えないので、たいていはグローバルになります。その例外の一つが自動変数です(自動変数の項を参照)。
もう一つの例外はターゲット特有の変数値(target-specific variable values)です。この機能を使えば同じ変数でもmake
がビルド中のターゲットによって違う値を定義することができます。自動変数と同様にこれらの値は一つのターゲットコマンドスクリプト(と別のターゲット特有の式中)でのみ有効になります。
ターゲット特有の変数値は次のようにセットしてください。
ターゲット ... : 変数の式
または次のようにしてください。
ターゲット ... : override 変数の式
複数のターゲット値ではターゲット特有の変数値をターゲットリストのそれぞれに対して個々に作成します。
変数の式は有効な式であればどんな形でも構いません。つまり、再帰(`=')、スタティック(`:=')、付加(`+=')、条件分岐(`?=')のいずれでも可能です。変数の式にあるすべての変数はターゲットの処理中に評価されます。このため、以前に定義した、ターゲット特有の変数値は効果を持ちます。注意しておいてほしいのは、この変数は実際は「グローバル」の値とは別個のものであるということです。つまり二つの変数が同じ味(再帰またはスタティック)である必要はないのです。
ターゲット特有の変数は他の変数と同じ優先度になります。コマンド行(と、さらに`-e'の影響下においては環境)で与えられる変数はそれよりも高いものになります。
override
ディレクティヴを指定すればターゲット特有の変数値を好きな優先順位に出来ます。
ターゲット特有の変数にはもう一つだけ特別な機能があります。その機能とはターゲット特有の変数を定義する時にそのターゲットの全依存関係に(それ自身のターゲット特有の変数値で上書きしなければ)変数の値が影響する、という事です。だから例えば、
prog : CFLAGS = -g prog : prog.o foo.o bar.o
…というような命令文では`prog'内のコマンドスクリプトではCFLAGS
に`-g'をセットしますが、それに加えて`prog.o'と`foo.o'と`bar.o'を作成するコマンドスクリプトと、それ以下の依存関係を作成するどのコマンドスクリプトにも、CFLAGS
に`-g'をセットすることになります。
GNU make
ではターゲット特有の変数値(ターゲット特有の変数値の項を参照)に加えて、型特有の変数値(pattern-specific variable values)もサポートしています。この形式を使うと指定した型に一致するすべてのターゲットを対象に変数を定義できます。こうやって定義した変数を調べるのは、そのターゲットで明示的に定義してあるターゲット特有の変数を調べた後、それから親ターゲットで定義されたターゲット特有の変数を調べる前です。
型特有の変数値はこのようにセットします。
型 ... : 変数の式
またはこのようにします。
型 ... : override 変数の式
型に入るのは"%"を使う型です。ターゲット特有の変数値のように複数の型を書いた場合はそれぞれの型に個々に型特有の変数値を作成します。変数の式は有効な式であればどんな形でも構いません。override
を指定しなければコマンド行での変数定義が優先されます。
例えば、
%.o : CFLAGS = -O
…とすると、%.o
という型に一致する全てのターゲットに対してCFLAGS
という変数に`-O'という値を代入します。