zoukankan      html  css  js  c++  java
  • Makefile学习之路——4

    变量的类别有递归扩展变量和简单扩展变量。只用一个“=”符号定义的变量被称为递归扩展变量。通过下面例子观察递归扩展变量的特点。

    1 .PHONY: all
    2 
    3 foo=$(bar)
    4 bar=$(ugh)
    5 ugh=Huh?
    6 
    7 all:
    8     @echo $(foo)

    从结果来看,递归扩展变量的引用是递归的。

    CFLAGS =$(CFLAGS) -O
    上面的赋值代码将会造成一个死循环,无限递归。
     
    简单变量扩展使用“ :=”操作符来定义的。对于这种变量,make只对其进行一次操作,通过下面的代码来帮助我们理解:
     1 .PHONY: all
     2 
     3 x=foo;
     4 y=$(x) b
     5 x=later
     6 
     7 xx:=foo
     8 yy:=$(xx) b
     9 xx:=later
    10 
    11 all:
    12     @echo "X=$(y), xx=$(yy)"

    递归和简单扩展变量相比的差距应该看出来了吧。递归相当于c++中的引用,而简单扩展变量make只对其进行一次展开。

    下面对于同一个变量采取不同的赋值操作,看看会有什么效果。

    1 .PHONY: all
    2 
    3 objs=main.o foo.o bar.o utils.o
    4 objs:=$(objs) another.o
    5 
    6 all:
    7     @echo $(objs)

    如果把第二个简单扩展变量变成递归的即

    objs=$(objs) another.o

    make会报错

    makefile:4:***递归变量'objs'引用本身(最终)。看来想引用自身的递归变量,编译器不会允许这样的行为。

     在Makefile中还可以实现条件赋值:当变量没有被定义时就定义它,并且将右边的值赋值给它,如果变量已经定义了,则不改变其原值。条件赋值可用于为变量赋默认值。条件赋值运用“?=”来实现。下面用条件赋值运行一个Makefile:

    1 .PHONY: all
    2 
    3 foo=x
    4 foo?=y
    5 
    6 bar?=y
    7 all:
    8     @echo "foo=$(foo),bar=$(bar)"

    foo已经定义,故保持原样,bar未定义,故把右侧数据赋值给bar。

    另外一个非常有用的赋值方法是通过“+=”实现追加赋值:

    1 .PHONY: all
    2 
    3 objs=main.o foo.o bar.o utils.o
    4 objs +=another.o
    5 all:
    6     @echo $(objs)

    变量及其值的来源

    从前面的示例可以看出,在Makefile中可以对变量进行定义。此外,还有其他的方式让make获得变量。比如:

    (1)对于自动变量,其值是在每一个规则中根据上下文自动获得的

    (2) 在运行make时,通过命令参数定义变量。如果以make bar=x的形式运行它,得到的结果则完全不同。从结果可以看出,在运行make的命令参数中定义的变量在Makefile中是可见的。其实完全可以通过make命令行中定义变量的方式覆盖Makefile文件中所定义变量的值。

    (3)变量还可以来自shell环境,采用shell中的export命令定义一个bar变量之后运行Makefile。

    export命令:设置或显示环境变量,具体用法请查看linux命令手册。

    高级变量引用功能:

    下面示例说明了变量引用的一种高级功能,即在赋值的同时完成文件名后缀替换操作。

    1 .PHONY: all
    2 
    3 foo = a.c b.c c.c
    4 bar :=$(foo:.c=.o)
    5 
    6 all:
    7     @echo "bar= $(bar)"

    但是需要注意,$(foo:.c=.o)中,foo:.c在":"和 "."之间不能有空格,有空格将使后缀替换失败,$(foo:.c=.o),相当于把foo变量后缀为.c的全部替换成.o的。

    1 .PHONY: all
    2 
    3 foo = a.c b.c c.c d.d
    4 bar :=$(foo:.c=.o)
    5 
    6 all:
    7     @echo "bar= $(bar)"

    可以看到,d.d并没被替换,只是替换后缀为.c的。

    避免变量被覆盖的方法:

    我们在设计Makefile时,可能并不希望发生变量被覆盖的现象,此时需要使用override指令进行限制。

    1 .PHONY: all
    2 
    3 override foo=x
    4 foo=y
    5 
    6 all:
    7     @echo "foo= $(foo)"

    借助“模式”精简规则:

    对于目前simple项目的Makefile,其中存在多个规则用于构建目标文件。 比如main.o 和foo.o,都是采用不同的规则进行描述的。如果对于每一个目标文件,都得写一个不同的规则来描述,那真是一种体力活。Makefile中的模式就是用来解决这个问题的。

     1 .PHONY: clean
     2 
     3 CC = gcc
     4 RM = rm
     5 
     6 EXE =simple
     7 OBJS =main.o foo.o
     8 
     9 $(EXE): $(OBJS)
    10     $(CC) -o $@ $^
    11 #main.o:main.c
    12     $(CC) -o $@ -c $^
    13 foo.o:foo.c
    14     $(CC) -o $@ -c $^ 被屏蔽的代码段
    15 %.o : %.c
    16     $(CC) -o $@ -c $^
    17 clean:
    18     $(RM) -rf $(EXE) $(OBJS)

     与前一个版本的相比,最为直观的改变就是将两条用于构建目标文件的规则变成了一条。模式类似与Windows操作系统中所使用的通配符,用“%”加以表示。采用了模式之后,无论有多少个源文件要编译都可以使用同一条规则,这极大地简化了Makefile。

    同样,"%" 和"."之间不能有空格。还有一点,上面的代码使用了Makefile中的#加上反斜杠的注释方式,是为了凸显和之前版本Makefile的差别。

  • 相关阅读:
    Minimum Depth of Binary Tree leetcode java
    Maximum Depth of Binary Tree leetcode java
    Symmetric Tree leetcode java
    Same Tree leetcode java
    Binary Tree Postorder Traversal leetcode java
    Binary Tree Preorder Traversal leetcode java
    Binary Tree Inorder Traversal leetcode java
    Combinations leetcode java
    一键清除Centos iptables 防火墙所有规则
    阿里云centos7.7x64安装open,并配置ip转发和nat伪装
  • 原文地址:https://www.cnblogs.com/yangguang-it/p/6650456.html
Copyright © 2011-2022 走看看