原创博文,转载请标明出处--周学伟http://www.cnblogs.com/zxouxuewei/

仔细研究我们的之前Makefile发现,我们还有改进的地方,就是此处:

  target_bin : main.o debug.o ipc.o timer.o tools.o
>---gcc -o target_bin main.o debug.o ipc.o timer.o tools.o

如果增加一个源文件xx.c的话,需要在两处或多处增加xx.o文件。我们可以使用变量来解决这个问题。之前说过,Makefile的变量就像C语 言的宏一样,使用时在其位置上直接展开。变量在声明时赋予初值,在引用变量时需要给在变量名前加上“$”符号,但最好用小括号“()”或是大括号“{}” 把变量给包括起来。

默认目标target_bin也在多处出现了,该文件也可以使用变量代替。

修改我们的Makefile如下

    SRC_OBJ = main.o debug.o ipc.o timer.o tools.o
SRC_BIN = target_bin
$(SRC_BIN) : $(SRC_OBJ)
>---gcc -o $(SRC_BIN) $(SRC_OBJ) clean:
>---rm $(SRC_OBJ) $(SRC_BIN)

这样每次有新增的文件是只需要在SRC_OBJ变量里面增加一个文件即可。要修改最终目标的名字是可以只修改变量SRC_BIN。

其实在之前还说过特殊变量:

$@,表示规则中的目标。

$<,表示规则中的第一个依赖文件。

$?,表示规则中所有比目标新的条件,组成一个列表,以空格分隔。

$^,表示规则中的所有条件,组成一个列表,以空格分隔。

上一节我们看到make -p有很多自定义的变量,比如CC。其中很多变量我们可以直接使用或修改其变量值或增加值。我们的Makefile中可以使用CC(默认值为cc)、RM(默认值为rm -f)。

由此可见我们的Makefile还可以进一步修改

    SRC_OBJ = main.o debug.o ipc.o timer.o tools.o
SRC_BIN = target_bin
$(SRC_BIN) : $(SRC_OBJ)
>---$(CC) -o $@ $^ clean:
>---$(RM) $(SRC_OBJ) $(SRC_BIN)

这样的Makefile编译也是可用的。

但是这样的Makefile还是需要我们手动添加文件,还是不够自动化,最好增删文件都要修改Makefile。伟大的人类真是太懒了!!于是乎, 他们发明了一个函数wilcard(函数后面会讲到),它可以用来获取指定目录下的所有的.c文件列表。这样的话我们可以自动获取当前目录下所有.c源文 件,然后通过其他方法再得到.o文件列表,这样的话就不需要在每次增删文件时去修改Makefile了。所谓其他方法这里给出两种:

1.     使用patsubst函数。在$(patsubst %.c,%.o,$(dir) )中,patsubst把$(dir)中的变量符合后缀是.c的全部替换成.o。

2.     变量值的替换。 我们可以替换变量中的共有的部分,其格式是“$(var:a=b)”或“${var:a=b}”,其意思是,把变量“var”中所有以“a”字串“结尾”的“a”替换成“b”字串。

修改后的Makefile如下:

# SRC_OBJ = $(patsubst %.c, %.o, $(wildcard *.c))                                                                                                                                          

SRC = $(wildcard *.c)
SRC_OBJ = $(SRC:.c=.o)
SRC_BIN = target_bin $(SRC_BIN) : $(SRC_OBJ)
>---$(CC) -o $@ $^ clean:
>---$(RM) $(SRC_OBJ) $(SRC_BIN)

其中# 后面的内容为注释。

这样终于满足了那些懒人的想法了。可见在使用变量时,的确可以是编译变得更自动化。

其实变量的定义有三种运算符=、:=、?=、+=。

1.     =运算符可以读取到后面定义的变量。比如:

    VAR = $(VAR2)
VAR2 = hello_make all:
>---@echo =====$(VAR)=====

运行结果为:

    #
=====hello_make=====
#

但是这种定义可能会导致并非我们意愿的事发生,并不是很符合C语言的编程习惯。

2.     :=运算符在遇到变量定义时立即展开

    VAR := $(VAR2)
VAR2 = hello_make all:
>---@echo =====$(VAR)=====

