Linux下makefile的制作(入门级)

Makefile简介

在Linux下编译大型项目时,各种库和源码之间的依赖关系比较复杂,给操作带来不便。所以就有了Makefile来组织,makefile很方便,当敲了make命令后,就自动开始编译。当然它 不仅可以用来编译项目, 还可以用来组织我们平时的一些日常操作,特别是需要大量重复的。

Makefile简单规则

在makefile中分为5部分:显示规则, 隐晦规则, 变量定义, 文件指示, 注释
1、显式规则。显式规则说明了,如何生成一个或多的的目标文件。这是由Makefile的书写者明显指出,要生成的文件,文件的依赖文件,生成的命令。

2、隐晦规则。由于我们的make有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略地书写Makefile,这是由make所支持的。

3、变量的定义。在Makefile中我们要定义一系列的变量,变量一般都是字符串,这个有点你C语言中的宏,当Makefile被执行时,其中的变量都会被扩展到相应的引用位置上。

4、文件指示。其包括了三个部分,一个是在一个Makefile中引用另一个Makefile,就像C语言中的include一样;另一个是指根据某些情况指定Makefile中的有效部分,就像C语言中的预编译#if一样;还有就是定义一个多行的命令。有关这一部分的内容,我会在后续的部分中讲述。

5、注释。Makefile中只有行注释,和UNIX的Shell脚本一样,其注释是用“#”字符,这个就像C/C++中的“//”一样。如果你要在你的Makefile中使用“#”字符,可以用反斜框进行转义,如:“#”。

引用链接

一般格式为:

变量定义

target:   depend1  depend2 depend3 ... 
<TAB> action1
<TAB> action2
...
target1:
<TAB> action1
<TAB> action2
...

target为目标,depend为依赖, action为动作(一般为shell命令),依赖亦可以是目标。在写action时需要以tab开头。
command太长, 可以用 “” 作为换行符

当敲了make以后,make 命令像命令行参数一样从Makefile(也可以是通过make -f 文件名 指定的文件)中接收目标。当 make 命令第一次执行时,它扫描 Makefile 找到目标以及其依赖。如果这些依赖自身也是目标,继续为这些依赖扫描 Makefile 建立其依赖关系,然后执行动作。make完成makefile的第一个,一般为all目标,其他的目标未被总目标也就是all依赖或者执行的话,是不会被执行的,如果需要,需要执行命令: make 目标
下面举一个简单的例子

nameserver=wujinlong_server
namecilent=wujinlong_client
all: gccclient gccserver
	@./${nameserver} -p 9418
	@./${namecilent} -p 9418 -i 192.168.0.16
gccclient:
	@gcc client.c -o ${namecilent}
gccserver:
	@gcc server_pthread.c -o ${nameserver} -lpthread -l sqlite3
shutdown:

clean:
	@rm -rf client ${nameserver} ${namecilent}

执行结果为
Linux下makefile的制作(入门级)

常见符号及作用

引自大佬博客:地址
${variable}——取{}中的值,Makefile中定义的或者是make的环境变量。

[email protected] 代表规则中的目标文件名。
$< 规则的第一个依赖文件名。如果是隐含规则,则它代表通过目标指定的第一个依赖文件。

规则中的通配符

*:表示任意一个或多个字符
? : 表示任意一个字符
[…] :: ex. [abcd] 表示a,b,c,d中任意一个字符, [^abcd]表示除a,b,c,d以外的字符, [0-9]表示 0~9中任意一个数字
~ :: 表示用户的home目录

路径搜索

当一个Makefile中涉及到大量源文件时(这些源文件和Makefile极有可能不在同一个目录中),这时, 最好将源文件的路径明确在Makefile中, 便于编译时查找. Makefile中有个特殊的变量 VPATH 就是完成这个功能的.指定了 VPATH 之后, 如果当前目录中没有找到相应文件或依赖的文件, Makefile 回到 VPATH 指定的路径中再去查找…

VPATH 使用方法:

