zoukankan      html  css  js  c++  java
  • Makefile学习之路5————变量

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

    .PHONY: all
    
    foo=$(bar)
    bar=$(ugh)
    ugh=Huh?
    
    all:
        @echo $(foo)

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

    CFLAGS = $(include_dirs) -O
    
    include_dirs = -Ifoo  -Ibar
    

     上例所示的Makefile,CFLAGS变量最后都会被展开为“-Ifoo  -Ibar  -O”

    CFLAGS =$(CFLAGS) -O
    

      上面的赋值代码将会造成一个死循环,无限递归。

    简单扩展变量(simply  expanded  variable)使用“ :=”操作符来定义的。对于这种变量,make只对其进行一次展开,通过下面的代码来帮助我们理解:

    .PHONY: all
    
    x=foo
    y=$(x) b
    x=later
    
    xx:=foo
    yy:=$(xx) b
    xx:=later
    
    all:
        @echo "X=$(y), xx=$(yy)"

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

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

    .PHONY: all
    
    objs=main.o foo.o bar.o utils.o
    objs:=$(objs) another.o
    
    all:
        @echo $(objs)

     

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

    objs=$(objs) another.o

    make会报错

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

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

    .PHONY: all
    
    foo=x
    foo?=y
    
    bar?=y
    all:
        @echo "foo=$(foo),bar=$(bar)"

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

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

    .PHONY: all
    
    objs=main.o foo.o bar.o utils.o
    objs +=another.o
    all:
        @echo $(objs)

    变量及其值的来源

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

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

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

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

     

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

    高级变量引用功能:

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

    .PHONY: all
    
    foo = a.c b.c c.c
    bar :=$(foo:.c=.o)
    
    all:
        @echo "bar= $(bar)"

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

    .PHONY: all
    
    foo = a.c b.c c.c d.d
    bar :=$(foo:.c=.o)
    
    all:
        @echo "bar= $(bar)"

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

    避免变量被覆盖的方法:

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

    .PHONY: all
    
    override foo=x
    foo=y
    
    all:
        @echo "foo= $(foo)"

    借助“模式”精简规则:

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

    .PHONY: clean
    
    CC = gcc
    RM = rm
    
    EXE =simple
    OBJS =main.o foo.o
    
    $(EXE): $(OBJS)
        $(CC) -o $@ $^
    #main.o:main.c
        $(CC) -o $@ -c $^
    foo.o:foo.c
        $(CC) -o $@ -c $^ 被屏蔽的代码段
    %.o : %.c
        $(CC) -o $@ -c $^
    clean:
        $(RM) -rf $(EXE) $(OBJS)

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

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

  • 相关阅读:
    iOS 字典实现原理
    IOS中armv7,armv7s,arm64以及i386和x86_64讲解
    SDWebImage源码解析
    iOS Runtime的消息转发机制
    二叉树的遍历
    LINUX 常用命令 ps 详解
    LINUX 文件权限详解
    LINUX查看内存使用情况 free
    PHP isset() empty() isnull() 的区别
    PHP unset()函数销毁变量 但没有实现释放内存
  • 原文地址:https://www.cnblogs.com/Liu-Jing/p/8253845.html
Copyright © 2011-2022 走看看