make命令和makefile文件的结合提供了一个十分强大的工具,它可以控制代码的编译,还可以用于手册页的编写,以及将应用程序安装的目标目录。
make命令的选项和参数:
-k : 作用是让make命令在发现错误时仍然继续执行 ,而不是在检测到第一个错误的时候就停下来。可以利用这个选项在一次操作中发现所有未编译成功的源文件。
-n : 作用是让make命令输出时将要执行的操作步骤,但是不是真正的执行这些操作。
-f <filename> : 作用是告诉make命令将哪个文件作为makefile文件,如果该名称不存在,make命令就会查找名为makefile的文件。
为了指示make命令创建一个特定的目标(通常是一个可执行文件),可以把该目标的名字作为make命令的一个参数。如果不这么做,make命令将试图创建列在makefile文件中的地一个目标。
有一个习惯是:许多情况下,都会将自己的makefile文件中地一个目标定为all,然后再列出其他丛书目标。这个约定可以明确的告诉make命令,在没有制定特定目标时候,默认情况下因该创建那个目标。
依赖关系:定义了最终应用程序里的每个文件与源文件之间的关系。写法是:险些目标的名称,然后紧跟着一个冒号,接着是空格或者TAB 。例如:
myapp : main.o 2.o 3.o
main.o : main.c a.h
2.o : 3.c a.h b.h
3.o : 3.c b.h c.h
可以得到:myapp依赖于main.o 2.o 3.o 而main.o依赖于main,c a.h
这样就可以看到一个层次结构,它显示了源文件之间的关系。假设 我们想一次创建多个文件,就可以利用伪目标 all 。all : myapp myapp.1 . 这样,假如一个应用程序由 myapp 和
myapp.1组成的话,只需要重建all就可以了,如果没有all目标的话,那么make命令只会创建在文件makefile 中找到的地一个目标。
规则:
要想写一个makefile文件只有依赖关系是不够的。第二部分就是规则,他们定义了目标的创建方式。也就是说,当make命令确定了要重建一个目标文件的时候,要用到哪些具体命令呢?要为调试设置哪些符号信息选项呢? 就要用到了makefile文件中明确定义的一写规则。
注意:makefile中空格和TAB 之间是有区别的。规则所在的行是要用TAB 开头的,空格不行。makefile文件中的某一行也不能以空格结尾。
了解了上面的知识之后就可以进行编写简单的makefile文件了。
myapp:main.o 2.o 3.o
gcc -o myapp main.o 2.o 3.o
main.o: main.c a.h
gcc -cmain.c
2.o: 2.c a.h b.h
gcc -c 2.c
3.o: 3.c b.h c.h
gcc -c 3.c
makefile文件提高
注释: makefile文件中的注释以#开头,一直到结束,与shell脚本一样。
宏 : 作用与C 语言类似,就是文字替换,只不过定义方式不同:MACRONAME =value。。。。引用的方法是$(MACRONAME) 和 ${MACRONAME} 如果想把一个宏定义为空就把等号后面留空就可以了。
通常情况下 makefile文件的宏常被用于设置编译器的选项。有的时候,编译器的名字是gcc 但是在其他的UNIX 系统中,编译器的名字可能是cc或c89。这个时候,就可以通过宏定义了。宏通常实在makefile文件中被定义的,但是我们也可以在make命令的时候,在命令行上给出宏定义。例如 make CC=c89。命令行的宏定义覆盖makefile文件中的宏定义。当在makefile文件之外使用宏定义时候,要注意宏定义必须以单个参数的形式传递。所以必须在宏定义中使用空格或应像下面这样加上引号 make ”CC = C 89“
例子(带宏定义)
all: myapp
# Which compiler
CC = gcc
# Where are include files kept
INCLUDE = .
# Options for development
CFLAGS = -g -Wall -ansi
# Options for release
#CFLAGS = -O -Wall -ansi
myapp:main.o 2.o 3.o
$(CC) -o myapp main.o 2.o 3.o
main.o: main.c a.h
$(CC) -I$(INCLUDE) $(CFLAGS) -c main.c
2.o: 2.c a.h b.h
$(CC) -I$(INCLUDE) $(CFLAGS) -c 2.c
3.o: 3.c b.h c.h
$(CC) -I$(INCLUDE) $(CFLAGS) -c 3.c
在makefile文件中 make命令有一些内置的特殊的宏定义。这些宏在使用的时候,才会展开,所以随着makefile文件的处理进展而变化着。
$? 当前目标所依赖的文件列表中比当前目标文件还要新的文件
$@ 当前目标的名字
$< 当前依赖文件的名字
$* 不包括后缀名的当前依赖文件的名字。
同时在makefile文件中还有连个特殊的字符
- : 告诉make命令忽略所有错误,例如,当你执行一条命令的时候,mkdir 想创建爱你新目录 但是后面的目录已经存在了,就可以在mkdir命令前面加上一个减号(-)
@ : 告诉make在执行某条命令前不要将该命令显示在标准输出上。如果想用echo命令给出一些说明信息,那么这个字符就很有用。
多个目标:
通常制作不止一个目标文件或者将多组命令集中到一个位置来执行是很有用的。你可以通过扩展makefile文件来达到这一目的。 为makefile文件增加clean选项来删除不需要的目标文件, 增加一个install选项来将编译成功的应用程序安装到另一个目录下。
例子:
all : myapp
#which compiler
CC = gcc
#where to install
INSTDIR = /usr/local/bin
#where are include files kept
INCLUDE = .
#Options for development
CFLAGS = -g -Wall -ansi
#Options for realease
#CFLAGS = -o -Wall -ansi
myapp : main.o 2.o 3.o
$(CC) -o myapp main.o 2.o 3.o
main.o : main.c a.h
$(CC) -I$(INCLUDE) $(CFLAGS) -c main.c
2.o : 2.c a.h b.h
$(CC) -I$(INCLUDE) $(CFLAGS) -c 2.c
3.o : 3.c b.h c.h
$(CC) -I$(INCLUDE) $(CFLAGS) -c 3.c
clean:
-rm main.o 2.o 3.o
install:myapp
@if [ -d $(INSTDIR)];\
then \
cp myapp $(INSTDIR);\
chmod a+x $(INSTDIR) / myapp;\
chmod cg -w $(INSTDIR) /myapp;\
echo "Installed in $(INSTDIR)";\
else \
echo "Sorry , $(INSTDIR) dose not exit";\
fi
其中有几处需要特殊注意一下。
首先目标all只指定了myapp这一个目标。因此如果在执行make命令时候未制定目标,它的默认行为就是创建目标myapp。 下一个值得关注之处就是两个新增加的目标,clean和install。目标clean用rm命令来删除目标文件。rm命令以减号-开头,减号的含义让make命令忽略rm命令的执行结果。这意味着,即使由于目标文件不存在而导致rm命令返回错误,命令make clean也会成功。用于制作目标clean的规则并未给目标clean定义热和依赖关系,行clean:的后面是空的,因此该目标总被认为是过时的,所以在执行make命令时候,如果指定目标clean。则该目标所对应的规则将总被执行。
目标install依赖于myapp,所以make命令知道它必须创建myapp,然后才能执行制作该目标所需的其他命令。用于制作install目标的规则由几个shell脚本命令组成。由于make命令在执行规则时会调用一个shell,并且会针对每个规则使用一个新shell,所以必须在上面每行代码的结尾加上一个反斜杠\ 让所有shell脚本命令在逻辑上处于同一行,并作为一个整体传递给一个shell执行,这个命令以符号@开头,表示make在执行这些规则之前不会在标准输出上显示命令本身。