Makefile基础教程(变量的高级主题,变量的拓展)

简介: Makefile基础教程(变量的高级主题,变量的拓展)

前言

本篇文章将给大家讲解一下变量的高级主题,变量的拓展,这些主题可以让你更加灵活地编写和维护 Makefile。


一、变量值的替换

1.简单替换

变量替换语法格式:

$(var:a=b)

其中,a 可以是一个字母,表示 var 中每个单词结尾的这个字母。b 则是替换的字符串。它会替换每个单词结尾的 a(如果有的话)。

这个语法通常用于修改一些表示文件路径或文件名的变量,以方便进行操作。

这里给出一个例子:

src := a.bc b.bc c.bc
obj := $(src:bc=oo)
test:
  @echo "src=>$(src)"
  @echo "obj=>$(obj)"

运行结果:

2.模式替换

1.变量的模式替换

在变量中使用模式替换就是将%前面和后面的换成我们想要替换的值。

src2 := a11b.c a22b.c a33b.c
src3 := $(src2:a%b.c=x%y)
test : 
  @echo "src3=>$(src3)"

运行结果:

2.规则中的模式替换

在工程开发中会有很多个需要被编译的文件,那么我们肯定不会和之前一样一个目标对应一个依赖,这样写是非常低效的,当要修改时也是非常困难的,所以在这里我们采取模式替换的方式来编写。

CC := gcc
TARGET := hello
OBJS := hello.o func.o
TARGET : $(OBJS)
  $(CC) -o $@ $^
$(OBJS) : %.o : %.c
  $(CC) -c -o $@ $<
.PHONY: clean rebuild all
rebuild : clean all
all : TARGET
clean :
  $(RM) *.o TARGET

二、变量值的嵌套

在Makefile中,变量可以嵌套使用,以方便进行更加复杂的操作。嵌套变量的语法格式如下:

$(first_var$(second_var))

其中,first_var和second_var都是变量名。Make会首先展开$(second_var),以获取second_var的值,然后再将其插入到$(first_var)中,以展开为最终的变量值。

下面举一个例子:

x := y
y := z
a := $($(x))
test3 :
  @echo "x=>$(x)"
  @echo "y=>$(y)"
  @echo "a=>$(a)"

运行结果:

三、命令行变量

在Makefile中,命令行变量指的是通过make命令行传递给Makefile的参数。这些参数可以用于控制Makefile执行过程中的一些行为,例如指定编译器、调试选项等等。命令行变量的定义方式如下:

make <variable>=<value>

中,variable 是命令行变量的名称,value是其值。在Makefile中,可以使用$(variable)来引用这个命令行变量的值。

这里举一个例子说明一下:

test := hello makefile
all : 
  @echo $(test)

运行结果:

四、define和override

在 Makefile 中,define 和 override 是两种比较重要的关键字。

define 关键字用来定义一个多行字符串,它的语法格式如下:

define <variable_name>
    <string>
endef

其中,<variable_name> 是定义的变量名,<string> 是这个变量名所对应的字符串,endef 表示字符串定义的结束标志符。事实上,define 定义的是一个多行的文本字符串,可以是命令、参数或者其他内容。定义后,这个变量就可以在 Makefile 的其他地方使用。

举个例子,你可以这样定义一个变量:

define MY_VARIABLE
    echo "hello world"
endef

然后在 Makefile 的其他地方,使用 $(MY_VARIABLE) 得到 “hello world” 的输出。

输出结果:

override关键字用于指示makefile中定义的变量不能被覆盖。

我们尝试着使用命令行来替换这个override 定义的变量:

define MY_VARIABLE
    "hello world"
endef
override var := hello
all : 
  @echo $(MY_VARIABLE)
  @echo $(var)

运行结果:

这里可以发现使用override定义的变量无法被命令行参数覆盖。

五.环境变量

在 Makefile 中,可以使用环境变量来传递参数或设置选项。环境变量是一种全局变量,对于整个 shell 都是可见的。Makefile 中可以访问这些环境变量,并在其中读取或设置值。

1.CFLAGS:编译选项的环境变量,可以用来设置编译器选项,例如 -Wall 和 -O2 等。

2.LDFLAGS:链接选项的环境变量,可以用来设置链接器选项,例如 -L 和 -l 等。

3.CC:编译器的环境变量,可以用来指定使用的编译器。例如 CC=gcc 表示使用 gcc 编译器。

使用export定义环境变量

一次定义一个变量和它的值:

export VARIABLE=value

示例代码:

test:
  @echo "var => $(var)"

