Linux —— 自动化构建工具make/makefile

本文详细解读了GNU Make的工作流程,包括makefile规则的基础格式、通配符、变量、搜索路径和隐含规则,还通过倒计时和进度条案例展示了实际应用。理解并掌握这些内容,将大大提高软件开发过程中的编译效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一,GNU make工作流程

二,makefile规则

基本格式

工作流程

通配符

变量定义及赋值

搜索路径

隐含规则

条件判断

伪目标

三,案例

倒计时

进度条


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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值