本文是我在对Makefile学习完后的一个记录总结,大多讲的都是一些值得注意或很常遇到的点,具体详细的Makefile操作在我这里是看不到的,这种网上有很多,建议大家积极Google。如果文中内容有误,还望在评论中提出,我会及时更正,感谢!
参考记录:
https://zhuanlan.zhihu.com/p/317716664
及部分没记住的大佬文献,尴尬,~_~
实际使用体验补充,这部分后面才是正文 !!!
更新时间 ----------------------------------- 2022 / 8 / 9
最近,为了加强对多线程的学习,我也是按照网上的教程重新敲了一遍相关的代码,但是由于涉及的代码要经常变动,需要重复的一句一句敲指令去编译.c文件,敲烦了,于是就写了个简单的Makefile来用,发现是真的好用,每次敲个make就行了,这感觉,谁用谁知道,嘿嘿!下面是我的实际应用展示:
在我没有用Makefile时,是这样敲的(虽然可以一句敲完 gcc test.c -o test -lpthread,但这个只是使用Makefile的栗子,请别在意):
但是每次敲的烦啊,就算是用上下键来切指令,一旦你后面敲的指令太多,把这两句编译指令后推太多的话,找的也是很麻烦的,于是,我就决定用Makefile来解决这种尴尬的问题:
写完后,手不疼了,脚也瞬间麻溜了,哈哈,之后,我每次改完文件后,敲下make就好了:
所以说,Makefile还是有必要学的,简直是生产力一大助力啊,哈哈~~
1、Linux下把.c文件编成可执行文件
Linux 下是采用 gcc 命令来进行代码编译等操作的。通常,我们可以选择采取一步到位的方式,即 gcc test.c -o test
当然了,我们也可以分步骤来进行相应的操作,具体如下:
预编译:生成 .i 文件,使用的 gcc 命令是:gcc -E test.c -o test.i
编译: 生成 .s 文件,使用的 gcc 命令是:gcc -S test.i -o test.s
汇编: 生成 .o 文件,使用的 gcc 命令是:gcc -C test.s -o test.o
链接: 生成 可执行文件,使用的 gcc 命令是:gcc test.o -o test (动态)、gcc test.o -o test_st – static (静态)
其中,链接又可以分为 静态链接 和 动态链接:
【1】 静态链接:函数的代码将从其所在地静态链接库中被拷贝到最终的可执行程序中
【2】 动态链接:函数的代码被放到称作是动态链接库或共享对象的某个目标文件中
2、Makefile
2.1 make
make工具 类似于批处理工具,可以对多个源文件进行批量的编译和链接
make 本身不具备编译和批处理功能,它只是一个根据指定的 Shell命令 进行构建的工具,通过调用 Makefile文件 中的命令来实现编译和链接
2.2 Makefile
Makefile 是一个文本文件,包含了 make工具,文本中记录了所需要执行的一系列规则,通过 make 来进行执行
3、Makefile文件格式
3.1 格式
Targets : Prerequisites
[Tab]Command
3.2 格式解析
【1】 Targets 是要生成的目标文件:
一个目标构成一条规则,目标通常为文件名(还可以是某个操作的名字:伪目标),可以是一个文件名,也可以是多个文件名(之间用空格分隔)
Makefile 中把那些无何依赖只有执行动作的目标称为 “ 伪目标 “ ,为了将 Targets 强声明为 “ 伪目标 ”,可以通过 .PHONY : name 来进行,例如:
.PHONY : clean
clean :
-rm *.o temp
【2】 Prerequisites 为要生成 targets 所需要的文件或是目标:
通常是一组文件名(用空格分隔);只要有一个前置文件不存在,或是有过更新(前置文件的时间戳 比 目标文件的时间戳),目标文件就需要重构
【3】 Command 为规则的命令行,必须以 [Tab] 开始,是 make 需要执行的命令
可由一行或多行的 Shell命令 组成;每行命令在一个单独的 Shell 中执行,这些 Shell 之间没有继承关系,如:(代码执行后,会取不到 foo 的值,因为两行命令在不同的进程执行)
var-lost:
export foo=bar
echo "foo=[$$foo]"
【4】 [TAB] 是默认的,如果想要其他键,可修改内置的变量 .RECIPEPREFIX
如:(我们可以把 [TAB] 换成 [>] )
.RECIPEPREFIX = >
all:
>echo 'Hello, World'
3.2 注意
【1】 “目标” 是必须的,“前置条件” 和 “命令” 都是可选的,但二者之中必须至少存在一个
【2】 如果 make命令 运行时没有指定目标,会默认执行 Makefile文件 的第一个目标
4、Makefile的语法
4.1 注释
#
4.2 回声(echoing)
正常情况下,make 会打印每条命令,然后再执行,这就叫回声
在命令行前加上 ’ @ ’ ,就可以关闭回声
由于在构建中,需要了解当前在执行哪条命令,所以通常只在注释和纯显示的 echo 前面加上 @
4.3 通配符
用来指定一组符合条件的文件名,其与 bash 一致
4.4 模式匹配
make命令 允许对文件名进行类似的正则运算符的匹配,主要用到的匹配符是 " % "
如,将当前目录下的 .c 文件全部编译为 .o :
bash %.o : %.c
4.5 变量和赋值符
Makefile 允许使用符号自定义变量 调用Shell变量时需要加一个 $ ,因为make命令会对 $ 符号转义
其中,还对 =号 进行了相应的扩展(=、:=、?=、+=)
【1】VARIABLE = value -> 在执行时扩展,允许递归扩展
【2】VARIABLE := value -> 在定义时扩展
【3】VARIABLE ?= value -> 只有在该变量为空时才设置值
【4】VARIABLE += value -> 将值追加到变量的尾端
4.6 内置变量
【1】$(CC) — 指向当前使用的编译器
【2】$(MAKE) — 指向当前使用的make工具,如:
output:
$(CC) -o output input.c
4.7 自动变量
make命令 还提供一些自动变量,它们的值与当前的规则有关。
【1】$@
指代当前目标,就是make命令当前构建的那个目标
a.txt b.txt: a.txt:
touch $@ -> touch a.txt
b.txt:
touch b.txt
【2】$<
指代第一个前置条件
a.txt: b.txt c.txt a.txt: b.txt c.txt
cp $< $@ -> cp b.txt a.txt
【3】$?
指代比目标更新的所有前置条件,之间以空格分隔,如:
t: p1 p2
其中,p2的时间戳比t新,$?就指代p2
【4】$^
指代所有前置条件,之间以空格分隔
【5】$
指代匹配符 % 匹配的部分,如:
% 匹配 f1.txt 中的 f1,$ 就表示 f1
【6】$(@D) 和 $(@F)
$(@D):$@ 的目录名
$(@F):$@ 的文件名
如: $@ 是 src/input.c,那么 $(@D) 的值为 src,$(@F)的值为 input.c
【7】$(<D) 和 $(<F)
$(<D):$< 的目录名
$(<F):$< 的文件名
4.8 Makefile函数
4.8.1 常函数
$(function arguments) / ${function arguments}
4.8.2 内置函数
【1】Shell 函数
srcfiles := $(shell echo src/{00...99}.txt)
【2】wildcard 函数,用在 Makefile 中替换 bash 的通配符
srcfiles := $(wildcard src/*.txt)
【3】subst 函数,用来替换文本
$(subst from, to, next)
例如,将字符串 " feet on the street " 替换成 " fEEt on the strEEt " :
$(subst ee, EE, feet on the street)
【4】patsubst 函数,用于模式匹配的替换
$(patsubst pattern, replacement, text)
例如,将文件名 " x.c.c、bar.c " 替换成 " x.c.o、bar.o " :
$(patsubst %.c, %.o, x.c.c bar.c)
【5】替换后缀名,实际上它是 patsubst 函数的简写形式
写法:变量名 + 冒号 + 后缀名替换规则
min: $(OUTPUT : .js=.min.js)
【6】foreach 函数
【7】filter 函数