前言

本文通过简单的几个示例,以及对同一个Makefile进行几个版本的迭代,帮助快速的理解变量和模式规则的使用。

1、回顾

在上一篇文章中,我们使用Makefile编译fun.c和main.c这两个文件,最终生成名为app的可执行文件。

fun.c的内容

#include <stdio.h>

void fun()
{
printf("This is fun()!\n");
}

main.c的内容

extern void fun(); 

int main()
{
fun();
return 0;
}

第一版Makefile

.PHONY:clean

all: main.o fun.o
gcc -o app main.o fun.o
main.o : main.c
gcc -o main.o -c main.c
fun.o : fun.c
gcc -o fun.o -c fun.c
clean:
rm app main.o fun.o

可以发现,Makefile里面有很多重复的内容,我们可以利用变量和模式规则对其进行优化。

2、自动变量

\(@:用于表示一个规则中的目标。当有多个目标时,\)@指的是其中任何导致规则命令被运行的自标。

$^:表示的是规则中的所有先决条件。

$<:表示的是规则中的第一个先决条件。

是不是看得有点晕?没关系,我们基于上面的Makefile,做一点点修改,把这些东西都打印出来看一下,就很清楚了。

.PHONY:clean

all: main.o fun.o
gcc -o app main.o fun.o @echo "\$$@ = $@"
@echo "$$^ = $^"
@echo "$$< = $<" main.o : main.c
gcc -o main.o -c main.c
fun.o : fun.c
gcc -o fun.o -c fun.c
clean:
rm app main.o fun.o

运行make,终端打印如下内容

gcc -o app main.o fun.o
$@ = all
$^ = main.o fun.o
$< = main.o

了解到这些之后,我们再次修改

第二版Makefile

.PHONY:clean

all: main.o fun.o
gcc -o app $^ main.o : main.c
gcc -o $@ -c $^
fun.o : fun.c
gcc -o $@ -c $^
clean:
rm app main.o fun.o

3、变量的类别与赋值

变量的类别有递归扩展变量和简单扩展变量

3.1 递归扩展变量

这种只用一个“=”符号定义的变量被称为递归扩展变量

.PHONY:all

goal = $(mid)
mid = $(fun)
fun = test all:
@echo "goal = $(goal)"

运行make命令 ,打印如下

goal = test

3.2 简单扩展变量

用“:=”操作符来定义的,make只对其进行一次展开。

.PHONY:all

goal_A = hello
mid_A = $(goal_A) world
goal_A = test goal_B := hello
mid_B := $(goal_B) world
goal_B := test all:
@echo "mid_A = $(mid_A),mid_B= $(mid_B)"

运行make命令 ,打印如下

mid_A = test world,mid_B= hello world

3.3 变量条件赋值

用“?=”操作符来定义,如果变量没有被定义,将右边的值赋值给它,如果变量已经定义了,则不改变其原值。

.PHONY:all

funA = original
funA ?= replacement funB ?= replacement
all:
@echo "funA = $(funA),funB = $(funB)"

运行make命令 ,打印如下

funA = original,funB = replacement

3.4 变量追加赋值

通过“+=”实现追加赋值

.PHONY:all

objects = main.o fun.o
objects += append.o all:
@echo "objects = $(objects)"

运行make命令 ,打印如下

objects = main.o fun.o append.o

3.5 高级变量引用功能

在赋值的同时,完成文件名后缀替换操作

.PHONY:all

src = a.c b.c c.c
objs := $(src:.c=.o) all:
@echo "objs = $(objs)"

运行make命令 ,打印如下

objs = a.o b.o c.o

注意,src:.c=.o 冒号后面不能有空格,如果加了空格变成src: .c=.o ,运行make,打印的结果如下

objs = a.c b.c c.c

4、模式规则

一个模式规则的格式为:

%.o : %.c
command...

我们利用模式规则对第二版的Makefile进行优化

第三版Makefile


#替换掉这部分
#main.o : main.c
# gcc -o $@ -c $^
#fun.o : fun.c
# gcc -o $@ -c $^ .PHONY:clean all: main.o fun.o
gcc -o app $^
%.o : %.c
gcc -o $@ -c $^
clean:
rm app main.o fun.o

这里将两条构建目标文件的规则变成了一条

" % " 类似于通配符,%.c匹配所有以".c "结尾的文件,采用了模式以后,不管有多少个源文件,都可以用同一条规则,可以极大的简化Makefile

5、利用变量和模式规则优化Makefile

我们再对第三版的Makefile进行优化,将编译器,目标等都用变量替代,这样以后修改只需要改动变量部分就好了

第四版Makefile

.PHONY:clean

CC = gcc
RM = rm TARGET = app
OBJS = main.o fun.o $(TARGET) : $(OBJS)
$(CC) -o $@ $^
%.o : %.c
$(CC) -o $@ -c $^
clean:
$(RM) $(TARGET) $(OBJS)

到这里,Makefile已经得到了很大的改善,但是我们可以看到OBJS = xxxx 这里,如果文件数量多,得一个个书写,还是不够智能。

下一篇文章,将介绍Makefile函数的使用,利用函数可以轻松管理好源文件和目标文件。

————————————————————————————————

码字不易,点个赞再走吧!

欢迎关注我的同名公众号,这里有更多好料等着你哦!

