プログラミングユーティリティ

複数のプログラムおよびライブラリの形式を管理する

前述の 2 つの例は、開発、デバッグ、プロファイルを別々に実行する場合には適しています。しかし、形式を切り替えるごとにすべてのオブジェクトファイルが再コンパイルされるので、コンパイル時間が長くなるという欠点があります。以下の 2 つの例は、3 つの形式すべてを独立した構成要素として別々に管理する方法を説明しています。

3 つの形式のオブジェクトファイルが同一のディレクトリにあることによる混乱を避けるため、デバッグ用およびプロファイル用のオブジェクトファイルと実行可能ファイルをサブディレクトリに保存できます。ただし、オブジェクトファイルのリストの各エントリに、サブディレクトリ名を接頭辞として追加する必要があります。

パターン置換マクロ参照

パターン置換マクロ参照は、形式および機能が接尾辞置換の参照と同様です。パターン置換参照を使用して、接頭辞、接尾辞のいずれかまたは両方を、マクロの値中で一致する語に追加または置換できます。


注 -

パターン置換マクロ参照は、パターンマッチングの規則と同様に、旧バージョンの make で使用することはできません。


パターン置換参照は、以下の形式で記述します。

$(macro:p%s =np%ns)

ここで、p は置換対象の既存の接頭辞 (ある場合)、s は置換対象の既存の接尾辞 (ある場合)、np および ns はそれぞれ新しい接頭辞および接尾辞、% はワイルドカードです。パターン置換は、値 p%s に一致するすべての語に適用されます。

SOURCES= old_main.c old_data.c moon 
OBJECTS= $(SOURCES:old_%.c=new_%.o) 
all: 
        	@echo $(OBJECTS)

この例は、以下のような結果になります。

$ make 
new_main.o new_data.o moon

= 記号の右側 (置換後の語) では、ワイルドカードの % を任意の数だけ必要に応じて使用できます。以下に例を示します。

...
OBJECTS= $(SOURCES:old_%.c=%/%.o)

この置換は、以下のような結果になります。

main/main.o data/data.o moon

ただし、パターン置換マクロ参照は、パターンマッチングの規則を指定しているターゲットエントリの依存関係を示す行では使用しないでください。使用した場合は、マクロとターゲット (または依存関係) のどちらにワイルドカードが適用されるかを make が特定できないため、衝突が生じます。

OBJECT= .o 

x: 
x.Z: 
        	@echo correct 
%: %$(OBJECT:%o=%Z)

このメークファイルは、makex.Z から x を構築するために記述したものです。しかし、依存関係の行に複数含まれている % のうちどれをパターンマッチングの規則で使用するかを make が特定できないため、パターンマッチングの規則は認識されません。

形式が複数あるプログラム用のメークファイル

次に示すのは、複数の形式が別々に管理されている C プログラム用のメークファイルの例です。まず .INIT という特殊ターゲットが、debug_dir および profile_dir というサブディレクトリを (まだ作成されていなければ) 作成します。これらのサブディレクトリには、デバッグ用およびプロファイル用のオブジェクトファイルと実行可能ファイルが含まれます。


注 -

make は、メークファイルが読み込まれた後に .INIT ターゲットの規則を実行します。


実行可能ファイルは、VARIANTS.o マクロで指定されているオブジェクトファイルに依存します。このマクロにはデフォルトでは OBJECTS の値が指定され、後に条件付きマクロ定義によって値が再度割り当てられます。このとき、debug_dir/ または profile_dir/ の接頭辞が追加されます。サブディレクトリ内の実行可能ファイルは、同じサブディレクトリ内に構築されるオブジェクトファイルに依存します。

次に、両方のサブディレクトリに含まれているオブジェクトファイルが作業中のディレクトリにあるソース (.c) ファイルに依存するように、パターンマッチングの規則が追加されます。これは、1 つのソースファイル群から 3 つの形式すべてを構築し管理するために必要です。

最後に、サブディレクトリの debug_dirprofile_dir は一時的に作成されたものであるため、clean ターゲットが更新されてこれらのサブディレクトリとその内容が再帰的に削除されます。これは、各形式用のサブディレクトリは一時的なものであるため、派生ファイルはそのソースと同一のディレクトリ内に構築するという慣例に従っています。

表 4-14 デバッグ用およびプロファイル用のプログラムを別々に扱うためのメークファイル
# デバッグ用およびプロファイル用のプログラムを
# 別々に扱うためのメークファイル

CFLAGS= -O 

SOURCES= main.c rest.c 
OBJECTS= $(SOURCES:%.c=$(VARIANT)/%.o) 
VARIANT= .

functions profile debug: $$(OBJECTS) 
 $(LINK.c) -o $(VARIANT)/$@ $(OBJECTS) 

debug := VARIANT = debug_dir
debug := CFLAGS = -g 
profile := VARIANT = profile_dir
profile := CFLAGS = -O -pg 

.KEEP_STATE:
.INIT:  profile_dir debug_dir
profile_dir debug_dir:
 test -d $@ || mkdir $@ 
 $$(VARIANT)/%.o: %.c 
 $(COMPILE.c) $< -o $@ 
clean:  
 rm -r profile_dir debug_dir $(OBJECTS) functions

複数の形式があるライブラリ用のメークファイル

複数の形式があるライブラリ用のメークファイルも、同様の方法で変更します。

# 複数の形式のライブラリを別々に扱うためのメークファイル

CFLAGS= -O 

SOURCES= main.c rest.c 
LIBRARY= lib.a 
LSOURCES= fnc.c 

OBJECTS= $(SOURCES:%.c=$(VARIANT)/%.o) 
VLIBRARY= $(LIBRARY:%.a=$(VARIANT)/%.a) 
LOBJECTS= $(LSOURCES:%.c=$(VARIANT)/%.o) 
VARIANT= .

program profile debug: $$(OBJECTS) $$(VLIBRARY) 
         	$(LINK.c) -o $(VARIANT)/$@ $< 

lib.a debug_dir/lib.a profile_dir/lib.a: $$(LOBJECTS) 
         	ar rv $@ $? 

$$(VLIBRARY)($$(VARIANT)%.o): $$(VARIANT)%.o 
        	@true 
profile := VARIANT = profile_dir
profile := CFLAGS = -O -pg 

debug := VARIANT = debug_dir
debug := CFLAGS = -g 

.KEEP_STATE:
profile_dir debug_dir:
        	test -d $@ || mkdir $@ 
$$(VARIANT)/%.o: %.c 
        	$(COMPILE.c) $< -o $@

複数の形式を管理するこの手法は、便利ですがやや複雑です。説明を簡潔にするため、この手法は以下の例では省略しています。