您的Makefile 没有包含在规则 形式中的依赖信息。规则是从左列(第 0 列)开始的行,在目标(要构建的对象)和必要条件(提供给规则的对象)之间有 : 分隔符
Make 会链接规则,因此在其先决条件具备之前无法构建目标,因此一个好的起点是:
ex1.exe: ex1.o
这意味着ex1.exe(Makefile 中的第一个目标)依赖于ex1.o(编译后的对象)......但是如何。您在下面添加命令,但在命令行前面插入一个制表符:
[tab char]gcc -Wall -g ex1.o -o ex1.exe
首先,看看该命令如何将ex1.o 作为gcc 的输入并生成(通过选项-o)文件ex1.exe。
所有这一切的意思是你总是缺少ex1.exe,或者它恰好在使用该命令的先决条件(ex1.o)之前被修改(从文件中的修改日期开始)。
现在,我们如何编译目标文件? (在您的 Makefile 中直接制作)
ex1.o: ex1.c
$(CC) $(CFLAGS) -c -o $@ $<
这一行需要更多解释(虽然如果你不使用它,它是由make程序自动提供的)它使用替换变量:$(CC)扩展为默认的C编译器(cc通常,但你可以改变它)。 $(CFLAGS) 是您在 Makefile 之上定义的变量,并扩展为通常用于编译程序的编译器选项。 $@ 由目标文件(在本例中为 ex1.o 文件)扩展,$< 扩展至规则右侧部分的左侧先决条件。这个把C文件编译成目标文件很常见的规则是make自动为你生成的,更多的可以在make高级使用中创建(这里就不多说了,因为量大需要的空间)只是说它可以这样写:
.c.o:
$(CC) $(CFLAGS) -c -o $@ $<
这意味着:任何扩展名为 .o 的文件都可以通过使用下面的下一个命令行从具有相同名称但扩展名为 .c 的文件创建。这会自动依赖具有相同名称但扩展名为 .c 的文件中的每个 .o 文件,并预加载在 make 中。
所以,您最简单的Makefile 可能是:
CFLAGS=-Wall -g
src=ex1.c
ex1.exe: $(src)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(src)
如您所见,我使用变量src 来描述用于编译我的程序的C 源文件。 仅当您修改了任何或先决条件(现在只有一个,ex1.c 但可能更多)并且我在同一个编译中进行编译和链接时,才会发出依赖项,我需要传递编译标志和链接标志(未使用,您可以在此处删除对$(LDFLAGS) 的引用)确实可以这样写:
ex1.exe: ex1.c
cc -g -Wall -o ex1.exe ex1.c
clean:
rm -f ex1.exe
所以,默认操作是创建ex1.exe,它依赖于ex1.c(所以只有在修改ex1.c时,才会重新编译ex1.exe。要编译它,只需:
make ex1.exe
或
make
这将使用Makefile 的默认第一条规则。
clean 是一个假目标(没有要生成的名为 clean 的文件)所以当你使用时
make clean
它的相关命令总是被执行。它使make 删除您的目标文件(因为它删除了所有make 生成的文件),因此下次运行make 时,它将通过执行必要的编译来重新创建所有文件。
常见用途
对于简单的程序,比方说,几个源.c文件和一些.h文件,每个文件都单独编译(编译中的-c选项)和链接,我通常使用这种方法(定义目标文件每个目标程序都需要不同的变量)
# makefile for programs foo and bar.
targets = foo bar
TOCLEAN = $(TARGETS) # this variable stores what should be erased on clean target. Here we store the programs to erase.
foo_objs = a.o b.o c.o
TOCLEAN += $(foo_objs) # here, we add the objects of foo
foo: $(foo_objs)
$(CC) $(LDFLAGS) -o $@ $(foo_objs)
bar_objs = d.o e.o f.o
bar_libs = -lm -lintl -lX
TOCLEAN += $(bar_objs) # here we add the objects of bar
bar: $(bar_objs)
$(CC) $(LDFLAGS) -o $@ $(bar_objs) $(bar_libs)
clean:
rm -f $(TOCLEAN)
a.o b.o c.o: a.h b.h c.h globals.h
b.o c.o d.o e.o f.o: my_defs.h
(如您所见,对头文件的依赖关系到编译后的对象 --- 不是 .c 源文件...源文件构建依赖关系,但目标文件是必须在其中重新创建的如果包含文件被修改,而不是包含.c文件)