Проблема в том, что ваши цели двоичных объектов (например, display.o
) на самом деле не соответствуют файлам, созданным по их правилам.Если вы скажете make
, что нужно сделать цель display.o
, он (обычно, за исключением фальшивых целей, но они всегда перезапускаются) ожидает, что соответствующий файл будет создан по рецепту правила, и он может отследить, должна ли цель бытьпеределан.Если такой файл не создается, эта цель всегда оценивается как устаревшая и нуждающаяся в переделке.
Немного глупого примера этого будет следующее дерево:
.
├── Makefile
├── main.c
└── test
└── file.c
и Makefile:
main: test.o main.o
$(CC) -o main *.o
test.o:
$(CC) $(CFLAGX) -c test/*.c
Нет файла test.o
, и цель должна быть переделана ... правило запускается, выдает file.o
(снова).Поскольку эта цель была переделана и является обязательным условием main
... все всегда переделывается.
Теперь с этой небольшой модификацией:
main: test.o main.o
$(CC) -o main *.o
test.o:
$(CC) $(CFLAGX) -o $@ -c test/*.c
test.o
цель действительно производит test.o
Файл и правило не нуждаются в переделке, если test.c
не изменяется ... и с test.o
без изменений и main.c
, возможно, также, мы получаем:
$ make
make: 'main' is up to date.
Это все еще не совсем правильно, так какэто действительно должно выглядеть так:
main: test.o main.o
$(CC) -o main $+
test.o: test/*.c
$(CC) $(CFLAGX) -o $@ -c $^
Где я объявляю зависимые предпосылки test.o
и ссылаюсь на них и на цель с помощью автоматической переменной в рецепте правила.И То же самое касается предпосылок для связывания.Конечно, в этом простом примере я мог бы просто положиться на неявные шаблонные правила и сделать это:
main: test/file.o main.c
test/file.o: test/*.c
Что это значит для вашего make-файла?Когда вы компилируете свои объектные файлы, посмотрите, что они на самом деле производят, и сопоставьте вашу цель с этим или (например, с -o $@
) скажите им, чтобы они точно создали файл, соответствующий вашей цели.
Я немного расширил глупый пример, и теперь в test/
есть два файла:
.
├── Makefile
├── main.c
└── test
├── file.c
└── other.c
И Makefile может выглядеть примерно так:
main: obj/file.o obj/other.o main.c
obj/%.o: test/%.c
mkdir -p obj
$(CC) $(CFLAGS) -c -o $@ $^
Теперь он хранитОбъектные файлы в obj/
и заставляют все еще понимать, что для чего нужно и могут отслеживать изменения.Конечно, ваша установка более сложна и потребует большего количества правил, возможно, также для разделения фактических источников или промежуточных целей из дерева каталогов и определения нескольких переменных для работы с этой информацией, например:
OBJS := $(patsubst test/%.c,obj/%.o,$(wildcard test/*.c))
main: $(OBJS) main.c
obj/%.o: test/%.c
mkdir -p obj
$(CC) $(CFLAGS) -c -o $@ $^
Но принципы остаютсято же самое.