运行结果为:

   #
==========
#  

3.     ?=运算符在复制之前先做判断变量是否已经存在。例如var1 ?= $(var2)的意思是:如果var1没有定义过,那么?=相当于=,如果var1先前已经定义了,则什么也不做,不会给var重新赋值。

4.     +=运算符是给变了追加值。如果变量还没有定义过就直接用+=赋值,那么+=相当于=

如何使用这几个运算符要看实际情况,有时一个大的工程可能有许多Makefile组成,变量可能在多个Makefile中都在使用,这时可能使用+=比较好。使用:=有时可能比要好。

有时在编译程序时,我们需要编译器给出警告,或加入调试信息,或告知编译器优化可执行文件。编译时C编译器的选项CFLAGS使用的较多,默认没有 提供值,我们可以给该变量赋值。有时我们还需要使用链接器选项LFLAGS告诉链接器链接时需要的库文件。可能我们还需要给出包含头文件的路径,因为头文 件很可能和源文件不再同一目录。所以,我们今天的Makefile加上部分注释又更新了:

    # A commonMakefile for c programs, version 1.0
# Copyright (C)2014 shallnew \at 163 \dot com CFLAGS += -g -Wall-Werror -O2
CPPFLAGS += -I.-I./inc
LDFLAGS +=-lpthread # SRC_OBJ =$(patsubst %.c, %.o, $(wildcard *.c))
SRC_FILES =$(wildcard *.c)
SRC_OBJ =$(SRC_FILES:.c=.o)
SRC_BIN =target_bin $(SRC_BIN) :$(SRC_OBJ)
>---$(CC) -o $@$^ $(LDFLAGS) clean:
>---$(RM)$(SRC_OBJ) $(SRC_BIN)

编译:

    # make
cc -g -Wall-Werror -O2 -I. -I./inc -c -o debug.odebug.c
cc -g -Wall-Werror -O2 -I. -I./inc -c -o ipc.oipc.c
cc -g -Wall-Werror -O2 -I. -I./inc -c -o main.omain.c
cc -g -Wall-Werror -O2 -I. -I./inc -c -o timer.otimer.c
cc -g -Wall-Werror -O2 -I. -I./inc -c -o tools.otools.c
cc -o target_bindebug.o ipc.o main.o timer.o tools.o -lpthread
#

可见我们的预编译选项,编译选项都用到了,之前我们说过make的使用隐含规则自动推导:

COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) –c

其中变量CFLAGS 和 CPPFLAGS均是我们给出的,变量$(TARGET_ARCH)未给,所以在编译输出可以看到-c前面有2个空,最早未给变量是有四个空。

目前给出的Makefile基本上可以适用于那些源代码全部在同一目录下的简单项目,并且基本上在增删文件时不需要再去手动修改Makefile代 码。在新的一个项目只需要把该Makefile拷贝到源代码目录下,再修改一下你需要编译的可执行文件名称以及你需要的编译连接选项即可。

后面章节将会讲到如何写多目录源代码工程下的Makefile。

最后,今天的最终Makefile是这样的:

        # A commonMakefile for c programs, version 1.0
# Copyright (C)2014 shallnew \at 163 \dot com CFLAGS += -g -Wall-Werror -O2
CPPFLAGS += -I.-I./inc
LDFLAGS +=-lpthread # SRC_OBJ =$(patsubst %.c, %.o, $(wildcard *.c))
SRC_FILES =$(wildcard *.c)
SRC_OBJ =$(SRC_FILES:.c=.o)
SRC_BIN =target_bin $(SRC_BIN) :$(SRC_OBJ)
>---$(CC) -o $@$^ $(LDFLAGS) clean:
>---$(RM)$(SRC_OBJ) $(SRC_BIN)