轻松玩转makefile | 变量与模式的更多相关文章

  1. 完整版的CAD技巧!3天轻松玩转CAD,零基础也能学会

    最近有很多小伙伴反应,CAD图纸学起来有点小困难,也许你还没能掌握技巧,CAD大神带你3天轻松玩转CAD,零基础也能快速学会. 一.看懂图纸是关键 CAD制图首先得让自己知道要绘制什么,如果心中对图纸 ...

  2. vue-cli3.0 环境变量与模式

    vue-cli3.0移除了配置文件目录: config和build文件夹.可以说是非常的精简了,那移除了配置文件目录后如何自定义配置环境变量和模式呢? 为什么需要配置环境变量和模式呢? 所有方法肯定是 ...

  3. 2021 .NET Conf China 主题分享之-轻松玩转.NET大规模版本升级

    去年.NET Conf China 技术大会上,我给大家分享了主题<轻松玩转.NET大规模版本升级>,今天把具体分享的内容整理成一篇博客,供大家研究参考学习. 一.先说一下技术挑战和业务背 ...

  4. Vim 的补全模式加速器,轻松玩转全部 15 种自动补全模式

    1. 关于 Vim 补全模式    ---- Vim 一共提供了 15 种自动补全的模式(:help ins-completion).其中有两种的补全列表内容与另外两种相同,只是排序不同,这 15 种 ...

  5. 干货: 可视化项目实战经验分享,轻松玩转 Bokeh (建议收藏)

    作者 | Will Koehrsen 翻译 | Lemon 译文出品 | Python数据之道 (ID:PyDataRoad) 本文通过一个项目案例,详细的介绍了如何从 Bokeh 基础到构建 Bok ...

  6. Makefile变量

    自定义变量 = 是最基本的赋值,会把整个makefile展开之后再决定是多少 x=foo y=$(x)bar #y是asdbar,不是foobar x=asd := 是覆盖之前的值,和=不同,和赋值的 ...

  7. makefile笔记5 - makefile变量

    在 Makefile 中的定义的变量,就像是 C/C++语言中的宏一样,他代表了一个文本字串,在 Makefile 中执行的时候其会自动原模原样地展开在所使用的地方.其与 C/C++所不同的是,你可以 ...

  8. makefile 变量展开

    Makefile中给变量赋值: =     是递归展开式变量 value1 = 5 value2 = $(value1) value1 = 6 最终$(value2)就变成了6 :=    是直接展开 ...

  9. 【 MAKEFILE 编程基础之三】详解 MAKEFILE 变量的定义规则使用!

    本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/gcc-makefile/770.html   ...

  10. 架构篇 | 带你轻松玩转 LAMP 网站架构平台(一)

    作者 | JackTian 微信公众号 | 杰哥的IT之旅(ID:Jake_Internet) 转载请联系授权(微信ID:Hc220066)备注:来自博客园 1.什么是 LAMP 架构? LAMP 架 ...

随机推荐

  1. Vue之将前端的筛选结果导出为csv文件

    有导入就有导出哈!这里继导入之后记录一下导出的实现过程. 1.按钮部分: <el-button class="filter-item" style="margin- ...

  2. 04 Tcl字符串

    Tcl字符串 4.1 Tcl将说有的变量值视作字符串,并将他们作为字符串进行保存. 命令 描述 append 将值追加到字符串尾 binary 二进制化字符串 format 字符串格式化 regexp ...

  3. 2023浙江省大学生信息安全竞赛技能赛初赛 部分wp

    CRYPTO 小小数学家 1.题目信息 查看代码 19+49=? 96-31=? 86-3=? 20+47=? 29+55=? 35+35=? 81+42=? 73-16=? 52+48=? 0+56 ...

  4. java - classpath 的配置

    classpath C:\Program Files\Java\jdk\jre\lib\rt.jar

  5. [转帖]ls 只显示目录

    https://www.cnblogs.com/lavin/p/5912369.html 只显示目录: ls -d */ 在实际应用中,我们有时需要仅列出目录,下面是 4 种不同的方法. 1. 利用 ...

  6. [转帖]028.PGSQL-用户创建、表空间创建、数据库创建、schema创建、表创建、生成测试数据、指定搜索路径、

    https://www.cnblogs.com/star521/p/15054341.html  登录数据库 su postgres #注意这里postgers 前后都有空格 psql -U post ...

  7. [转帖]PostgreSQL 参数优化设置 32GB内存(推荐) 内存参数 检查点 日志参数 自动初始化参数shell脚本

    1.修改参数列表 (1)执行计划 enable_nestloop = off #默认为on enable_seqscan = off #默认为on enable_indexscan = on enab ...

  8. [转帖]Redis中的Lua脚本

    最近琢磨分布式锁时接触到的知识点,简单记一下. 文章目录 1. Redis中的Lua 2. 利用Lua操作Redis 3. Lua脚本的原子性 4. 关于 EVALSHA 5. 常用`SCRIPT` ...

  9. [转帖]Ubuntu Server安装图形界面

    最早接触到的Linux系统是Ubuntu 10.04,当时在自己的一台Win7笔记本电脑上安装的Win/Ubuntu双系统,Ubuntu简洁的操作界面给我留下了深刻的印象. 后来开始做一些服务器开发, ...

  10. Spring源码——初识Spring容器

    Spring源码之工厂(容器) 为什么把Spring的工厂又叫做容器呢? 工厂的责任是创建对象,但是创建完对象后还要进行存储(针对于单例的对象来讲),以供其他地方使用,这就是容器.为了能存多个对象,并 ...