Если вы ожидаете этого:
SRC= $(wildcard $(DSRC)**/*.cpp)
, чтобы найти все .cpp
файлы во всех подкаталогах $(DSRC)
, вы будете разочарованы.Специальная последовательность глобализации **
является нестандартной и поддерживается только некоторыми оболочками (например, zsh или bash, если вы включили специальную опцию).Он не входит в стандартную глобализацию POSIX и не поддерживается функцией GNU make wildcard
.Вам нужно будет использовать стандартную реализацию, такую как:
SRC := $(shell find $(DSRC) -name \*.cpp)
(здесь используется простое присвоение переменной (:=
), а не рекурсивное присвоение переменной (=
) для значительного повышения эффективности).
Также это:
OBJ= $(subst $(DSRC), $(DOBJ), $(patsubst %.cpp, %.o, $(SRC)))
может привести к неприятностям, потому что subst
заменяет все экземпляров, даже в середине слов, даже если их несколькоэкземпляр одним словом.Гораздо лучше (и проще) это просто:
OBJ := $(patsubst $(DSRC)/%.cpp,$(DOBJ)/%.o,$(SRC))
Причина, по которой вы видите тот же исходный файл, заключается в том, что ваш рецепт неверен:
$(OBJ): $(SRC)
mkdir -p $(DOBJ)
mkdir -p $(@D)
$(CC) -o $@ -c $< $(CXXFLAGS)
Предположим, SRC
разрешается в src/foo.cpp src/bar.cpp src/biz.cpp
.Затем OBJ
разрешается до obj/foo.o obj/bar.o obj/biz.o
.Таким образом, после расширения цели и предварительных условий вышеуказанного правила, make получит следующее:
obj/foo.o obj/bar.o obj/biz.o : src/foo.cpp src/bar.cpp src/biz.cpp
mkdir -p $(DOBJ)
mkdir -p $(@D)
$(CC) -o $@ -c $< $(CXXFLAGS)
Когда make видит несколько целей в явном правиле, он обрабатывает это как несколько явных правил, по одному для каждой цели,например:
obj/foo.o : src/foo.cpp src/bar.cpp src/biz.cpp
mkdir -p $(DOBJ)
mkdir -p $(@D)
$(CC) -o $@ -c $< $(CXXFLAGS)
obj/bar.o : src/foo.cpp src/bar.cpp src/biz.cpp
mkdir -p $(DOBJ)
mkdir -p $(@D)
$(CC) -o $@ -c $< $(CXXFLAGS)
obj/biz.o : src/foo.cpp src/bar.cpp src/biz.cpp
mkdir -p $(DOBJ)
mkdir -p $(@D)
$(CC) -o $@ -c $< $(CXXFLAGS)
Вы можете видеть, что во всех ваших правилах первым предварительным условием (к которому относится $<
) будет src/foo.cpp
, и именно это поведение вы наблюдаете.
Make не каким-то волшебным образом перебирает все цели и предпосылки и сопоставляет их для вас.
В make вы всегда пишете правило, которое строит одну цель из списка предпосылок этой цели.,В вашем случае вы, вероятно, захотите написать шаблонное правило , например:
$(DOBJ)/%.o : $(DSRC)/%.cpp
mkdir -p $(@D)
$(CC) -o $@ -c $< $(CXXFLAGS)
вместо явного правила, приведенного выше.Это обеспечивает make шаблоном, который он может использовать для создания любой цели, которая ему соответствует, и перечисляет предварительное условие связанного файла .cpp
.