GNU Make: шаблонное правило срабатывает только на первом файле
Имеется Makefile:
ROOT_DIR = $(PWD)
BUILD_DIR = $(ROOT_DIR)/build
CXX = g++
SOURCES = $(wildcard $(ROOT_DIR)/*.cc)
OBJS = $(patsubst %.cc, %.o, $(subst $(ROOT_DIR), $(BUILD_DIR), $(SOURCES)))
$(OBJS) : $(SOURCES)
@echo $< $@
$(CXX) -c -o $@ $<
all: $(OBJS)
$(CXX) $? $<
clean:
rm $(BUILD_DIR)/*o
print : $(ROOT_DIR)/*.cc
@echo "OBJS" $(OBJS)
@echo "SOURCES" $(SOURCES)
@echo "@" $@
@echo "<" $<
@echo "^" $^
@echo "*" $*
И каталог, в котором исходники:
build main.cc Makefile smb1.cc smb1.h smb1_tr.cc
При вызове правила $(OBJS) : $(SOURCES) оно срабатывает только на первом файле списка.
Также вообще не срабатывает, если написать $(OBJS) : %.cc
Пишет что нету правила для сборки пререквизита. (Для примера попробуйте заменить символ * на % в правиле print.)
Что я делаю не так?
GNU Make 4.1
Можете скачать тут весь каталог: https://disk.yandex.ru/d/r-wId25734YCwA
Ответы (1 шт):
Цель по умолчанию это первая цель в makefile.
Цель all рекомендуется делать целью по умолчанию. Для этого она должна быть либо первой в файле, либо можно использовать специальную переменную .DEFAULT_GOAL:
.DEFAULT_GOAL := all
В целом у вас очень странный makefile. Непонятно зачем нужет ROOT_DIR, мы и так в каталоге с исходниками.
Правило $(OBJS) : $(SOURCES) означает что каждый .o-файл зависит от всех .cc-файлов. Вряд ли вы хотели именно так. Тем не менее, в рецепте к этому правилу вы использовали переменную $< которая означает «первый из списка зависимостей», т.е. у вас для любого .o-файла всегда компилировался первый файл из списка.
Я бы написал так:
# Задаём дефолтную цель
.DEFAULT_GOAL = all
# ROOT_DIR не нужен, сборка всегда запускается в текущем каталоге
BUILD_DIR = build
CXX = g++
SOURCES := $(wildcard *.cc)
OBJS := $(patsubst %.cc, %.o, $(addprefix $(BUILD_DIR)/,$(SOURCES)))
# создаём папку
$(BUILD_DIR):
mkdir -p $@
# Правило для сборки build/FOO.o из FOO.cc
# https://www.gnu.org/software/make/manual/make.html#Implicit-Rules
$(BUILD_DIR)/%.o : %.cc | $(BUILD_DIR)
@echo $< $@
$(CXX) -c -o $@ $<
$(BUILD_DIR)/prog: $(OBJS)
$(CXX) -o $@ $(OBJS)
all: $(BUILD_DIR)/prog
clean:
rm -r $(BUILD_DIR)