Makefile笔记

  • 代码变成可执行文件,叫做编译(compile);先编译这个,还是先编译那个(即编译的安排),叫做构建(build)。
  • Make命令依赖Makefile文件里的命令进行构建,也可以自定义构建文件,如:指定make命令依据rules.txt文件中的规则,进行构建。
$ make -f rules.txt
# 或者
$ make --file=rules.txt
  • 要考虑的问题:要构建哪个文件?它依赖哪些源文件?当那些文件有变动时,如何重新构建它?
  • 穿插gcc相关指令

-g 可执行程序包含调试信息

-o 指定输出文件名

-c 只编译不链接,产生.o文件,就是obj文件,不产生执行文件

-pipe 使用管道代替编译中临时文件

-S 对源代码进行预处理、编译,不执行汇编、链接工作,有时我们想查看源代码的汇编代码,可以通过-S 选项实现

 -E 仅对源代码进行预处理(比如替换宏),这个选项不会像之前一样产生一个文件,而是直接将结果输出到屏幕

-D 定义宏,与源代码中#define指令定义的宏效果一样。

-v 将编译过程中运行细节显示在屏幕上(错误输出stderr),可以将编译器的每步工作细节都展现出来

-Wall 使GCC产生尽可能多的警告信息
警告信息虽然不能算作错误,但却很可能成为错误的来源。一个好的程序员应该尽量避免产生警告信息,使自己的代码始终保持标准、健壮。所以应将警告信息当成编码错误来对待
如果在编译程序时带上-Werror选项,那么GCC会在产生警告时停止编译
-I 指定头文件包含目录

-L 指定库文件目录,假定在/home/jie/lib目录下动态库文件libadd.so和静态库文件libadd.a

-std= 指定语言标准

GCC提供不同等级的代码优化功能。开关选项是:-On,n取值为0到3。默认为1。-O0表示没有优化,而-O3是最高优化。优化级别越高代码运行越快,但并不是所有代码都能够加载最高优化,而应该视具体情况而定。但一般都使用-O2选项,因为它在优化长度、编译时间和代码大小之间,取得了一个比较好的平衡点。
详细指令

举例:

max_num.exe: max_num.o max.o
    gcc -o max_num.exe max_num.o max.o
 
max_num.o: max_num.c max.h
    gcc -c max_num.c
 
max.o: max.c max.h
    gcc -c max.c
  •  每行命令之前必须有一个tab键。如果想用其他键,可以用内置变量.RECIPEPREFIX声明。
  • 模式匹配     

    %.o: %.c

 支持三个通配符:*, ?, [...]。可以用在规则中,也可以用在变量中

  • 变量和赋值符     

 

VARIABLE = value
# 在执行时扩展,允许递归扩展。

VARIABLE := value
# 在定义时扩展。

VARIABLE ?= value
# 只有在该变量为空时才设置值。

VARIABLE += value
# 将值追加到变量的尾端。

 $@指代当前目标

 $< 指代第一个前置条件

 $? 指代比目标更新的所有前置条件,之间以空格分隔

 $^ 指代所有前置条件,之间以空格分隔

 $* 指代匹配符 % 匹配的部分

 $(@D) 和 $(@F) 分别指向 $@ 的目录名和文件名

 $(<D) 和 $(<F) 分别指向 $< 的目录名和文件名

  • 判断和循环

Makefile使用 Bash 语法,完成判断和循环

语法

<条件语句>
<true 执行语句>
else
<false 执行语句>
endif

其中条件语句有四种情形:

1、表示是否相等

    ifeq (<arg1>, <arg2>)    # 推荐
    ifeq '<arg1>' '<arg2>'
    ifeq "<arg1>" "<arg2>"

2、表示是否不等,上面的 ifeq 换成 ifneq
3、ifdef
4、ifndef

  • 常用函数

字符串替换

$(subst <from>, <to>, <text>)

模式字符串替换

$(patsubst <pattern>, <replacement>, <text>)

去开头和结尾的空格

$(strip <string>)

查找字符串

$(findstring <find>, <in>)

反过滤

$(filter-out <pattern_or_string>, <text>)

排序(单词升序)

$(sort <list>)

取单词

$(word <n>, <text>)

取单词串

$(wordlist <n_start>, <n_end>, <text>)

单词个数统计

$(words <text>)

去掉每个单词的最后文件名部分,只剩下目录部分

$(dir <names ...>)

去掉每个单词的目录部分,只剩下文件名部分

$(notdir <names ...>)

读取各文件名的后缀

$(suffix <names ...>)

加后缀

$(addsuffix <suffix>, <names ...>)

加前缀

加前后缀在动态创建局部变量很有用
$(addprefix <prefix>, <names ...>)

连接字符串

$(join <list1>, <list2>)

for 循环

$(foreach <var>, <list>, <text>)
这其实是一个函数,作用是:将 list 的单词逐一取出,放到 var 指定的变量中,然后执行 text 的表达式。返回值则是 text 的最终执行值。

shell 函数

执行 shell 命令,并且将 stdout 作为返回值返回,如:
contents := $(shell ls -la)

控制 make 输出

$(error <text ...>)
$(warning <text ...>)
这也同时是调试和定位 make 的好方法。

判断文件是否存在

 
ifeq ($(FILE), $(wildcard $(FILE)))
...
endif
  • 参考链接:

https://www.ruanyifeng.com/blog/2015/02/make.html

https://segmentfault.com/a/1190000012091117

 

上一篇:Linux基础命令more


下一篇:Linux C : Makefile 的编写和示例