Makefile经验总结

0.概述

记录工作中makefile编写常用方法和函数,详细的用法见跟我一起写Makefile无法下载的可以在评论区@我。

1.常用规则

1.1 清空目录的规则

.PHONY : clean
clean :
    -rm edit $(objects)

.PHONY 表示 clean 是一个“伪目标”。而在 rm 命令前面加了一个小减号的意思就是,也许某些文件出现问题,但不要管,继续做后面的事。

不成文的规矩是——“clean从来都是放在文件的最后”。

1.2 文件搜寻 (用起来比较爽)

Makefile文件中的特殊变量 VPATH 就是完成这个功能的。

VPATH = src:../headers

上面的定义指定两个目录,“src”和“…/headers”,make会按照这个顺序进行搜索。目录由“冒号”分隔。(当然,当前目录永远是最高优先搜索的地方)

1.3 伪目标(可用生成多个目标和配置工程删除规则)

Makefile需要一口气生成若干个可执行文件,但你只想简单地敲一个make完事,并且,所有的目标文件都写在一个Makefile中,那么你可以使用“伪目标”这个特性:

all : prog1 prog2 prog3
.PHONY : all

prog1 : prog1.o utils.o
    cc -o prog1 prog1.o utils.o

prog2 : prog2.o
    cc -o prog2 prog2.o

prog3 : prog3.o sort.o utils.o
    cc -o prog3 prog3.o sort.o utils.o

.PHONY : all 声明了“all”这个目标为“伪目标”。 “all” 是一个伪目标,执行make不会生成“all”文件,而执行后面的多个目标。

.PHONY : cleanall cleanobj cleandiff

cleanall : cleanobj cleandiff
    rm program

cleanobj :
    rm *.o

cleandiff :
    rm *.diff

“make cleanall”将清除所有要被清除的文件。“cleanobj”和“cleandiff”这两个伪目标有点像“子程序”的意思。我们可以输入“make cleanall”和“make cleanobj”和“make cleandiff”命令来达到清除不同种类文件的目的。

1.4 静态模式(用起来也很爽)

静态模式可以更加容易地定义多目标的规则,可以让我们的规则变得更加的有弹性和灵活。

<targets ...> : <target-pattern> : <prereq-patterns ...>
    <commands>
    ...

targets定义了一系列的目标文件,可以有通配符。是目标的一个集合。
target-pattern是指明了targets的模式,也就是的目标集模式。
prereq-patterns是目标的依赖模式,它对target-pattern形成的模式再进行一次依赖目标的定义。

objects = foo.o bar.o

all: $(objects)

$(objects): %.o: %.c
    $(CC) -c $(CFLAGS) $< -o $@

上面的例子中,指明了我们的目标从$object中获取, %.o 表明要所有以 .o 结尾的目标,也就是 foo.o bar.o ,也就是变量 $object 集合的模式,而依赖模式 %.c 则取模式 %.o 的 % ,也就是 foo bar ,并为其加下 .c 的后缀,于是,我们的依赖目标就是 foo.c bar.c 。而命令中的 $< 和 $@ 则是自动化变量, $< 表示第一个依赖文件, $@ 表示目标集(也就是“foo.o bar.o”)。于是,上面的规则展开后等价于下面的规则:

foo.o : foo.c
    $(CC) -c $(CFLAGS) foo.c -o foo.o
bar.o : bar.c
    $(CC) -c $(CFLAGS) bar.c -o bar.o

1.5 显示命令(有助于调试makefile)

通常,make会把其要执行的命令行在命令执行前输出到屏幕上。当我们用 @ 字符在命令行前,那么,这个命令将不被make显示出来。

 正在编译XXX模块......

当make执行时,会输出“正在编译XXX模块……”字串,但不会输出命令,如果没
有“@”,那么,make将输出:

echo 正在编译XXX模块......
正在编译XXX模块......

如果make执行时,带入make参数 -n 或 --just-print ,那么其只是显示命令,但不会执行命令,这个功能很有利于我们调试我们的Makefile。

1.6 命令执行

如果你要让上一条命令的结果应用在下一条命令时,你应该使用分号分隔这两条命令。

exec:
    cd /home/hchen; pwd

当我们执行 make exec 时,cd起作用了,pwd会打印出“/home/hchen”。

1.7 命令出错

忽略命令的出错,可在Makefile的命令行前加一个减号 - (在Tab键之后),标记为不管命令出不出错都认为是成功的。如:

clean:
    -rm -f *.o

还有一个全局的办法是,给make加上 -i 或是 --ignore-errors 参数,那么,Makefile中所有命令都会忽略错误。

1.8 变量的定义和用法

变量在声明时需要给予初值,使用时在变量名前加上 $ 符号,最好用小括号 () 或是大括号 {} 把变量给包括起来。如果你要使用真实的 $ 字符,那么你需要用 $$ 来表示。

  • 变量中的变量(使用的是 := 操作符)