定义环境变量:

运行结果:

这里定义的环境变量不仅可以在这个makefile当中使用也可以在其他的makefile中使用。

环境变量也能够被命令行变量覆盖:

使用-e选项可以优先使用环境变量:

var := abc
test :
  @echo "var =>$(var)"

使用make -e选项运行结果:

六.局部变量

在 Makefile 中,可以使用局部变量(也称为自动化变量),用于临时存储一些值,例如命令行参数、编译器选项和源文件列表等。和全局变量不同,局部变量只在当前的规则中有效。

test : test1
test : var1:=test-var1
test : test1
  @echo "var1=>$(var1)"
test1 :
  @echo "var1=>$(var1)"
test2 : 
  @echo "var1=>$(var1)"

运行效果:

从结果可以看出局部变量只在指定目标和连带规则中有效。

七.模式变量

模式变量则是一种构建在模式规则之上的变量类型,它可以让我们更方便地定义和管理模式规则的组合。

var := D.T.Software
new := TDelphi
%e : override new:= test-new
test : rule
  @echo "var => $(var)"
  @echo "new => $(new)"
rule :
  @echo "var => $(var)"
  @echo "new => $(new)"

运行结果:

从结果中可以看出模式变量作用域只在符合模式的目标及连带规则中。

总结

本篇文章知识点较多,这些内容也是makefile中比较重要的一些内容大家看完后要多加练习。

相关文章
|
8月前
|
存储 缓存 算法
【CMake 基础教程 】深入理解CMake变量:类型、原理及最佳实践
【CMake 基础教程 】深入理解CMake变量:类型、原理及最佳实践
225 0
|
8月前
|
JavaScript 前端开发 编译器
TypeScript【泛型1、泛型2、声明合并、命名空间 、模块1、模块2、声明文件简介】(五)-全面详解(学习总结---从入门到深化)
TypeScript【泛型1、泛型2、声明合并、命名空间 、模块1、模块2、声明文件简介】(五)-全面详解(学习总结---从入门到深化)
146 0
|
8月前
|
前端开发
【专栏】`webpack` 的 `DefinePlugin` 插件用于在编译时动态定义全局变量,实现环境变量差异化、配置参数动态化和条件编译
【4月更文挑战第29天】`webpack` 的 `DefinePlugin` 插件用于在编译时动态定义全局变量,实现环境变量差异化、配置参数动态化和条件编译。通过配置键值对,如 `ENV: JSON.stringify(process.env.NODE_ENV)`,可以在代码中根据环境执行相应逻辑。实际应用包括动态加载资源、动态配置接口地址和条件编译优化代码。注意变量定义的合法性和避免覆盖,解决变量未定义或值错误的问题,以提升开发效率和项目质量。
400 3
|
8月前
|
算法 编译器 C语言
【C++ 函数 基本教程 第六篇 】深度解析C++函数符号:GCC与VS的名称修饰揭秘
【C++ 函数 基本教程 第六篇 】深度解析C++函数符号:GCC与VS的名称修饰揭秘
290 1
|
8月前
|
存储 缓存 算法
CMake 变量作用域全解析:扩展、管理与应用
CMake 变量作用域全解析:扩展、管理与应用
124 0
|
8月前
|
编译器 定位技术 C++
【CMake高级技巧】如何创建一个通用的库查找模板?
【CMake高级技巧】如何创建一个通用的库查找模板?
102 0
|
8月前
|
算法 开发者
【CMake 设计命名思路】自定义命令命名规范与风格指南
【CMake 设计命名思路】自定义命令命名规范与风格指南
110 0
|
8月前
|
JavaScript 前端开发 编译器
TypeScript【泛型1、泛型2、声明合并、命名空间 、模块1、模块2、声明文件简介】(五)-全面详解(学习总结---从入门到深化)(下)
TypeScript【泛型1、泛型2、声明合并、命名空间 、模块1、模块2、声明文件简介】(五)-全面详解(学习总结---从入门到深化)
67 0
TypeScript【泛型1、泛型2、声明合并、命名空间 、模块1、模块2、声明文件简介】(五)-全面详解(学习总结---从入门到深化)(下)
|
8月前
|
JavaScript
TypeScript【泛型1、泛型2、声明合并、命名空间 、模块1、模块2、声明文件简介】(五)-全面详解(学习总结---从入门到深化)(上)
TypeScript【泛型1、泛型2、声明合并、命名空间 、模块1、模块2、声明文件简介】(五)-全面详解(学习总结---从入门到深化)
83 0