Правило такого рода ...
%.o: %.c
$(CC) -c -o $@ $< $(CFLAGS)
прекрасно (с GNU make - не так много с другими make
реализациями). Он создает файл .o
из соответствующего файла .c
, где «соответствующий» означает наличие имени, образованного путем изменения конечного .o
на .c
. Это на самом деле не нужно, потому что make
имеет встроенное правило, которое делает практически то же самое.
Сообщение
Нет правила для создания цели 'obj / main.o', необходимой для 'prog'. Стоп.
Идентифицирует obj/main.o
как необходимое условие для цели prog
, которая не существует и для которой нет [применимого] правила. Приведенное выше правило шаблона будет применимо, если существует соответствующий источник (в смысле, описанном выше), но, очевидно, его нет.
Чтобы быть абсолютно ясным: соответствующий источник, образованный заменой .o
в obj/main.o
на .c
, равен obj/main.c
. Если такой файл не существует, представленное вами правило шаблона не применимо для сборки obj/main.o
. Сама программа make
не знает и не заботится о каталогах. Команды, которые он выполняет, выполняют, но для самого make
целевые и обязательные идентификаторы являются просто плоскими последовательностями символов.
Моя первая рекомендация для таких вещей - перестать пытаться быть милыми. Проще всего и чаще всего создавать объектные файлы в том же каталоге, что и их источники. Предположим, что ваши исходники C находятся в подкаталоге src/
относительно make-файла, этого make-файла будет достаточно (полагаясь на встроенное правило .c.o):
CC=gcc
CFLAGS=-Iinclude.
prog: src/main.o src/print.o
$(CC) -o $@ $^ $(CFLAGS)
Но если вы настаиваете на компиляции объектов в отдельном каталоге, тогда ваше шаблонное правило должно отражать это:
CC=gcc
CFLAGS=-Iinclude.
OBJ = obj/main.o obj/print.o
obj/%.o: src/%.c
$(CC) -c -o $@ $< $(CFLAGS)
prog: $(OBJ)
$(CC) -o $@ $^ $(CFLAGS)