第六载:makefile变量的高级主题

    在makefile中,我们已经知道变量的基本赋值方法、使用等,但是在makefile中,变量还有一些高级的属性,掌握这些属性,可以使编写的makefile更加高效,现在就来了解下makefile中变量的高级属性

    一、变量值的替换

        - makefile支持使用指定字符(串)替换变量值中的后缀字符(串)
        - 语法格式为:$(var:a=b) 或者 ${var:a=b},即使用b替换变量var的后缀a,假如var为cba,那个替换后的结果cbb
          注意:替换表达式中不能有任何空格, make中也支持使用${}方式对变量进行取值

.PHONY : all

src := a.cpp b.cpp c.cpp
obj := $(src:.cpp=.o)

all:
    @echo "obj => $(obj)"

如上的makefile内容,执行后结果如下(使用.o替换src变量中的.cpp后缀)

/home/delphi>make all
obj => a.o b.o c.o
/home/delphi>

    二、变量的模式替换

        上边说的变量值的替换,仅仅是使用新的字符串替换变量的指定后缀字符串,而模式替换的替换范围稍微广一些,可以保留变量的指定字符,替换其他字符。
        - 使用%保留变量值中的指定字符,替换其他字符(%可以理解为make中的通配符)
        - 语法格式:$(var:a%b=x%y)或${var:a%b=x%y},即将var变量的前缀后缀a\b分别用x\y替换,中间部分不变。

.PHONY : all

src := hello.cpp hello.cpp hello.cpp
obj := $(src:h%.cpp=H%.o)

all:
    @echo "obj => $(obj)"

    上述的makefile,我们H、.o分别替换src变量的h前缀与.cpp后缀,运行结果如下

/home/delphi>make all
obj => Hello.o Hello.o Hello.o
/home/delphi>

   三、规则中的模式替换

    targets : target-pattern : prereq-pattern
              command1
              command2
              ......
     意义为:
      -通过target-patterntargets匹配子目标;再通过prereq-pattern子目标生成依赖;进而构成完整的规则。这个稍微不大好理解,下边用一个例子来说明

对于   $(obj) : %.o : %.c,会对变量obj进行逐个处理,首先拿%.o规则去匹配obj变量,得到main.o,main.o作为一个子目标,改行表达式就成为main.o : %.c,再使用%.c生成main.o的依赖,最后衍生成main.o : main.c这样的目标依赖关系,最终得到$@与$^;同理,遍历完obj中的main.o后,会接着遍历fun.o,逻辑与main.o一样,使用规则中的模式替换的方式可以避免对每个.c文件都写一条编译命令,下边来看一个makefile文件

.PHONY : clean rebuild all


target := hello.out
CC := gcc

obj : main.o func.o

#使用模式规则替换,避免每一条.c都要写一个编译命令
$(obj) : %o : %c
        $(CC) -o $@ -c $^

$(target) : main.o func.o
        $(CC) -o $@ $^


all : $(target)

rebuild : clean all

clean : 
        rm -f *.o $(target)

执行结果

/home/delphi/myshare/makefile>make all
gcc    -c -o main.o main.c
gcc    -c -o func.o func.c
gcc -o hello.out main.o func.o
/home/delphi/myshare/makefile>

从结果看出,规则中的模式替换,可以大大简化我们的工作量,尤其在项目中有成千上百个文件要编译时。

    四、变量值的嵌套引用

       - 一个变量名之中可以包含对其他变量的引用
       - 嵌套引用的本质是使用一个变量表示另一个变量

.PHONY : all

x := y
y := z
val := $($(x))

all:
    @echo "val => $(val)"

make all,这个嵌套引用比较简单

/home/delphi>make all
val => z
/home/delphi>

    五、命令行变量

        - 运行make时,在命令行定义变量
        - 命令行变量默认覆盖makefile中定义的变量
      
  - makefile中使用override关键字修饰变量时,命令行变量值不能覆盖makefile中定义的变量

.PHONY : all test

ifeq ($(DEBUG),true)
    result := this is debug
else
    result := this is release
endif

val_1 := this_is_val_1
override val_2 := this_is_val_2

all:
    @echo "result => $(result)"
    @echo "val_1 => $(val_1)"
    @echo "val_2 => $(val_2)"

执行命令,参数从命令行传入make all DEBUG:=true val_1:=cmd_this_is_val_1  val_2:=cmd_this_is_val_2

