设置我的makefile以仅使用“ make”来编译C

时间:2019-01-09 22:44:58

标签: c makefile cmder

我正在做Zed Shaw的“学习C的艰难方法”课程,在第2课中,我发现在视频和书中,作者只使用make ex1来编译他的C,而我需要运行gcc -Wall -g ex1.c -o ex1。这是我的Makefile,似乎第一部分应该是使make命令可以编译的内容,但是“ make”命令不能编译它。

CFLAGs=-Wall -g

clean:
    rm -f ex1.exe

all:
    gcc -Wall -g ex1.c -o ex1.exe




4 个答案:

答案 0 :(得分:4)

默认目标是第一个目标,因此请切换其顺序,以使all为默认目标。

the documentation on goals中有更多详细信息:

默认情况下,目标是makefile中的第一个目标(不计算以句点开头的目标)。因此,通常编写makefile,以便第一个目标是编译它们描述的整个程序。如果makefile中的第一个规则具有多个目标,则仅该规则中的第一个目标成为默认目标,而不是整个列表。您可以使用.DEFAULT_GOAL变量从makefile中管理默认目标的选择

答案 1 :(得分:3)

您的Makefile没有以规则的形式包含的依存关系信息。规则是从左列(第0列)开始的行,在目标(要构建的对象)和必需项(提供给规则的对象)之间具有:分隔符。

Make进行规则的链接,因此在其先决条件尚未达到之前就无法构建目标,因此一个不错的起点是:

ex1.exe: ex1.o

这意味着ex1.exeMakefile中的第一个目标)取决于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编译器({{ 1}},但可以更改)。 cc是您在$(CFLAGS)上方定义的变量,并扩展为通常用于编译程序的编译器选项。 Makefile由目标文件(在这种情况下为$@文件)扩展,而ex1.o扩展到规则右部分的左先决条件。该规则非常常见,可以将C文件编译为目标文件,它是$<自动为您生成的,并且可以在make高级使用中创建更多规则(我不再在这里输入,由于需要的空间量大)只能说可以这样写:

make

表示:任何扩展名为.c.o: $(CC) $(CFLAGS) -c -o $@ $< 的文件都可以通过使用以下命令行从具有相同名称但扩展名为.o的文件创建。这样可以自动依赖具有相同名称但扩展名为.c且已预加载到.o中的文件的每个.c文件。

因此,最简单的make可能是:

Makefile

如您所见,我已经使用变量CFLAGS=-Wall -g src=ex1.c ex1.exe: $(src) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(src) 来描述用于编译程序的C源文件。当您修改了任何或前提条件(src上只有一个前提条件,但可能会更多)并且我正在使用相同的条件进行编译和链接时,将仅 发出依赖性编译,我需要传递编译标志和链接标志(未使用,您可以在此处删除对ex1.c的引用)确实可以写:

$(LDFLAGS)

因此,默认操作是创建依赖于ex1.exe: ex1.c cc -g -Wall -o ex1.exe ex1.c clean: rm -f ex1.exe 的{​​{1}}(因此,只有在修改ex1.exe后,ex1.c才会重新编译。要对其进行编译,只要这样做:

ex1.c

ex1.exe

将使用make ex1.exe 的默认第一规则。

make 是伪造的目标(没有要生成的名为Makefile的文件),因此在您使用时

clean

其关联的命令始终被执行。它使clean删除目标文件(因为它会删除所有make生成的文件),因此,下次运行make clean 时,它将通过进行必要的编译来重新创建所有文件。

常用

对于简单的程序,假设有几个源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 文件,则重新创建)

答案 2 :(得分:1)

CFLAGS = -Wall -g

all: ex1

clean:
    $(RM) ex1

.PHONY: all clean

首先修正了我的CFLAGS定义,并在.PHONYall的末尾添加了clean,所以make知道不为这些文件制作文件

答案 3 :(得分:0)

对于一个非常简单的makefile,我这样做:

qsorttest: qsorttest.c 
     gcc -Wall -g qsorttest.c -o qsorttest -lm

clean:
     rm -f qsorttest

“ qsorttest.c”是我的源文件的名称,我创建的可执行文件是“ qsorttest” 确保在“程序名称:源文件”和“清洁:”下的行被制表了并且不随空格键一起移动。我把头撞在墙上一会儿,直到我搜寻出那条路为止。

我将该程序另存为“ Makefile”,与该程序的其他文件位于同一目录中,并每次都能正常运行。我只是根据需要更改源文件和程序名称,并在需要时添加额外的参数来链接库。