目录
makefile
- 定义了一系列编译规则的文档,可使用make命令“自动编译”,极大提供开发效率;
- 一个工程中,源文件按类型、功能、模块会分别存放在若干个目录中,哪些文件需先编译、哪些文件需后编译、哪些文件需重新编译,甚至更复杂的功能操作,均可在makefile中指定;
make
- 是一个解释makefile中指令的命令工具,大多数IDE都有此命令;
- 执行make时,会在当前目录下搜索makefile,查找目标及其依赖,然后执行相关命令;
[wz@VM-4-4-centos ~]$ which make /usr/bin/make [wz@VM-4-4-centos ~]$ whereis make make: /usr/bin/make /usr/share/man/man1/make.1.gz [wz@VM-4-4-centos ~]$ whatis make make (1) - GNU make utility to maintain groups of programs
一,GNU make工作流程
- 读入主makefile,主makefile中可引用其他makefile;
- 读入被include的其他makefile;
- 初始化文件中的变量;
- 推导隐含规则,并分析所有规则;
- 为所有目标文件创建依赖关系链;
- 根据依赖关系,决定哪些文件需要重新生成;
- 执行命令;
二,makefile规则
基本格式
target : prerequisites
[前缀]command
//或
target : prerequisites; command
[前缀]command
- target,目标文件(可以是object file,也可是可执行文件,还可为标签);
- prerequisites,生成目标文件所依赖的文件或目标(可以多个,或没有);
- command,make时执行的命令(任意shell命令,可以有多条);
- [前缀]
- 不加,打印命令及命令结果,出错停止执行;
- @,只打印命令结果,出错停止执行;
- -,忽略命令出错,继续执行;
显示规则:说明如何生成一个或多个目标文件(包括生成的文件、依赖的文件,命令);
隐含规则:make自动推导功能所执行的规则;
变量定义:makefile中定义的变量;
文件指示:makefile中引用的其他makefile,指定makefile中有效部分,定义一个多行命令;
注释:行注释“#”,转义注释符“\#”;
工作流程
- make,默认执行第一个目标;
- target不存在,会依据其规则创建;
- target存在,其依赖src比target“更新”,会重新编译;
- target存在,其依赖src不比target“更新”,什么都不做;
通配符
- *,表示零个或任意个字符;
- ?,表示任意一个字符;
- ex. [abcd] ,表示a,b,c,d中任意一个字符;
- [^abcd],表示除a,b,c,d以外的字符;
- [0-9],表示 0~9中任意一个数字;
- %,匹配任意字符;
- ~,表示家目录;
变量定义及赋值
- VAR_LIST = val1 val2 val3 ...
- :=,简单赋值;
- =,递归赋值;
- ?=,条件赋值;
- +=,追加赋值;
自动化变量
- $@,目标文件名;
- $<,第一个依赖文件名;
- $^,所有依赖文件列表;
- $?,所有比目标文件新的依赖文件列表;
搜索路径
- 默认在makefile当前路径下搜索源文件;
- 特殊变量VPTH,可指定路径;
- VPATH <directories> ,当前目录未找到,则会在此目录下查找;
- VPATH <pattern> <directories>,符合pattern格式的文件,在此目录下查找;
- VPATH <pattern>,清除符合pattern格式的文件查找目录;
- VPATH,清除查找目录;
- 关键字vpth,可指定路径;
- vpth <pattern> <directories>,符合pattern格式的文件,在此目录下查找;
- vpth <pattern>,清除符合pattern格式的文件查找目录;
- vpth,清除查找目录;
//当前目录未找到会在../dir1和../dir2中查找
VPATH = ../dir1 : ../dir2
VPATH = ../dir1 ../dir2
vpath ../dir1 : ../dir2 //当前目录未找到会在../dir1和../dir2中查找
vpath %.d ./header //以.h结尾的文件都从./header内查找
vpath %d //清除.h结尾的文件的查找规则
vpath //清除所有查找规则
隐含规则
[wz@VM-4-4-centos ~]$ ls
makefile src.c
[wz@VM-4-4-centos ~]$ cat makefile
target:src.o
gcc $^ -o $@
[wz@VM-4-4-centos ~]$ make
cc -c -o src.o src.c
gcc src.o -o target
[wz@VM-4-4-centos ~]$ ls
makefile src.c src.o target
上述makefile文件缺少生成src.o命令,但make后,依然可生成src.o、target,是因为隐含规则的作用;
执行make的过程中,找到隐含规则,提供此目标的基本依赖关系,确定目标的依赖文件和使用命令;隐含规则提供的依赖文件只是基本的文件,需增加依赖文件时则要额外给出;
target:src.o
gcc $^ -o $@
target:src.h
条件判断
- ifeq,判断参数是否相等,相等为true;
- ifeq(arg1,arg2)
- ifneq,判断参数是否不相等,不相等为true;
- ifneq(arg1,arg2)
- ifdef,判断是否有值,有值为true;
- ifdef variablename
- ifndef,判断是否无值,无值为true;
- ifndef variablename
[wz@VM-4-4-centos tmp]$ cat makefile
arg = no
all:
ifeq ($(arg),yes)
@echo $(arg)=yes
else
@echo $(arg)=no
endif
[wz@VM-4-4-centos tmp]$ make
no=no
伪目标
- 伪目标即并非一个目标,不生成目标文件,且总是可执行的;
- make,如源文件没有更新,只执行一次;
- 声明伪目标即将目标作为.PHONY的依赖;
- 如.PHONY:clean;
- 不加此声明可能会与真正目标文件产生冲突;
//被.PHONY修饰的目标,均是总是可执行的
.PHONY:clean
clean:
rm -rf *.o test
三,案例
倒计时
原位置刷新数字;
- 刷新方式
- 直接刷新,不缓冲;
- 缓冲区写满,在刷新,即全缓冲;
- 遇到\n刷新,行刷新;
- 强制刷新,fflush(stdout);
#include<stdio.h>
#include<unistd.h>
int main()
{
int count = 10;
while(count >= 0)
{
printf("%2d\r",count);
fflush(stdout);
count--;
sleep(1);
}
return 0;
}
进度条
注,可能打印的是多行,把终端窗口宽度调大即可打印为一行;
printf,有颜色控制;
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#define NUM 100
int main()
{
int i = 0;
char bar[NUM+2];
memset(bar,0,sizeof(bar));
const char* label = "|/-\\";
while(i<=NUM)
{
bar[i] = '#';
printf("[%-101s][%d%%][%c]\r",bar,i,label[i%4]);
fflush(stdout);
i++;
usleep(100000);
}
printf("\n");
return 0;
}