Как и в большинстве языков программирования, синтаксис make не может быть понятен, если вы его не знаете.Если вы используете GNU, сделайте GNU make manual вашим другом.В следующих пояснениях я буду предполагать, что BUILD_DIR = build
и что один из исходных файлов - bar/foo.c
.
$(BUILD_DIR)
в списке предварительных условий (зависимостей) говорит, чтокаталог сборки (в который предполагается помещать объектные файлы) должен существовать до выполнения рецепта;логичной.Где-то должно быть другое правило для создания каталога, если он еще не существует.Что-то вроде:
$(BUILD_DIR):
mkdir -p $@
Но если вы не забыли скопировать важный символ, эта зависимость ужасно неоптимальная.Поскольку время последнего изменения каталога изменяется каждый раз, когда изменяется его содержимое (файлы или подкаталоги добавляются или удаляются), оно будет вызывать повторную компиляцию всех исходных файлов при каждом изменении каталога, а это не то, что вам нужно.Лучшей зависимостью будет только для заказа :
$(BUILD_DIR)/%.o: %.c | $(BUILD_DIR)
, которая заставляет make учитывать только существование $(BUILD_DIR)
, а не время его последней модификации, при принятии решения о перестроении илине.
$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $@
- это просто комбинация автоматических переменных make и .
$<
и $@
расширяются как первая предпосылка (bar/foo.c
) и цель (build/bar/foo.o
) соответственно. $(<:.c=.lst)
заменяет .c
на .lst
в $<
: bar/foo.lst
. $(notdir $(<:.c=.lst))
удаляет часть каталога: foo.lst
.
В общем, для исходного файла bar/foo.c
и с BUILD_DIR = build
, правило шаблона будет эквивалентно:
build/bar/foo.o: bar/foo.c | build
$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=build/foo.lst bar/foo.c -o build/bar/foo.o
Обратите внимание, что необходимо учитывать две разные ситуации:
Все ваши исходные файлы находятся в одном и том жекаталог как Makefile (без bar/foo.c
, просто foo.c
).Тогда вы можете упростить свой рецепт:
$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(<:.c=.lst) $< -o $@
, поскольку $(notdir...)
бесполезен.
Ваши исходные файлы могут находиться в подкаталогах (bar/foo.c
),Тогда вам нужно $(notdir...)
в вашем рецепте.Но имейте в виду, что если у вас есть два исходных файла с одинаковым базовым именем (bar/foo.c
и baz/foo.c
), у вас будет конфликт имен для $(BUILD_DIR)/foo.lst
, и ваш Makefile не будет работать должным образом.Более того, обязательное условие правила только для заказа должно быть эквивалентно build/bar
(или build/baz
), а не просто build
.И должно быть правило для его создания, если это необходимо.Если это ваш случай, я предлагаю изменить правило шаблона для:
$(BUILD_DIR)/%.o: %.c
mkdir -p $(dir $@)
$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $@
Существуют другие решения (вторичное расширение ...), но они слишком сложны для этого уже слишком длинного ответа.