/home/delphi>make all DEBUG:=true val_1:=cmd_this_is_val_1  val_2:=cmd_this_is_val_2
result => this is debug
val_1 => cmd_this_is_val_1
val_2 => this_is_val_2
/home/delphi>

参数从命令行传入的好处是,我们可以直接在make参数中决定编译debug版本还是release版本

    六、环境变量(全局变量)

        - makefile中能够直接使用环境变量的值
        a、makefile中定义与环境变量同名的变量,环境变量会被覆盖
        b、运行make时指定"- e"选项,优先使用环境变量
        注意:所有makefile都可以直接使用环境变量,但是过多使用环境变量,会降低makefile的移植性

        - 变量在不同makefile之间的传递方式
        a、直接在外部定义环境变量进行传递(不推荐,可移植性差)
        b、使用export定义变量进行传递(定义临时环境变量)
        c、使用make 命令行变量进行传递(推荐)
        为了说明变量的跨文件传输,我们编写两个makefile测试:makefile与makefile1

#makefile 内容

.PHONY : all

QTDIR := MY_QTDIR    #QTDIR为环境变量,此处更改为MY_QTDIR,会覆盖原有环境变量,影响makefile1的QTDIR
val1 := this_is_val1
export val2 := this_is_val2    #定义临时环境变量,makefile1中可直接使用


all:
    @echo "QTDIR => $(QTDIR)"
    @echo "val1 => $(val1)"
    @echo "val2 => $(val2)"

    @echo "---------make test -f makefile1---------"
    @$(MAKE) test -f makefile1    #通过-f 指定make执行makefile1(下同)
    @echo "---------make test -f makefile1 end---------"

    @echo "---------make test -f makefile1 val1:=$(val1)---------"
    @$(MAKE) test -f makefile1 val1:=$(val1)    #通过命令行传递变量val1值
    @echo "---------make test -f makefile1 val1:=$(val1) end---------"
#makefile1 内容

.PHONY : test

test:
        @echo "QTDIR => $(QTDIR)"
        @echo "val1 => $(val1)"
        @echo "val2 => $(val2)"

 make all结果如下,可以看到,在makefile更改的QTDIR环境变量会覆盖原有的系统环境变量;export定义的临时环境变量val2在makefile1中也可直接访问;而普通变量在makefile中通过make参数传递到makefile1中,才能为makefile1所用

/home/delphi>make all
QTDIR => MY_QTDIR
val1 => this_is_val1
val2 => this_is_val2
---------make test -f makefile1---------
make[1]: 正在进入目录 `/home/delphi'
QTDIR => MY_QTDIR
val1 => 
val2 => this_is_val2
make[1]:正在离开目录 `/home/delphi'
---------make test -f makefile1 end---------
---------make test -f makefile1 val1:=this_is_val1---------
make[1]: 正在进入目录 `/home/delphi'
QTDIR => MY_QTDIR
val1 => this_is_val1
val2 => this_is_val2
make[1]:正在离开目录 `/home/delphi'
---------make test -f makefile1 val1:=this_is_val1 end---------
/home/delphi>

     七、目标变量及模式变量(二者均为局部变量,模式变量时目标变量的扩展)

        - 目标变量:作用域只在指定目标连带规则中
        - 模式变量:作用域只在符合模式的目标及连带规则中
       
说的直白点就类似于C语言中函数内部的局部变量,只不过这里的函数换成的目标
       
下边直接来看一个例子

.PHONY : all test another

val := this_is_val     #val作用域为整个makefile文件(同比C语言源文件中的全局变量)

test :  val := this_is_test_val   #val作用域为test目标或者连带规则中(同比C语言中函数中的局部变量)
%e : val := this_is_%e_val    #val作用域为以e结尾的目标或者连带规则中(同比C语言中函数中的局部变量)

all:
        @echo "all:"
        @echo "val => $(val)"

test : another
        @echo "test:"
        @echo "val => $(val)"

another :
        @echo "another:"
        @echo "val => $(val)"

rule :
        @echo "rule:"
        @echo "val => $(val)"
/home/delphi>
/home/delphi>make all test rule 
all:
val => this_is_val
another:
val => this_is_test_val
test:
val => this_is_test_val
rule:
val => this_is_%e_val
/home/delphi>

从运行结果可以看出,可以给变量限制不同的作用域。

以上7点便是变量的一些高级属性,需要在工作使用过程中慢慢体会。

以上内容参考《狄泰软件学院》操作系统篇之 - makefile专题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值