从头開始写项目Makefile(三):变量的使用

【版权声明:转载请保留出处:blog.csdn.net/gentleliu。

Mail:shallnew at 163 dot com】

细致研究我们的之前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。

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

[email protected]。表示规则中的目标。

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

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

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

上一节我们看到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 [email protected] $^                                                                                                                                                                         

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 [email protected] $^

clean:
>---$(RM) $(SRC_OBJ) $(SRC_BIN)

当中# 后面的内容为凝视。

这样最终满足了那些懒人的想法了。

可见在使用变量时,的确能够是编译变得更自己主动化。

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

1.     =运算符能够读取到后面定义的变量。比方:

VAR = $(VAR2)
VAR2 = hello_make

all:
>[email protected] =====$(VAR)=====

执行结果为:

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

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

2.     :=运算符在遇到变量定义时马上展开。

VAR := $(VAR2)
VAR2 = hello_make

all:
>[email protected] =====$(VAR)=====

执行结果为:

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

3.     ?=运算符在复制之前先做推断变量是否已经存在。比如var1 ?= $(var2)的意思是:假设var1未定义过。那么?=相当于=,假设var1先前已经定义了,则什么也不做。不会给var又一次赋值。

4.     +=运算符是给变了追加值。假设变量还未定义过就直接用+=赋值。那么+=相当于=

怎样使用这几个运算符要看实际情况,有时一个大的project可能有很多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 [email protected]$^ $(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复制到源码文件夹下。再改动一下你须要编译的可运行文件名以及你须要的编译连接选项就可以。

后面章节将会讲到怎样写多文件夹源码project下的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 [email protected]$^ $(LDFLAGS)

clean:
>---$(RM)$(SRC_OBJ) $(SRC_BIN)
时间: 2024-10-14 05:02:04

从头開始写项目Makefile(三):变量的使用的相关文章

从头開始写项目Makefile(五):嵌套运行

[版权声明:转载请保留出处:blog.csdn.net/gentleliu.Mail:shallnew at 163 dot com] 在大一些的项目里面,全部源码不会仅仅放在同一个文件夹,一般各个功能模块的源码都是分开的,各自放在各自文件夹下.而且头文件和.c源文件也会有各自的文件夹.这样便于项目代码的维护.这样我们能够在每一个功能模块文件夹下都写一个Makefile,各自Makefile处理各自功能的编译链接工作,这样我们就不必把全部功能的编译链接都放在同一个Makefile里面,这可使得我

从头開始写项目Makefile(七):统一目标输出文件夹

[版权声明:转载请保留出处:blog.csdn.net/gentleliu. Mail:shallnew at 163 dot com] 上一节我们把规则单独提取出来,方便了Makefile的维护,每一个模块仅仅须要给出关于自己的一些变量,然后再使用统一的规则Makefile.这一节我们继续改进我们的Makefile,到眼下为止我们的Makefile编译链接输出的目标都在源文件同文件夹下或模块Makefile同一文件夹下.当一个项目大了之后,这样会显得非常乱,寻找编译输出的文件也比較困难. 既然

从头开始写项目Makefile(三):变量的使用

[版权声明:转载请保留出处:blog.csdn.net/gentleliu.Mail:shallnew at 163 dot com] 仔细研究我们的之前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(六):参数传递、条件判断、include

[版权声明:转载请保留出处:blog.csdn.net/gentleliu.Mail:shallnew at 163 dot com] 在多个Makefile嵌套调用时,有时我们需要传递一些参数给下一层Makefile.比如我们在顶层Makefile里面定义的打开调试信息变量DEBUG_SYMBOLS,我们希望在进入子目录执行子Makefile时该变量仍然有效,这是需要将该变量传递给子Makefile,那怎么传递呢?这里有两种方法: 1.     在上层Makefile中使用"export&qu

从头开始写项目Makefile(二):自动推导

[版权声明:转载请保留出处:blog.csdn.net/gentleliu.Mail:shallnew at 163 dot com] 上一节的Makefile勉强可用,但还写的比较繁琐,不够简洁.对每一个.c源文件,都需要写一个生成其对应的.o目标文件的规则,如果有几百个或上千个源文件,都手动来写,还不是很麻烦,这也不够自动化啊. 这样,我们把生成.o目标文件的规则全部删除掉,就是这样一个Makefile文件: target_bin : main.o debug.o ipc.o timer.o

从头开始写项目Makefile(十):make内嵌函数及make命令显示

[版权声明:转载请保留出处:blog.csdn.net/gentleliu.Mail:shallnew at 163 dot com] 这一节我们讲一下make的函数,在之前的章节已经讲到了几个函数:wildcard.patsubst.notdir.shell等.一般函数的调用格式如下: $(funcname arguments) 或 $(funcname arguments) 其中funcname是需要调用函数的函数名称,应该是make内嵌函数:arguments是函数参数,参数和函数名之间使

从头开始写项目Makefile(九):目录搜索

[版权声明:转载请保留出处:blog.csdn.net/gentleliu.Mail:shallnew at 163 dot com] 在一个较大的工程中,一般会将源代码和二进制文件(.o 文件和可执行文件)安排在不同的目录来进行区分管理.这种情况下,我们可以使用 make 提供的目录搜索依赖文件功能(在指定的若干个目录下自动搜索依赖文件).在Makefile中,使用依赖文件的目录搜索功能.当工程的目录结构发生变化后,就可以做到不更改 Makefile的规则,只更改依赖文件的搜索目录. 在我们上

从头开始写项目Makefile(四):伪目标

[版权声明:转载请保留出处:blog.csdn.net/gentleliu.Mail:shallnew at 163 dot com] 一般情况下,Makefile都会有一个clean目标,用于清除编译过程中产生的二进制文件.我们在第一节的Makefile就用到了这个 clean目标,该目标没有任何依赖文件,并且该目标对应的命令执行后不会生产clean文件. 像这种特点目标,它的规则所定义的命令不是去创建文件,而仅仅通过make指定目标来执行一些特定系统命令或其依赖为目标的规则(如all),称为

从头开始写项目Makefile(五):嵌套执行

[版权声明:转载请保留出处:blog.csdn.net/gentleliu.Mail:shallnew at 163 dot com] 在大一些的项目里面,所有源代码不会只放在同一个目录,一般各个功能模块的源代码都是分开的,各自放在各自目录下,并且头文件和.c源文件也会有各自的目录,这样便于项目代码的维护.这样我们可以在每个功能模块目录下都写一个Makefile,各自Makefile处理各自功能的编译链接工作,这样我们就不必把所有功能的编译链接都放在同一个Makefile里面,这可使得我们的Ma