Вот MCVE вашей проблемы:
$ ls -R
.:
bar.c main.c Makefile
$ cat main.c
extern int bar(void);
int main(void)
{
bar();
return 0;
}
$ cat bar.c
int bar(void)
{
return 42;
}
$ cat Makefile
OBJS := main.o bar.o
BINS := prog
.PHONY: all clean
all: $(BINS)
%: $(OBJS)
$(CC) -o $@ $(OBJS)
clean:
$(RM) $(OBJS) $(BINS)
Выполните в первый раз:
$ make
cc -c -o main.o main.c
cc -c -o bar.o bar.c
cc -o prog main.o bar.o
rm bar.o main.o
Пауза, чтобы заметить нежелательные последствия 10.4 Цепи неявных правил :
rm bar.o main.o
Все объектные файлы автоматически удаляются после связывания программы, что отрицательно сказывается на цели Make.Неявные правила, в которых мы виноваты, это наше собственное неявное правило:
%: $(OBJS)
$(CC) -o $@ $(OBJS)
плюс встроенное неявное правило 1 :
%.o: %.c
# recipe to execute (built-in):
$(COMPILE.c) $(OUTPUT_OPTION) $<
, которые вместе составляютнеявная цепочка правил, которая приводит к тому, что все объектные файлы становятся промежуточными файлами .
Продолжая, давайте обновим исходный файл:
$ touch main.c
и сделаем второй раз:
$ make
cc -c -o main.o main.c
cc -c -o bar.o bar.c
cc -o Makefile main.o bar.o
rm bar.o main.o
Makefile:1: warning: NUL character seen; rest of line ignored
Makefile:1: *** missing separator. Stop.
Наш Makefile перекрыт связующим звеном:
cc -o Makefile main.o bar.o
Этот snafu объяснен в руководстве 3.5 Как восстанавливаются Makefile :
Иногда make-файлы могут быть переделаны из других файлов, таких как файлы RCS или SCCS.Если make-файл может быть переделан из других файлов, вы, вероятно, захотите, чтобы make получал актуальную версию make-файла для чтения.
С этой целью после чтения во всех make-файлах выполнитебудет рассматривать каждый как цель цели и попытаться обновить его.Если в make-файле есть правило, в котором указано, как его обновить (находится либо в этом самом make-файле, либо в другом), либо если к нему применяется неявное правило (см. «Использование неявных правил»), оно будет обновлено при необходимости .После того, как все make-файлы были проверены, если они действительно были изменены, make запускается с чистого листа и снова читает все make-файлы.(Он также попытается обновить каждый из них снова, но обычно это не изменит их снова, поскольку они уже обновлены.)
(выделение мое).Существует ли неявное правило, применимое к Makefile
, которое считается целью?Да, это:
%: $(OBJS)
$(CC) -o $@ $(OBJS)
, поскольку целевой шаблон %
соответствует любому файлу независимо от того.Если мы восстановим наш сжатый Makefile и попробуем ту же самую экспериментальную вещь снова, на этот раз с отладкой:
make -d >debug.log 2>&1
, результат покажет нам:
...
Reading makefiles...
Reading makefile 'Makefile'...
Updating makefiles....
Considering target file 'Makefile'.
Looking for an implicit rule for 'Makefile'.
...
...
Found an implicit rule for 'Makefile'.
...
...
Finished prerequisites of target file 'Makefile'.
Prerequisite 'main.o' is newer than target 'Makefile'.
Prerequisite 'bar.o' is newer than target 'Makefile'.
Must remake target 'Makefile'.
cc -o Makefile main.o bar.o
...
Мы можем избежать этого результата, итакже саморазрушающееся автоудаление наших объектных файлов, не используя неявное правило match-everything для выполнения нашей связи.Обычным делом является создание программы из ее объектных файлов по явному правилу, например
Makefile (2)
OBJS := main.o bar.o
BIN := prog
.PHONY: all clean
all: $(BIN)
$(BIN): $(OBJS)
$(CC) -o $@ $(OBJS)
clean:
$(RM) $(OBJS) $(BIN)
Похоже, что вы дорожите опциейиметь BINS
список нескольких программ:
Я хочу просто иметь возможность запускать
make clean
make
чтобы построить все в списке BINS.
Но учтите это с:
BINS := prog1 prog2
и рецептом:
%: $(OBJS)
$(CC) $(LFLAGS) -o $@ $(OBJS)
как способ сделать всев списке BINS
вы просто создадите одну и ту же программу дважды с двумя разными именами.И даже если вы хотели сделать это, способ сделать это будет:
Makefile (3)
OBJS := main.o bar.o
BINS := prog1 prog2
.PHONY: all clean
all: $(BINS)
$(BINS): $(OBJS)
$(CC) -o $@ $(OBJS)
clean:
$(RM) $(OBJS) $(BIN)
, который выполняетсянапример:
$ make
cc -c -o main.o main.c
cc -c -o bar.o bar.c
cc -o prog1 main.o bar.o
cc -o prog2 main.o bar.o
[1] Вы можете заставить GNU Make показать вам все встроенные правила и все остальные правила для конкретной сборки, набрав make --print-data-base ...