什么是Makefile?
或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作,但要作一个好的和professional的程序员,makefile还是要懂。这就好像现在有这么多的HTML的编辑器,但如果你想成为一个专业人士,你还是要了解HTML的标识的含义。特别在Unix下的软件编译,你就不能不自己写makefile了,会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力。因为,makefile关系到了整个工程的编译规则。一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。
Makefile 介绍
make命令执行时,需要一个 Makefile 文件,以告诉make命令需要怎么样的去编译和链接程序。
首先,我们用一个示例来说明Makefile的书写规则。以便给大家一个感兴认识。这个示例来源于GNU的make使用手册,在这个示例中,我们的工程有8个C文件,和3个头文件,我们要写一个Makefile来告诉make命令如何编译和链接这几个文件。我们的规则是:
1.如果这个工程没有编译过,那么我们的所有C文件都要编译并被链接。
2.如果这个工程的某几个C文件被修改,那么我们只编译被修改的C文件,并链接目标程序。
3.如果这个工程的头文件被改变了,那么我们需要编译引用了这几个头文件的C文件,并链接目标程序。
只要我们的Makefile写得够好,所有的这一切,我们只用一个make命令就可以完成,make命令会自动智能地根据当前的文件修改的情况来确定哪些文件需要重编译,从而自己编译所需要的文件和链接目标程序。
Makefile的规则
在讲述这个Makefile之前,还是让我们先来粗略地看一看Makefile的规则。
target… : prerequisites …
command
…
…
-------------------------------------------------------------------------------
target也就是一个目标文件,可以是Object File,也可以是执行文件。还可以是一个标签(Label),对于标签这种特性,在后续的“伪目标”章节中会有叙述。
prerequisites就是,要生成那个target所需要的文件或是目标。
command也就是make需要执行的命令。(任意的Shell命令)
这是一个文件的依赖关系,也就是说,target这一个或多个的目标文件依赖于prerequisites中的文件,其生成规则定义在command中。说白一点就是说,prerequisites中如果有一个以上的文件比target文件要新的话,command所定义的命令就会被执行。这就是Makefile的规则。也就是Makefile中最核心的内容。
示例
INCLUDE =
PROG = telnet
DEFS = -D_POSIX_SOURCE
CFLAGS = -g ${DEFS} ${INCLUDE}
HDR =
SRC = cerrexit.c connectTCP.c connectUDP.c connectsock.c \
dcon.c do_echo.c do_noga.c do_notsup.c \
do_txbinary.c errexit.c fsmbuild.c fsminit.c \
sonotsup.c sofsm.c tclient.c recopt.c \
scrgetc.c scrinit.c scrwrap.c soputc.c \
sowrite.c status.c subend.c subfsm.c \
subopt.c subtermtype.c suspend.c sync.c \
tcout.c telnet.c tnabort.c ttfsm.c \
ttputc.c ttysetup.c ttwrite.c unscript.c \
will_notsup.c will_termtype.c will_txbinary.c xput.c
OBJ = cerrexit.o connectTCP.o connectUDP.o connectsock.o \
dcon.o do_echo.o do_noga.o do_notsup.o \
do_txbinary.o errexit.o fsmbuild.o fsminit.o \
sonotsup.o sofsm.o tclient.o recopt.o \
scrgetc.o scrinit.o scrwrap.o soputc.o \
sowrite.o status.o subend.o subfsm.o \
subopt.o subtermtype.o suspend.o sync.o \
tcout.o telnet.o tnabort.o ttfsm.o \
ttputc.o ttysetup.o ttwrite.o unscript.o \
will_notsup.o will_termtype.o will_txbinary.o xput.o
all: ${PROG}
${PROG}: ${OBJ}
${CC} -o $@ ${CFLAGS} ${OBJ} -ltermcap
clean: FRC
rm -f Makefile.bak a.out core errs lint.errs ${PROG} *.o
depend: ${HDR} ${SRC} FRC
maketd -a ${DEFS} ${INCLUDE} ${SRC}
install: all FRC
@echo "Your installation instructions here."
lint: ${HDR} ${SRC} FRC
lint ${DEFS} ${INCLUDE} ${SRC}
print: Makefile ${SRC} FRC
lpr Makefile ${HDR} ${SRC}
spotless: clean FRC
rcsclean Makefile ${HDR} ${SRC}
tags: ${SRC}
ctags ${SRC}
${HDR} ${SRC}:
gcc $@
FRC:
Makefile里有什么
Makefile里主要包含了五个东西:显式规则、隐晦规则、变量定义、文件指示和注释。
- 显式规则。显式规则说明了,如何生成一个或多的的目标文件。这是由Makefile的书写者明显指出,要生成的文件,文件的依赖文件,生成的命令。
- 隐晦规则。由于我们的make有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略地书写Makefile,这是由make所支持的。
- 变量的定义。在Makefile中我们要定义一系列的变量,变量一般都是字符串,这个有点你C语言中的宏,当Makefile被执行时,其中的变量都会被扩展到相应的引用位置上。
- 文件指示。其包括了三个部分,一个是在一个Makefile中引用另一个Makefile,就像C语言中的include一样;另一个是指根据某些情况指定Makefile中的有效部分,就像C语言中的预编译#if一样;还有就是定义一个多行的命令。有关这一部分的内容,我会在后续的部分中讲述。
- 注释。Makefile中只有行注释,和UNIX的Shell脚本一样,其注释是用“#”字符,这个就像C/C++中的“//”一样。如果你要在你的Makefile中使用“#”字符,可以用反斜框进行转义,如:“#”。
最后,还值得一提的是,在Makefile中的命令,必须要以[Tab]键开始。
参考资料
Linux下C编程指南 清华大学出版社
网络日志
嵌入式开发标准教程 华清远见