我已经在这个制作文件上工作了几个小时。它不断收到错误:make:***没有规则来使目标"hangman.c","hangman.o"需要。停


CFLAGS=-std=c99 -Wall
CC=gcc
hangman: hangman.o hangman.c
$(CC) $(CFLAGS) hangman.o hangman.c -o hangman
hangman.o: hangman.c
$(CC) $(CFLAGS) -c hangman.c
clean:
rm -f hangman *.o

好吧,hangman(程序二进制文件)只依赖于hangman.o,而不是hangman.c,它已经被编译成hangman.o(在编译阶段)。

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.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.cmake(1)说, 我对handman.c有依赖关系,但没有找到这样的文件(而且我没有依赖关系可以让我构建它)

如果您的项目是单个源项目,则可以避免生成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)

最新更新