Makefile常用知识点总结
1. Makefile的格式
生成的目标(target,...):生成目标所需要的依赖(prerequisites,...)
生成目标用到的命令(command)
...
...
target通常为你要生成的目标文件包括可执行文件或者库文件,(也可以是仅仅是一个标签,即伪目标,不真实存在的目标,常见的伪目标是clean,用于清理编译生成的垃圾文件)。
prerequisites 生成该target 所依赖的文件和或其他target
command 该target 要执行的命令(任意的shell 命令)
Makefile就是一个定义可执行文件生成顺序关系的文件,根据定义的依赖关系,从首个目标开始通过递归的方式,查找需要的依赖,如果没有则调用其他的target的生成,并最终生成Makefile中首个定义的目标文件。每个target的生成通过下面的shell命令实现。
实例
例如我们要利用Makefile编译下main两个文件main.c、welcome.c生成可执行文件main
main.c:
#include<stdio.h>
void welcome();
int main()
{
printf("Hello World!\n");
welcome();
return 0;
}
welcome.c:
#include<stdio.h>
void welcome()
{
printf("Welcome to QingDao!\n");
}
所用到的gcc编译命令为
gcc -o main main.c welcome.c
这里我们只有一个生成目标,即可执行文件main,所以Makefile应该这样写
main:main.c welcome.c #目标:依赖
gcc -o main main.c welcome.c #生成目标所执行的命令
请记住这个文件后面的说明全部以它为例。
2. Makefile规则
使用变量
变量的含义可以理解成C语言中的宏定义,是一种字符串的替换。
比如上面的例子我们可以这样写:
CC=gcc
OBJ=main.c welcome.c
main:$(OBJ) #目标:依赖
$(CC) -o main $(OBJ) #生成目标所执行的命令
这样写的效果与第一小节的Makefile等价,科学地使用变量可以提高可维护性,便于Makefile的修改。
自动化变量
自动化变量可以理解成是Makefile规则中已经自动定义好的变量。
常见的自动化变量$@、$<、$^、$%和$?,常用的为u含义如下:
$@:目标的遍历值
$<:依赖的遍历值
$^:依赖的集合
$%:当库为生成目标时,库中所包含的成员名,不是库是为空
$?:所有比目标新的依赖目标的集合,以空格分割
常用的为前三个,在1节的Makefile文件中,他们代表的实际变量值
$@:依次代表"main",因为只有一个目标^_^
$<:依次代表"main.c"和"welcome.c"
$^:代表"main.c welcome.c"
清理
每个Make file中都应添加一个清理文件的规则(伪目标)clean,通过rm命令清理不必要的文件,这是建议而不是强制要求,为的是方便重新编译和保持文件的清洁。
通配符
Makefile中支持的通配符为*,?,~。
注意:变量的定义中不能直接使用通配符,需要配合使用函数。
~代表当前用户的家目录,Window下为HOME环境变量的值。
*代表任意字符,*.c代表所有的.c文件,故1节中的Makefile也可以写成这样:
main:*.c #目标:依赖
gcc -o main *.c #生成目标所执行的命令
3. Makefile中的函数
Makefile中的函数并不多这里我们介绍几个常用的其余可以借鉴《跟我一起写Makefile》。
Makefile中的函数跟变量的使用形式很像,也用$来标识,函数名与变量之间空格分隔,不同变量之间使用逗号,分割,其语法如下:
$(<function> <arguments>)
或是
${<function> <arguments>}
这里我们统一都是用圆括号(好记^_^)。
下面介绍几个常用的函数。
subst
${subst <from>,<to>,<text>}
将<text>这中的<from>字符全部替换成<to>字符,返回替换后的字符串
patsubst
${subst <from>,<to>,<text>}
与subst类似,不同的是patsubst会以单词为单位进行替换,查找单词是否符合<from>的规则,并将其替换成<to>中定义的形式。
filter和filter-out
$(filter <pattern>,<text>)
过滤函数,<pattern>为匹配规则不同的是filter保留符合规则的字符串,而filter-out去除符合规则的字符串。
以下不太常用
sort
$(sort <list>)
排序列表。
word
$(word <n>,<text>)
取
4. 生成库文件
无论是生成静态库还是动态库第一步都是生成与位置无关的.o文件。
gcc -fPIC -c *.c
生成动态库
gcc -shared -Wl,-soname,lib*so.l -o lib*so.1.10 *.o
生成静态库
静态库的生成依靠ar打包命令,如下:
ar rcs lib*.a *.o
使用动态库或者动态库只需要把库文件当作gcc的输入即可。
使用ldd命令可以查看可执行文件所以来的动态链接库,共享库使用中如果提示找不到动态链接库,需要将共享库所在目录添加到相应的ld.conf文件中,再使用ldconfig -v更新即可,系统会自动生成带主版本号的链接库文件,可执行文件按照编译时的主版本号查找动态链接库,主版本号相同代表可以兼容。
结束语
本文是作者个人对Makefile的学习过程的简单总结,方便新手入门,同时作者本人也在不断学习中,如果存在错误或者疏漏,欢迎大佬来指正错误和补充内容。
如果有大佬或者和我一样对Linux感兴趣的小伙伴欢迎找我私信交流学习经验。