原创博文,转载请标明出处--周学伟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. ph 的使用步骤

    Arcanist用户指南Windows Updated 44 Day(s) Ago所有用户 https://phabricator.webfuns.net/book/phabricator/artic ...

  2. web-project的/WEB-INF/lib

    哪些jar包应该放到你的/WEB-INF/lib中?(目前为止,我的classpath只配置了dt.jar和tools.jar,也就是说,我的web-project所用的所有jar包都没有配置到cla ...

  3. ehcache 缓存管理工具

    ehcache  ehcache.xml <ehcache>   <diskStore path="java.io.tmpdir" />   <def ...

  4. 浅谈C#委托和事件【转】

    委托给了C#操作函数的灵活性,我们可使用委托像操作变量一样来操作函数,其实这个功能并不是C#的首创,早在C++时代就有函数指针这一说法,而在我看来委托就是C#的函数指针,首先先简要的介绍一下委托的基本 ...

  5. 手风琴式焦点图jQuery特效

    手风琴式焦点图jQuery特效是一款鼠标点击人物图像滑动切换案例说明信息代码.效果图如下: 在线预览   源码下载 实现的代码. html代码: <div class="ag-cont ...

  6. iOS runtime探究(二): 从runtime開始深入理解OC消息转发机制

    你要知道的runtime都在这里 转载请注明出处 http://blog.csdn.net/u014205968/article/details/67639289 本文主要解说runtime相关知识, ...

  7. linux 中常用的一些头文件

    #include <linux/***.h> 是在linux-2.6.29/include/linux下面寻找源文件. #include <asm/***.h> 是在linux ...

  8. Jackson2.1.4 序列化格式化时间

    public class User { private int id; private Date birthday; private double money; private String name ...

  9. Java NIO使用及原理分析 (一)(转)

    最近由于工作关系要做一些Java方面的开发,其中最重要的一块就是Java NIO(New I/O),尽管很早以前了解过一些,但并没有认真去看过它的实现原理,也没有机会在工作中使用,这次也好重新研究一下 ...

  10. Linq中的ToList()和CopyToDataTable()

    最近在项目中使用了Linq,想把Linq的查询结果直接转换成DataTable对象,通过查找发现Linq有一个CopyToDataTable<T>的泛型方法,该方法只能在T是DataRow ...