Makefile从入门到上手 3

简介: Makefile从入门到上手

5、编译时的参数

还有一个扩展就是,编译时的参数, -g,-Wall 这些,可以放在 makefile 里面

修改后 makefile 如下:

Makefile 第十版

src = $(wildcard *.c) # hello.c add.c sub.c mul.c  div.c
obj = $(patsubst %.c, %.o, $(src)) # hello.o add.o sub.o mul.o div.o
myArgs = -Wall -g
ALL : a.out
$(obj) : %.o : %.c
  gcc -c $< -o $@ $(myArgs)
a.out : $(obj)
  gcc $^ -o $@ $(myArgs)
clean :
  -rm -rf $(obj) a.out
.PHONY : clean ALL

执行 make,如下:

6、make 的参数

参数:

  • -n:模拟执行 make、 make clean 命令。
  • -f:指定文件执行 make 命令。 xxxx.mk

如果 makefile 的名字变化一下,比如,叫 m6

用 m6 执行 makefile, make -f m6

用 m6 执行 clean make -f m6 clean

四、工程源码优化

将上述 .c 文件都放到 src 目录中,.h 文件都放在 inc 目录中,所生成的 .o 文件产物都放在 obj 目录中

使用 tree 命令查看树形结构拓扑

修改 makefile 如下,主要是注意 % 的匹配理解,只匹配文件名,目录位置要手动添加

Makefile 第十一版

