Ну, hangman
(двоичный файл программы) зависит только от hangman.o
, но не от hangman.c
, который уже был скомпилирован в hangman.o
(на этапе компиляции).
In Makefile
, вы только указываете прямые зависимости, в то время как make(1)
выполняет всю остальную работу.
Я использую для обозначения всех объектов в программе в переменной, так как они будут использоваться несколько раз. Таким образом:
# Makefile -- make file for hangman.
targets = hangman
hangman_objs = hangman.o
hangman: $(hangman_objs)
$(CC) $(LDFLAGS) -o hangman $(hangman_objs)
и ничего больше, поскольку make(1)
имеет правило c для автоматов, то есть
.c.o:
$(CC) $(CFLAGS) -o $@ -c $<
, которое эквивалентно этому правилу:
hangman.o: hangman.c
$(CC) $(CFLAGS) -o hangman.o -c hangman.c
(и то же самое для каждого файла .c
и .o
, который вы можете иметь.)
Кстати, ошибка, которую вы получаете, заключается в том, что make нашла зависимость от hangman.c
, но не находит ни одного файла с именем hangman.c
, поэтому он должен его собрать, но вы не предоставляете этот файл. Вы, вероятно, стерли файл hangman.c
(что иногда случается, если вы неправильно вводите файлы в Makefile
, заканчиваете стиранием файлов, которые важны для вас) В этом случае он пытается собрать handman
, который зависит от handman.o
, который зависит от handman.c
, так что отсутствие handman.c
не дает make(1)
сказать, что у меня есть зависимость от handman.c
, но такой файл не найден (и у меня нет зависимости, которая позволяет мне строить it)
Если ваш проект является проектом с одним исходным кодом, тогда вы можете избежать генерации hangman.o
и создать Makefile
следующим образом:
hangman: hangman.c
$(CC) $(CFLAGS) $(LDFLAGS) -o hangman hangman.c
, который утверждает явное, прямая ссылка из двоичного файла на исходный код. В этом случае вы не используете флаг -c
для компилятора, чтобы просто компилировать, не связываете и не собираете свой исполняемый файл напрямую с помощью одной команды. Это не используется в больших проектах, так как обычно вы хотите просто скомпилировать источники, которые изменились. Как в этом примере:
hangman_objs = hang.o man.o foo.o bar.o a.o b.o c.o
hangman: $(hangman_objs)
$(CC) $(LDFLAGS) -o hangman $(hangman_objs)
если вы развернете переменную, вы получите это правило:
hangman: hang.o man.o foo.o bar.o a.o b.o c.o
cc -o hangman hang.o man.o foo.o bar.o a.o b.o c.o
#all this are automatic dependencies generated from
# .c.o:
# $(CC) $(CFLAGS) -c $< -o $@
# for the files hang.o man.o foo.o bar.o a.o b.o c.o
hang.o: hang.c
cc -O2 -pipe -c hang.c -o hang.o
man.o: man.c
cc -O2 -pipe -c man.c -o man.o
foo.o: foo.c
cc -O2 -pipe -c foo.c -o foo.o
bar.o: bar.c
cc -O2 -pipe -c bar.c -o bar.o
a.o: a.c
cc -O2 -pipe -c a.c -o a.o
b.o: b.c
cc -O2 -pipe -c b.c -o b.o
c.c: c.c
cc -O2 -pipe -c c.c -o c.o
, но вы не должны использовать как объектный код, так и исходный код на этапе связывания вашей программы. Компилятор свяжет предоставленный вами файл hangman.o
и скомпилирует его (который генерирует новый hangman.o
), и попытается связать обе (две версии одного и того же кода), что может привести к новым ошибкам.
Мой подход к вашей программе будет:
# main targets to build (programs)
targets = hangman
# toclean maintains everything must be erased on clean.
toclean = $(targets)
# object files of hangman target
hangman_objs = hangman.o foo.o
# add all those objects to the toclean variable.
toclean += $(hangman_objs)
# libraries
hangman_ldflags = -L path/to/libbar
hangman_libs = -lbar
# main target all
all: $(targets)
# ... and clean
clean:
rm -f $(toclean)
# just the link phase, the compiling is automatically done.
hangman: $(hangman_objs)
$(CC) $(LDFLAGS) $($@_ldflags) -o $@ $($@_objs) $($@_libs)