x := foo
y := $(x) bar
x := later

其等价于:

y := foo bar
x := later

这种方法,前面的变量不能使用后面的变量,只能使用前面已定义好了的变量。

还有一个比较有用的操作符是 ?= ,先看示例:

FOO ?= bar

其含义是,如果FOO没有被定义过,那么变量FOO的值就是“bar”,如果FOO先前被定义过,那么这条语将什么也不做,其等价于:

ifeq ($(origin FOO), undefined)
    FOO = bar
endif
  • 变量高级用法(变量值的替换)

替换变量中的共有的部分,其格式是 $(var:a=b) 或是 ${var:a=b} ,其意思是,把变量“var”中所有以“a”字串“结尾”的“a”替换成“b”字串。这里的“结尾”意思是“空格”或是“结束符”。

foo := a.o b.o c.o
bar := $(foo:.o=.c)

这个示例中,我们先定义了一个 $(foo) 变量,而第二行的意思是把 $(foo) 中所有以 .o 字串“结尾”全部替换成 .c ,所以我们的 $(bar) 的值就是“a.c b.c c.c”。

另外一种变量替换的技术是以“静态模式”

foo := a.o b.o c.o
bar := $(foo:%.o=%.c)

这依赖于被替换字串中的有相同的模式,模式中必须包含一个 % 字符,这个例子同样让 $(bar) 变量的值为“a.c b.c c.c”。

  • 变量高级用法(把变量的值再当成变量)
x = y
y = z
a := $($(x))

在这个例子中,((y),于是$(a)的值就是“z”。

1.9 使用条件判断

使用条件判断,可以让make根据运行时的不同情况选择不同的执行分支。条件表达式可以是比较变量的值,或是比较变量和常量的值。如:

判断 $(CC) 变量是否 gcc ,如果是的话,则使用GNU函数编译目标

libs_for_gcc = -lgnu
normal_libs =

foo: $(objects)
ifeq ($(CC),gcc)
    $(CC) -o foo $(objects) $(libs_for_gcc)
else
    $(CC) -o foo $(objects) $(normal_libs)
endif

1.10 指定目标

makefile都包含了编译、安装、打包等功能。我们可以参照这种规则来书写我们的makefile中的目标。

  • all:这个伪目标是所有目标的目标,其功能一般是编译所有的目标。
  • clean:这个伪目标功能是删除所有被make创建的文件。
  • install:这个伪目标功能是安装已编译好的程序,其实就是把目标执行文件拷贝到指定的目标中去。
  • print:这个伪目标的功能是例出改变过的源文件。
  • tar:这个伪目标功能是把源程序打包备份。也就是一个tar文件。
  • dist:这个伪目标功能是创建一个压缩文件,一般是把tar文件压成Z文件。或是gz文件。
  • TAGS:这个伪目标功能是更新所有的目标,以备完整地重编译使用。
  • check和test:这两个伪目标一般用来测试makefile的流程。

1.11 检查规则

有时候,我们不想让我们的makefile中的规则执行起来,我们只想检查一下我们的命令,或是执行的序列。
在这里插入图片描述

1.12 隐含规则(能够熟练应用可提升效率)

可以把隐含规则中使用的变量分成两种:一种是命令相关的,如 CC ;一种是参数相的关,如 CFLAGS 。

  • 关于命令的变量
    在这里插入图片描述
  • 关于命令参数的变量
    下面的这些变量都是相关上面的命令的参数。如果没有指明其默认值,那么其默认值都是空。
    在这里插入图片描述
  • 自动化变量
    在这里插入图片描述
    四个变量( $@ 、 $< 、 $% 、 $* )在扩展时只会有一个文件,而另三个的值是一个文件列表。

下面是对于上面的七个变量分别加上 D 或是 F 的含义:
在这里插入图片描述
对于 $< ,为了避免产生不必要的麻烦,我们最好给 $ 后面的那个特定字符都加上圆括号,比如, $(<) 就要比 $< 要好一些。

2.常用函数

在Makefile中可以使用函数来处理变量,从而让我们的命令或是规则更为的灵活和具有智能。

2.1 函数的调用语法

函数调用,很像变量的使用,也是以 $ 来标识的,其语法如下:

$(<function> <arguments>)

或是:

${<function> <arguments>}

参数间以逗号 , 分隔,而函数名和参数之间以“空格”分隔。函数调用以 $ 开头,以圆括号或花括号把函数名和参数括起。

comma:= ,
empty:=
space:= $(empty) $(empty)
foo:= a b c
bar:= $(subst $(space),$(comma),$(foo))

为了风格的统一,函数和变量的括号最好一样。

2.2 函数概览

在这里插入图片描述

具体用法见mikefile函数与实用模板
无法下载的可以在评论区@我。

  • 17
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值