#c #makefile
#c #makefile
Вопрос:
У меня есть немного огромный Makefile, который в основном работает так, как я хочу.
Проблема: Проблема, с которой я сталкиваюсь, заключается в том, что makefile проверяет только, нуждается ли в обновлении первый .o
, а не какие-либо другие. Я не уверен, в какой части моего makefile ошибка.
Контекст: у меня есть структура проекта, подобная этой:
quendor
src
main.c
options.c
quendor.h
Makefile
Когда мой Makefile собирается, он создает build
каталог, и все выглядит следующим образом:
quendor
build
src
main.d
main.o
options.d
options.o
src
main.c
options.c
quendor.h
Makefile
Чтобы увидеть проблему: Теперь предположим, что я не меняю свой main.c
, но я меняю свой options.c
файл. В этом случае, когда я снова запускаю make, я получаю это:
make: 'build/./src/main.o' is up to date.
Я не уверен, связано ли это с тем, что он создается в build/src
каталог, а не просто build
так, как я предполагал.
Вот полный Makefile, и я включаю его весь только потому, что я не уверен, в чем может быть проблема, и я не хочу делать необоснованных предположений.
.PHONY : all clean
NAME := quendor
PLATFORM := windows
CC := gcc
LINK := gcc
BUILD_DIR ?= ./build
SRC_DIR ?= ./src
ifeq ($(PLATFORM), windows)
TARGET ?= quendor.exe
else
TARGET ?= quendor
endif
ifeq ($(CC), gcc)
CFLAGS = -std=c11 -Wall -Wextra -Wpedantic -Wconversion -Wmissing-prototypes -Wshadow -MMD -MP
LDFLAGS =
OPT =
endif
SRCS := $(wildcard $(SRC_DIR)/*.c)
OBJS := $(SRCS:%.c=$(BUILD_DIR)/%.o)
DEPS := $(OBJS:%.o=%.d)
MKDIR_P ?= @mkdir -p $(dir $@)
-include $(DEPS)
all : $(TARGET)
@echo "Building $(TARGET)"
$(TARGET) : $(OBJS)
$(LINK) $(OPT) -o $@ $^ $(LDFLAGS)
$(BUILD_DIR)/%.o : %.c
$(MKDIR_P)
$(CC) $(CFLAGS) -c $< -o $@
clean:
$(RM) $(TARGET) -r $(BUILD_DIR)
Это может быть результатом того, как StackOverflow анализирует мой Makfile, но я замечаю, что после этой строки он показывает другую подсветку синтаксиса:
SRCS := $(wildcard $(SRC_DIR)/*.c)
Комментарии:
1. Вы уже пытались удалить начало
./
в своих определенияхBUILD_DIR
иSRC_DIR
?2. Я этого не делал, но я только что попробовал это, и я получаю точно такую же проблему. Чтобы было понятно, что я пробовал, я использовал
BUILD_DIR ?= build
иSRC_DIR ?= src
. Но при этом все равно отображается то же поведение.3. Можете ли вы попробовать переместить
-include $(DEPS)
в конец вашего makefile (или, по крайней мере, в точку послеall
целевого правила). В качестве альтернативы попробуйте вызвать make asmake all
явно.4. Извините, я слишком быстро прочитал ваш вопрос. Итак, make сообщает вам, что
main.o
обновлено. Угадайте, что? make — это правильно. Поскольку вы не вносили измененийmain.c
, нет необходимости перекомпилировать его. Однако вы должны увидеть, чтоoption.c
выполняется перекомпиляция иquendor.exe
повторная компоновка. Это то, что вы видите?5. @RenaudPacalet Правильно, я не вижу
options.c
перекомпиляции, даже когда она изменена. Он просто останавливается наmain.c
, потому что видит, что он обновлен. Я был уверен, что это связано с тем, что одно из моих правил не допускало чего-либо рекурсивного.
Ответ №1:
Проблема в том, что вы включаете зависимости перед определением all
правила:
-include $(DEPS)
all : $(TARGET)
Если вы не указываете конкретную цель для сборки в командной строке (например, если вы не запускаете make all
), то make выбирает первую явную цель в makefile (и все включенные makefile-ы!!) в качестве цели для сборки.
Я предполагаю, что определения зависимостей в $(DEPS)
переменной определяют main.o
как цель, и поскольку это происходит раньше all
, это единственное, что выполняется по умолчанию.
Переместите -include
инструкцию позже в makefile (обычно я помещаю их все в конец makefile), и это сработает.
Комментарии:
1. АХ! Это было все! Я не могу поверить, что я этого не понял. Я читал так много источников по Makefiles и просто не понимал, что расположение здесь имеет значение. Это полностью решило проблему, и я благодарю вас.