设置我的 makefile 以仅使用 "make" 编译 C
Set up my makefile to compile C with just "make"
我正在学习 Zed Shaw 的 Learn C The Hard Way 课程,在第 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
默认目标是第一个目标,因此请调换这些目标的顺序,使 all
成为默认目标。
the documentation on goals中有更多详细信息:
By default, the goal is the first target in the makefile (not counting targets that start with a period). Therefore, makefiles are usually written so that the first target is for compiling the entire program or programs they describe. If the first rule in the makefile has several targets, only the first target in the rule becomes the default goal, not the whole list. You can manage the selection of the default goal from within your makefile using the .DEFAULT_GOAL
variable
CFLAGS = -Wall -g
all: ex1
clean:
$(RM) ex1
.PHONY: all clean
修复了我在开头的 CFLAGS
定义,并在末尾为 all
和 clean
添加了 .PHONY
,因此 make
知道不要创建文件对于这些。
对于一个非常简单的 makefile,我这样做:
qsorttest: qsorttest.c
gcc -Wall -g qsorttest.c -o qsorttest -lm
clean:
rm -f qsorttest
"qsorttest.c" 是我的源文件的名称,我创建的可执行文件是 "qsorttest"
确保 "program name: source file" 和 "clean:" 下的行被制表并且没有被 space 键移动。我用头撞墙了一会儿,直到我用谷歌搜索了出来。
我将其保存为 "Makefile",保存在与程序的其他文件相同的目录中,并且每次都能正常工作。我只是根据需要更改源文件和程序名称,并在需要时添加用于链接库的额外参数。
您的 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文件编译成object文件很常用的规则,是make
自动帮你生成的,更多的可以在make
创建高级使用(我这里就不输入了,由于需要 space 的数量)只是说它可以这样写:
.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
但可能更多)并且我正在编译和 linking 在同一编译中,我需要传递编译标志和 link 标志(未使用,您可以在此处删除对 $(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
选项)和 linking,我通常使用这种方法(在不同的变量中定义每个目标程序所需的目标文件)
# 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
文件)
我正在学习 Zed Shaw 的 Learn C The Hard Way 课程,在第 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
默认目标是第一个目标,因此请调换这些目标的顺序,使 all
成为默认目标。
the documentation on goals中有更多详细信息:
By default, the goal is the first target in the makefile (not counting targets that start with a period). Therefore, makefiles are usually written so that the first target is for compiling the entire program or programs they describe. If the first rule in the makefile has several targets, only the first target in the rule becomes the default goal, not the whole list. You can manage the selection of the default goal from within your makefile using the .DEFAULT_GOAL
variable
CFLAGS = -Wall -g
all: ex1
clean:
$(RM) ex1
.PHONY: all clean
修复了我在开头的 CFLAGS
定义,并在末尾为 all
和 clean
添加了 .PHONY
,因此 make
知道不要创建文件对于这些。
对于一个非常简单的 makefile,我这样做:
qsorttest: qsorttest.c
gcc -Wall -g qsorttest.c -o qsorttest -lm
clean:
rm -f qsorttest
"qsorttest.c" 是我的源文件的名称,我创建的可执行文件是 "qsorttest" 确保 "program name: source file" 和 "clean:" 下的行被制表并且没有被 space 键移动。我用头撞墙了一会儿,直到我用谷歌搜索了出来。
我将其保存为 "Makefile",保存在与程序的其他文件相同的目录中,并且每次都能正常工作。我只是根据需要更改源文件和程序名称,并在需要时添加用于链接库的额外参数。
您的 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文件编译成object文件很常用的规则,是make
自动帮你生成的,更多的可以在make
创建高级使用(我这里就不输入了,由于需要 space 的数量)只是说它可以这样写:
.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
但可能更多)并且我正在编译和 linking 在同一编译中,我需要传递编译标志和 link 标志(未使用,您可以在此处删除对 $(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
选项)和 linking,我通常使用这种方法(在不同的变量中定义每个目标程序所需的目标文件)
# 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
文件)