makefile--变量的使用(二)的更多相关文章

  1. makefile使用笔记(二)变量

    By francis_hao    Oct 30,2017   makefile中可以使用变量,变量有多种类型,下面分别介绍 简单变量 简单变量的命名规则和c语言一致. 给变量赋值就表示创建了这个变量 ...

  2. 开始编写Makefile(二)Makefile变量的使用

    Makefile可以使用变量代替 命令行:make -f Makefile2 说明开始make一个名为Makefile2的文件 ###############定义变量################# ...

  3. makefile笔记5 - makefile变量

    在 Makefile 中的定义的变量,就像是 C/C++语言中的宏一样,他代表了一个文本字串,在 Makefile 中执行的时候其会自动原模原样地展开在所使用的地方.其与 C/C++所不同的是,你可以 ...

  4. 【 MAKEFILE 编程基础之三】详解 MAKEFILE 变量的定义规则使用!

    本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/gcc-makefile/770.html   ...

  5. 【 MAKEFILE 编程基础之二】MAKEFILE 书写规划以及语法规则!

    本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/gcc-makefile/768.html   ...

  6. makefile变量赋值

    在定义变量的值时,我们可以使用其它变量来构造变量的值,在Makefile中有两种方式来在用变量定义变量的值. 先看第一种方式,也就是简单的使用“=”号,在“=”左侧是变量,右侧是变量的值,右侧变量的值 ...

  7. Makefile变量

    自定义变量 = 是最基本的赋值,会把整个makefile展开之后再决定是多少 x=foo y=$(x)bar #y是asdbar,不是foobar x=asd := 是覆盖之前的值,和=不同,和赋值的 ...

  8. [dart学习]第三篇:dart变量介绍 (二)

    本篇继续介绍dart变量类型,可参考前文:第二篇:dart变量介绍 (一) (一)final和const类型 如果你不打算修改一个变量的值,那么就把它定义为final或const类型.其中:final ...

  9. 工控随笔_13_西门子_WinCC的VBS脚本_04_变量类型之二

    上一个随笔说了一些关于vbs变量类型的内容,这一篇我们继续说说变量类型相关的内容. 一.NULL补充内容 '需要注意的是,NULL不能简单通过 = 来进行比较,而必须通过 'IsNull函数来实现 ' ...

  10. makefile 变量展开

    Makefile中给变量赋值: =     是递归展开式变量 value1 = 5 value2 = $(value1) value1 = 6 最终$(value2)就变成了6 :=    是直接展开 ...

随机推荐

  1. Oracle PLSQL Demo - 22.查看字符串的长度[lengthb, length],判断字符串是否包含中文

    --Count the length of string select lengthb('select * from scott.emp') as countted_by_byte, length(' ...

  2. Oracle“不等于号”与Null的情况

    今天突然才发现,Oracle中的“不等于操作符”是忽略Null的. 比如,查询comm不等于的300的记录,我会理所当然地使用where comm != 300 预想会返回包含Null的不等于300的 ...

  3. 五、String在Java中是传“引用”

    这个是Java的经典问题.许多类似的问题在stackoverflow被提问,有很多不正确或不完备的答案.如果不想太多你会认为这个问题比较简单.( The question is simple if y ...

  4. JQuery中eq()和get()的区别

    众所周知,eq()方法返回的是一个JQuery对象,也就是[object Object]; get()方法返回的是DOM对象组成的数组,也就是[object HTMLLIElement]; 我们用一个 ...

  5. POJ1579:Function Run Fun

    Description We all love recursion! Don't we? Consider a three-parameter recursive function w(a, b, c ...

  6. linux 内核参数调整优化网络

    Linux系统内核设置优化tcp网络,# vi /etc/sysctl.conf,添加以下内容 net.ipv4.tcp_syncookies = 1 表示开启SYN Cookies.当出现SYN等待 ...

  7. jquery轮播控件

    网上找了一个轮播控件,效果不错,而且很容易改,需要的同学去下载咯 地址是:http://download.csdn.net/detail/jine515073/7704143

  8. 快速上手最棒的网格框架ag-Grid

    由于对aggrid由衷的感谢, 又忍不住写了一篇软文来推广它(其实主要是为了弥补我把enterprise版扣下来后内心的愧疚...) ag-Grid是速度最快,功能最丰富的JavaScript dat ...

  9. java判断邮件是否发送成功

    http://www.cnblogs.com/winner-0715/p/5136392.html

  10. EMS快递单号生成算法

    <?php function emsnum($ems, $num) { $fri = substr($ems, 2, 8); $head = substr($ems, 0, 2); $tail ...