vpath :: 当前目录中找不到文件时, 就从中搜索
vpath :: 符合格式的文件, 就从中搜索
vpath :: 清除符合格式的文件搜索路径
vpath :: 清除所有已经设置好的文件路径

Makefile 中的变量

变量定义 ( = or := )
其中 = 和 := 的区别在于, := 只能使用前面定义好的变量, = 可以使用后面定义的变量
?=如果定义则使用定义的值,如果没有定义则定义
appname ?=test.app
变量追加值 +=

Makefile 命令前缀

Makefile 中书写shell命令时可以加2种前缀 @ 和 -, 或者不用前缀.
3种格式的shell命令区别如下:

不用前缀 :: 输出执行的命令以及命令执行的结果, 出错的话停止执行
前缀 @ :: 只输出命令执行的结果, 出错的话停止执行
前缀 - :: 命令执行有错的话, 忽略错误, 继续执行

make命令常用选项

-C dir
–directory=dir
指定读取makefile的目录。如果有多个“-C”参数,make的解释是后面的路径以前面的作为相对路径,并以最后的目录作为被指定目录。如:“make –C ~hchen/test –C prog”等价于“make –C ~hchen/test/prog”。

—debug[=options]
输出make的调试信息。它有几种不同的级别可供选择,如果没有参数,那就是输出最简单的调试信息。下面是options的取值:
a —— 也就是all,输出所有的调试信息。(会非常的多)
b —— 也就是basic,只输出简单的调试信息。即输出不需要重编译的目标。
v —— 也就是verbose,在b选项的级别之上。输出的信息包括哪个makefile被解析,不需要被重编译的依赖文件(或是依赖目标)等。
i —— 也就是implicit,输出所以的隐含规则。
j —— 也就是jobs,输出执行规则中命令的详细信息,如命令的PID、返回码等。
m —— 也就是makefile,输出make读取makefile,更新makefile,执行makefile的信息。

-d
相当于“–debug=a”。
-e
–environment-overrides”
指明环境变量的值覆盖makefile中定义的变量的值。

-f=file
–file=file
–makefile=file
指定需要执行的makefile。

-h
–help
显示帮助信息。

-i
–ignore-errors
在执行时忽略所有的错误。

-I dir
–include-dir=dir
指定一个被包含makefile的搜索目标。可以使用多个“-I”参数来指定多个目录。

-j [jobsnum]
–jobs[=jobsnum]
指同时运行命令的个数。如果-j后没有这个jobsnum参数,make运行命令时能运行多少就运行多少。如果有一个以上的“-j”参数,那么仅最后一个“-j”才是有效的。(注意这个参数在MS-DOS中是无用的)

-k
–keep-going
出错也不停止运行。如果生成一个目标失败了,那么依赖于其上的目标就不会被执行了。

-n
–just-print
–dry-run
–recon
仅输出执行过程中的命令序列,但并不执行。

-o file
–old-file=file
–assume-old=file
不重新生成的指定的file,即使这个目标的依赖文件新于它。

“p
–print-data-base
输出makefile中的所有数据,包括所有的规则和变量。这个参数会让一个简单的makefile都会输出一堆信息。如果你只是想输出信息而不想执行 makefile,你可以使用“make -qp”命令。如果你想查看执行makefile前的预设变量和规则,你可以使用“make –p –f /dev/null”。这个参数输出的信息会包含着你的makefile文件的文件名和行号,所以,用这个参数来调试你的makefile会是很有用的, 特别是当你的环境变量很复杂的时候。

-s
–silent
–quiet
在命令运行时不输出命令的输出。

-w
–print-directory
输出运行makefile之前和之后的信息。这个参数对于跟踪嵌套式调用make时很有用。

–no-print-directory
禁止“-w”选项。

-W file
–what-if=file
–new-file=file
–assume-file=file
假定目标file需要更新,如果和“-n”选项使用,那么这个参数会输出该目标更新时的运行动作。如果没有“-n”那么就像运行UNIX的“touch”命令一样,使得file的修改时间为当前时间。

–warn-undefined-variables
只要make发现有未定义的变量,那么就输出警告信息