web-dev-qa-db-ja.com

GNU Makeのワイルドカードターゲットの適切な方法

ソースファイルとオブジェクトファイルを分離してMakefileを書き込もうとしていますが、これを実現する適切な方法がわからないようです。私には2つの方法がありますが、誰かがこれを行うための「正しい」方法を指摘できることを望んでいます。

私のプロジェクトはsrcフォルダーとobjフォルダーに分かれており、Makefileはこれらと同じレベルにあります。

最初の方法では、ワイルドカード関数を使用してsrc内のソースファイルを検索し、次にテキスト置換を使用して対応するオブジェクトファイルを決定します。

SRC = $(wildcard src/*.cpp)
OBJ = $(SRC:.cpp=.o)

prog: $(OBJ)
       $(CC) $(CFLAGS) $(LDFLAGS) $(LIBS) -o prog $(patsubst src/,obj/,$(OBJ))

%.o: %.cpp
     $(CC) $(CFLAGS) -c $< -o $(COMPILE)/$(@F)  

これは機能しているようですが、make progを実行するたびに、すべてのオブジェクトファイルが再コンパイルされます。 OBJ変数はすべてのオブジェクトの前にsrc/を持っている必要があります。そうしないと、「ターゲットを作成するルールがありません」というメッセージが表示されます。プラス面として、progターゲットのpatsubstを使用して、オブジェクトファイルを簡単に指定できます。

2番目の方法も同様ですが、OBJ変数でvpathとテキスト置換を使用します。

 vpath = %.cpp src
 vpath = %.o obj

 SRC = $(wildcard src/*.cpp)
 OBJ = $(subst src/,,$(SRC:.cpp=.o))
 POBJ = $(patsubst src/,obj/$(SRC:.cpp=.o))

 prog: $(OBJ)
       $(CC) $(CFLAGS) $(LDFLAGS) $(LIBS) -o prog $(POBJ)

 %.o: %.cpp
     $(CC) $(CFLAGS) -c $< -o $(COMPILE)/$(@F)  

これにより、オブジェクトファイルの再コンパイルが不要になりますが、POJBターゲットに別の変数progを追加する必要があります(basedirがないとオブジェクトファイルだけでpatsubstを実行できないため)。

どちらの方法も機能し、それぞれに利点がありますが、どちらが「正しい」アプローチであり、どちらでもない場合、このタイプの建物を実現するための適切な方法は何ですか?

19
nhmood

あなたの最初の例はほとんどそこにあります:

SRC = $(wildcard src/*.cpp)
OBJ = $(patsubst src/%.cpp, obj/%.o, $(SRC))

prog: $(OBJ)
  $(CC) $(CFLAGS) $(LDFLAGS) $(LIBS) $(OBJ) -o prog 

obj/%.o: src/%.cpp
  $(CC) $(CFLAGS) -c $< -o $@
22
perreal