一、退出码
make运行结束后会返回一个退出码
0:执行成功
1:通用错误
2:错误的shell命令语法
126:无法执行命令,因为它不具有可执行权限
127:未找到指定的命令
128:命令执行失败,因为它被信号中断
130:命令执行被Ctrl+C终止
注意:不同操作系统可能会对执行码进行稍微的调整
二、伪目标
伪目标是Makefile中一种特殊目标,表示不会生成与之对应的文件
通常用于表示一些特殊操作,如清理文件、打包文件等操作,使用".PHONY"指令,可以告诉Makefile该目标不对应任何实际文件
all:默认目标,构建程序的所有组件
clean:清理生辰的目标文件和临时文件
distclean:彻底清理所有生成的文件,包括配置文件和备份文件等
install:安装程序或库到系统中
uninstall:从系统中卸载程序或库
check/test:运行测试makefile流程的套件
debug:构建带有调试信息的二进制文件
release:构建发布版本的程序,通常会关闭调试选项并启用优化
docs/doc:构建文档
print:列出改变过的源文件
tar:把源程序打包成tar文件
dist:创建一个压缩文件,一般是把tar文件压缩成Z文件或是gz文件
TAGS:更新所有目标,以备完整地重编译使用
注意:伪目标不应该与实际的文件名重名,否则可能会导致意外发生
三、自动化变量
Makefile中提供的特殊变量,用于表示正在构建的文件名、文件路径等动态信息
使用自动化变量,可以避免在Makefile中硬编码文件名或路径,使Makefile更加灵活和通用
1、基础
$@:表示规则中的目标文件名,例如在"all:target1 target2"中代表"target1 target2"
$<:表示第一个依赖文件的文件名,例如在"all:target1 target2"中代表"target1"
$^:表示规则中所有依赖文件的文件名,并去除重复项,例如在"target:foo.c bar.c foo.c"中代表"foo.c bar.c"
$+:表示规则文件中所有依赖文件的文件名,与"$^“不同在于会将重复出现的依赖文件都包括在内,例如在"target:foo.c bar.c foo.c"中代表"foo.c bar.c foo.c”
$?:表示所有比目标文件更新的依赖文件列表(新更新的文件),以空格分隔
$*:表示目标文件除去后缀名之后的部分,例如在"target1.c target2.o"中代表"target1 target2"
$=:表示makefile中定义的变量的值
$%:表示目标文件去除前缀与后缀之后的部分,例如在"/src/foo/bar.c"中代表"bar"
2、扩展
$(@D):表示目标文件所在的目录路径
$(@F):表示目录文件名本身,不包括路径
$(<D):表示第一个依赖文件所在的目录路径
$(<F):表示第一个依赖文件名本身,不包括路径
$(^D):表示所有依赖文件所在的目录路径,以空格分隔
$(^F):表示所有依赖文件名本身,以空格分隔
$(+D):表示所有依赖文件(包括重复的)所在的目录路径,以空格分隔
$(+F):表示所有依赖文件名(包括重复的)本身,不包括路径,以空格分隔
$(*D):表示通配符匹配的所有文件所在的目录路径
$(%F):表示通配符匹配的所有文件名本身,不包括路径
$(?D):表示通配符匹配条件的依赖文件所在的目录路径
$(?F):表示通配符匹配条件的依赖文件名本身
四、双后缀
双后缀规则就是指一个特定的目标文件匹配到两个后缀名,但其依赖文件的后缀不同,因此也会有不同的规则适用于不同的依赖
通过这种方式,可以使用不同的规则来生成不同的对象文件
假设,现在有一个源文件"program.c",要编译成静态库和动态库两个版本,分别使用".a"和".so"作为文件扩展名
CC = gcc
CFLAGS = -Wall -O
#静态库目标
libprogram.a:program.o
ar rcs $@ $^
#动态库目标
libprogram.so:program.o
$(CC) -shared -o $@ $^
#编译源文件
program.o:program.c
$(CC) $(CFLAGS) -o $@ -c $<
#清理文件
clean:
rm -f *.o *.a *.so
五、文件打包
打包文件是一个常见的任务,通常使用"Tar"命令将一些文件打包成一个归档文件,该归档文件可以用于备份、传输和发布等目的
1、定义变量
在Makefile中首先需要声明需要打包的文件列表,定义用于打包的文件和目录的变量
SRCS = src/main.c src/util.c
INCS = include/util.h
DOCS = readme.md
2、定义目标文件
定义打包文件的目标文件名及其依赖关系,编写归档命令(本案例用"tar"),并指定文件名为"myapp.tar"
dist/myapp.tar:$(SRCS) $(INCS) $(DOCS)
tar czf $@ $(SRCS) $(INCS) $(DOCS)
#或
tar czvf myapp.tar $(SRCS) $(INCS) $(DOCS)
“c”:表示创建归档文件
“z”:表示对归档文件进行gzip压缩
“v”:表示显示进度信息
“f”:表示指定输出文件
3、添加规则(可选)
由于打包目标不代表任何实际的文件名,因此应将打包目标声明为伪目标或者如果需要在重新生成打包文件时删除旧的打包文件,也可以加一个清理规则
.PHONY:myapp
clean:
rm -f dist/myapp.tar
4、执行命令
在打包文件时,还可以添加其他选项和参数来控制打包方式和压缩算法,比如通过"-C"选项可以指定打包文件的根目录
dist/myapp.tar: $(SRCS) $(INCS) $(DOCS)
tar czf $@ -C src $(SRCS) -C include $(INCS) -C . $(DOCS)
这里将"$(SRCS)“和”$(INCS)“添加到"src"目录下,将”$(DOCS)"添加到当前目录下并打包成"myapp.tar"文件
此外打包格式还有"zip"、“rpm”、"deb"等,不同打包格式需要使用不同的打包工具和命令行参数,具体参考对应格式的文档和说明