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
目录
相关文章
|
6月前
|
编译器 Shell Linux
Makefile(3)进阶
Makefile(3)进阶
51 0
|
6月前
|
Linux 编译器 C语言
Linux应用开发基础知识——Makefile 的使用(二)
Linux应用开发基础知识——Makefile 的使用(二)
227 0
Linux应用开发基础知识——Makefile 的使用(二)
|
Java 编译器 Linux
Makefile教程(入门介绍)
Makefile教程(入门介绍)
114 0
|
Web App开发 存储 IDE
手把手教你使用LiteIDE配置Go语言开发环境
手把手教你使用LiteIDE配置Go语言开发环境
429 0
|
3月前
|
存储 Java Shell
CMake01快速上手
CMake01快速上手
|
3月前
|
编译器 测试技术 持续交付
深入了解CMake:高级技巧与最佳实践
【8月更文挑战第8天】在软件开发的世界里,构建系统扮演着至关重要的角色,它们确保了代码能够顺利编译、链接并生成可执行文件或库。CMake,作为跨平台的自动化构建系统,凭借其强大的灵活性和易用性,在众多项目中占据了主导地位。本文将深入探讨CMake的高级技巧与最佳实践,帮助你在工作和学习中更高效地使用CMake。
60 0
|
6月前
|
Linux 编译器 C语言
快速上手makefile自动化构建工具
快速上手makefile自动化构建工具
|
6月前
Makefile(1)入门
Makefile(1)入门
44 0
|
6月前
|
JSON 开发工具 开发者
CMake进阶教程:深入FetchContent与ExternalProject模块
CMake进阶教程:深入FetchContent与ExternalProject模块
488 0
|
6月前
|
编译器 Shell C语言
Makefile快速入门
Makefile快速入门
47 0