src = $(wildcard ./src/*.c) # ./src/hello.c ./src/add.c ...
obj = $(patsubst ./src/%.c, ./obj/%.o, $(src)) # ./obj/hello.o ./obj/add.o ...
inc_path = ./inc
myArgs = -Wall -g
ALL : a.out
$(obj) : ./obj/%.o : ./src/%.c
  gcc -c $< -o $@ $(myArgs) -I $(inc_path)
a.out : $(obj)
  gcc $^ -o $@ $(myArgs)
clean :
  -rm -rf $(obj) a.out
.PHONY : clean ALL

执行 make 和 make clean,效果如下

如果 makefile 的名字变化一下,比如,叫 m6

用 m6 执行 makefile, make -f m6

用 m6 执行 clean make -f m6 clean


五、Makefile 语法

1、两种变量

在 Makefile 中有两种变量,一种称为即时变量(简单变量),另一种称为延时变量

  • 即时变量(简单变量)
  • A := xxx # A 的值即刻确定,在定义时即确定
  • 延时变量
  • B = xxx # B 的值使用到时才确定

编写下面一个 Makefile

A := abc
B = 123
all :
  @echo $(A)
  @echo $(B)

执行 make

从上面我们看不出即时变量和延时变量的差别,我们再对 Makefile 进行如下修改:

A := $(C)
B = $(C)
C = abc
all :
  @echo A = $(A)
  @echo B = $(B)

执行 make

可以看到 A 的值为空,B 的值为 abc,因为 A 为即时变量,在定义时即确定,所以为空

修改 Makefile 将 C 的赋值放在最后:

A := $(C)
B = $(C)
#C = abc
all :
  @echo A = $(A)
  @echo B = $(B)
C = abc

执行 make,可以发现结果并不受影响

因为当我们执行 make 的时候,会把 Makefile 整个文件读进来进行分析,然后解析里面的变量,所以变量 C 的赋值放在哪里并不受影响

2、赋值方法

:=    # 即时变量
=     # 延时变量
?=    # 延时变量,如果是第 1 次定义才起效,如果在前面该变量已定义则忽略这句
+=    # 附加,他是即时变量还是延时变量取决于前面的定义

①、+=(附加) 使用案例

如下 Makefile

A := $(C)
B = $(C)
C = 123
all :
  @echo A = $(A)
  @echo B = $(B)
C += abc

执行 make

②、?= 使用案例

修改 Makefile 如下:

A := $(C)
B = $(C)
C = 123
D = 777
D ?= 888
all :
  @echo A = $(A)
  @echo B = $(B)
  @echo D = $(D)
C += abc

执行 make

六、Makefile 函数

函数调用,很像变量的使用,也是以 $ 来标识的,其语法如下:

$(<function> <arguments>)

或是:

${<function> <arguments>}

这里, 就是函数名,make支持的函数不多。 为函数的参数,参数间以逗号 , 分隔,而函数名和参数之间以“空格”分隔。函数调用以 $ 开头,以圆括号或花括号把函数名和参数括起。

1、foreach 函数

foreach 函数和别的函数非常的不一样。因为这个函数是用来做循环用的,Makefile 中的 foreach 函数几乎是仿照于 Unix 标准 Shell(/bin/sh)中的 for 语句,或是 C-Shell(/bin/csh)中的 foreach 语句而构建的。它的语法是:

$(foreach <var>,<list>,<text>)

这个函数的意思是,把参数 <list> 中的单词逐一取出放到参数 <var> 所指定的变量中,然后再执行 <text> 所包含的表达式。每一次 <text> 会返回一个字符串,循环过程中, <text> 的所返回的每个字符串会以空格分隔,最后当整个循环结束时, <text> 所返回的每个字符串所组成的整个字符串(以空格分隔)将会是 foreach 函数的返回值。


所以, <var> 最好是一个变量名, <list> 可以是一个表达式,而 <text> 中一般会使用 <var> 这个参数来依次枚举 <list> 中的单词。举个例子:

如下 Makefile

names := a b c d
files := $(foreach n,$(names),$(n).o)
ALL:
  @echo $(files)

执行 make

上面的例子中, $(name) 中的单词会被挨个取出,并存到变量 n 中, $(n).o 每次根据 $(n) 计算出一个值,这些值以空格分隔,最后作为foreach函数的返回,所以, $(files) 的值是 a.o b.o c.o d.o 。

注意,foreach中的 <var> 参数是一个临时的局部变量,foreach函数执行完后,参数 <var> 的变量将不在作用,其作用域只在 foreach 函数当中。


2、filter 和 filter-out 函数

$(filter <pattern...>,<text>)
  • 名称:过滤函数
  • 功能:以 <pattern> 模式过滤 <text> 字符串中的单词,保留符合模式 <pattern> 的单词。可以有多个模式。
  • 返回:返回符合模式 <pattern> 的字串。
$(filter-out <pattern...>,<text>)
  • 名称:反过滤函数
  • 功能:以 <pattern> 模式过滤 <text> 字符串中的单词,去除符合模式 <pattern> 的单词。可以有多个模式。
  • 返回:返回不符合模式 <pattern> 的字串。

示例 Makefile 如下:

C = a b b d/
D = $(filter %/, $(C))
E = $(filter-out %/, $(C))
ALL:
  @echo D = $(D)
  @echo E = $(E)

执行 make

3、patsubst

$(patsubst <pattern>,<replacement>,<text>)
  • 名称:模式字符串替换函数。
  • 功能:查找 <text> 中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)是否符合模式 <pattern> ,如果匹配的话,则以 <replacement> 替换。这里, <pattern> 可以包括通配符 % ,表示任意长度的字串。如果 <replacement> 中也包含 % ,那么, <replacement> 中的这个 % 将是 <pattern> 中的那个 % 所代表的字串。(可以用 \ 来转义,以 % 来表示真实含义的 % 字符)
  • 返回:函数返回被替换过后的字符串。
  • 示例:$(patsubst %.c,%.o,x.c.c bar.c),把字串 x.c.c bar.c 符合模式 %.c 的单词替换成 %.o ,返回结果是 x.c.o bar.o
目录
相关文章
PADS原理图分页设计
当我们遇到原理图内容比较多,一个图页放不下时,我们就需要将原理图拆分成多个图页设计。比如分成MCU、POWER、CONNECT三个图页,如下图所示:
715 0
|
7月前
|
存储 Java API
Java Optional 完全指南:彻底告别 NullPointerException
Java 8 引入的 `Optional` 类旨在解决 `null` 带来的空指针异常问题,通过提供容器类显式处理可能为空的值,提升代码健壮性和可读性。本文从基础到进阶解析 `Optional` 的用法,涵盖创建、检查、获取值、处理值等核心功能,结合实际应用场景与最佳实践,助你彻底告别 `NullPointerException`,编写更优雅的 Java 代码。
384 0
|
10月前
|
存储 人工智能 弹性计算
云端问道6期方案教学-创意加速器:AI 绘画创作
本文整理自绍懿老师在云端问道第6期关于“创意加速器:AI绘画创作”的分享,主要介绍阿里云通义万相大模型的应用。内容涵盖七大部分:有趣的应用场景、通义万相简介、使用方法、优势特点、典型案例(如电商和营销场景)、收费标准及实操部署。通过这些内容,用户可以快速了解如何利用通义万相实现文字生成图片、图像编辑等功能,并应用于实际业务中,提升效率与创造力。
260 1
|
人工智能 自然语言处理 API
零一万物API开放平台,正式向开发者开放了!
零一万物API开放平台向开发者开放,提供多领域AI模型,包括自然语言处理、图像识别和语音识别,助力开发者轻松实现智能化功能。平台以简单API调用实现易用性,高性能计算资源保证服务稳定性。按需付费模式降低成本,免费体验机会鼓励尝试。全面的开发者支持包括详细文档、技术支持和定期技术交流会,构建友好社区。开发者需注意账户余额管理。访问平台:&lt;https://platform.lingyiwanwu.com/playground&gt;。
454 6
零一万物API开放平台,正式向开发者开放了!
|
jenkins 持续交付 开发者
利用Docker容器化部署应用的实战指南
【6月更文挑战第27天】本文详述Docker应用部署,涵盖Docker基本概念、安装、镜像制作及运行。通过编写Dockerfile构建镜像,使用`docker build`、`run`、`push`及`stop`命令管理。集成CI/CD工具如Jenkins,实现自动化构建、测试和部署,提升开发效率与部署质量。Docker助力轻量级、可移植的微服务架构。
|
小程序 JavaScript Java
基于SpringBoot+Vue+uniapp微信小程序的速达物流信息查询微信小程序的详细设计和实现
基于SpringBoot+Vue+uniapp微信小程序的速达物流信息查询微信小程序的详细设计和实现
214 0
|
机器学习/深度学习 人工智能 自然语言处理
从零开始的stable diffusion
从零开始的stable diffusion
534 0
|
人工智能 Serverless
构建AI助手:利用阿里云云函数计算FC快速构建“通义千问”
本文介绍了如何利用阿里云云函数计算(FC)快速构建一个强大的通义千问AI助手。通过阅读本文,您将能够利用阿里云云函数计算(FC)快速体验义千问AI助手。
5043 1
|
JavaScript API
vue数据更新但不改变视图,解决办法?
开发过程中会碰到数据更新,但是视图并未改变的情况,情况如下
981 0
|
SQL 存储 数据可视化
【Sql Server】存储过程通过定时执行添加记录作业
通过上篇了解了什么是存储过程,创建存储过程的方法,以及调用存储过程的方法 本次将通过数据库中的作业功能,进行定时执行存储过程,这样就可以完成我们刚开始假设的场景
851 0