makefile教程(2)

条件判断

使用条件判断可让make根据运行时的不同情况选择不同的执行分支

libs_for_gcc = -lgnu

normal_libs =

foo : $(objects)

ifeq ($(CC), gcc)

$(CC) -o foo $(objects) $(libs_for_gcc)

else

$(CC) -o foo $(objects) $(normal_libs)

endif

也可以写的更简洁点

ifeq($(CC), gcc)

libs = $(libs_for_gcc)

else

libs = $(normal_libs)

foo : $(objects)

$(CC) -o foo $(objects) $(libs)

使用到了三个关键字:ifeq else endif

  • ifeq

如果要比较make的命令行参数可以使用

ifeq(< arg1>, < arg2>)

  • ifneq 如果不相同
  • ifdef 如果变量的值为非空,则表达式的值为真,否则表达式的值为假

foo =

var = $(foo)

ifdef var

bozz = yes

else

bozz = no

endif

foo =

ifdef foo

bozz = yes

else

bozz = no

endif

则我们知道,第一个$ (bozz)为yes,第二个$(bozz)为no

  • ifndef 他的作用与ifdef相反

特别注意,make是在读取makefile时就计算条件表达式的值,所以最好不要把自动化变量$@放入条件表达式中,因为自动化变量是在运行时才有的

makefile函数调用

函数的调用语法

函数的调用与变量的使用方法类似,都是通过$来标识

$(< function> < arguments, arguments, arguments>)

参数之间以“,”分隔,函数名和参数之间以空格分隔

函数中的参数可以使用变量 eg:$ (subst a,b,$(x))

字符串处理函数

$(subst < from>,< to>,< string>)

将字符串中的字符替换函数

comma := ,

empty :=

space := $ (empty)$(empty)

string := a b c

bar := $(subst $ (space),$ (comma),$(string))

将a b c替换成为a,b,c

$(patsubst < pattern>,< replacement>,< text>)

模式字符串替换函数,查找text中的单词(单词以空格、Tab、回车、换行分隔)是否符合模式< pattern>,如果匹配的话,则以< replacement>替换

pattern可以包含通配符 %,表示任意长度的字串

bar := $(patsubst %.c,%.o,x.c.c foo.c)

得到的$(bar) = x.c.o foo.o

$(strip < string>)

去空格函数,去掉字符串开头或者结尾的空字符

bar := $(strip a b c )

得到的$(bar) = a b c

$(findstring < find>,< in>)

查找字符串函数,在字符串in中查找find字串,如果找到就返回find,否则返回空字符串

$(findstring a,a b c)

$(findstring a, b c)

第一个函数返回字符串a,第二个函数返回空字符串

$(filter < pattern…>,< text>)

过滤函数,以pattern模式过滤text中的字符串中的单词,只保留符合pattern的单词,返回符合模式的pattern的字串

sources := 1.c 2.c 3.o 4.s

foo : $(sources)

gcc $ (filter %.c %.s,$(sources)) -o foo

$(filter-out < pattern>,< text>)

反过滤函数,按照pattern的要求过滤text的内容,返回过滤后不存在pattern的单词

objects = main1.o foo.o main2.o bar.o

mians = mian1.o main2.o

$(filter-out $ (mians),$(objects))的返回值就是 foo.o bar.o

$(sort < list>)

排序函数,给字符串list中的单词首字母排序(升序),并且会去除重复的单词

$(sort foo bar lose)返回的就是bar foo lose

$(word < n>,< text>)

取单词函数,从text中取第n个单词,从1开始数;如果n比text中的单词数要大,那么返回空字符串

$(word 2, foo bar baz)返回的值为bar

$(wordlist < s>,< e>,< text>)

取单词串函数,从text中取从s到e的单词串,s和e是数字

如果s比e大,则返回的是空字符串

如果e比text的单词数大,则返回的是text

$(wordlist 2,3,foo bar baz)返回的就是 bar baz

$(words < text>)

统计text中的单词数量

$(words foo bar baz)返回的值就是3

$(firstword < text>)

取text中第一个单词

$(firstword foo bar baz)返回值就是foo

也可以使用

$(word 1,foo bar baz)返回值也是foo

练习:

假设搜索路径的特殊变量VPATH = src : …/header

修改为cc 或gcc 搜索头文件路径的参数是多少,并且如何修改

参数是目录前面加上-I,因为有两个目录,所以分别要加上-I,分隔符冒号也要修改为空格

为-Isrc , -I…/header

使用subst和patsubst修改:

$ (patsubst %,-I%,$ (subst :, ,$(VPATH)))

最后修改为:-Isrc -I…/header

override CFLAGS += $ (patsubst %,-I%, ( s u b s t : , , (subst :, , (subst:,,(VPATH)))

文件名操作函数

这里的函数主要是处理文件名,每个函数的参数字符串都会被当做一个或者一系列的文件名来对待,最重要是文件名

$(dir < names…>)

取出目录部分,所谓的目录部分就是最后一个 / 之前的内容

如果没有/,则返回 “./”

$(dir src/foo.c hacks)的返回值是 “src/”加上 “./”

因为这是两个路径:src/foo.c 、hacks

$(notdir < names…>)

取出文件函数,从路径中取出非目录部分,指最后一个反斜杠 “/” 之后的部分

$(notdir src/foo.c hacks)的返回值就是 foo.c hacks

$(suffix < names…>)

取后缀函数,从文件名序列names中取出各个文件名的后缀,如果没有后缀则返回空字符串

$(suffix src/foo.c src-1.0/bar.c hacks)的返回值是.c .c

$(basename < names…>)

取前缀函数,从文件名序列names中取出各个文件名的前缀,如果没有前缀则返回空字符串

$(basename src/foo.c src-1.0/bar.c hacks)的返回值是 src/foo src-1.0/bar hacks

$(addsuffix < suffix>,< names…>)

加后缀函数,将suffix加到每个names中的每个单词后面

$(addsuffix .c,foo bar)返回值是 foo.c bar.c

$(addprefix < prefix>,< names…>)

加前缀函数,将prefix加到每个names中的每个单词前面

$(addprefix src/,foo bar)的返回值是src/foo src/bar

$(join < list1>,< list2>)

连接函数,将list2单词对应连接到每个list1的单词的后面

如果list1的单词数大于list2的单词数,则list1的单词就会保持原样

如果list1的单词数小于list2的单词数,则list2的单词就会保持原样连接

$(join aaa bbb,111 222 333)的返回值为 aaa111 bbb222 333

foreach函数

foreach主要用于循环

$(foreach < var>,< list>,< text>)

表示将list中的单词逐个取出放入var指定的容器中,每放一次就会执行一次text中的表达式,得到结果就会返回一个字符串,每次返回的字符串都会用空格分隔开,最后当整个循环结束时,< text>所返回的每个字符串所组成的整个字符串(以空格分隔)将会是 foreach 函数的返回值

list := a b c d

$ (foreach n,$ (list),$(n).o)则返回的值为a.o b.o c.o d.o

var只是一个局部变量作用域只会存在于foreach中

call函数

call用来创建新的参数化的函数

你可以写一个复杂的表达式,定义很多参数,并用call来依次传递参数

$(call < expression>,< parm1>,< parm2>,< parm3>…)

例如我定义了一个表达式:reverse = $(1) $(2)

foo = $(call reverse,a,b)

a和b依次覆盖了1和2,同时得到的返回值foo的值就是a b

reverse = $(2) $(1)

foo = $(call reverse,a,b)

a和b依次覆盖了1和2,同时得到的返回值foo的值就是b a

origin函数

origin函数不同于其他函数,其他函数都是去操作参数的值,而这个函数通过返回值告诉你参数的来源

$(origin < variable>)

此时variable是变量的名字,而不是变量的引用,所以不要去加$

origin函数的返回值解析
“undefined”如果< variable>从来没有定义过,origin 函数返回这个值“undefined”。
“default”如果< variable>是一个默认的定义,比如“CC”这个变量
“environment”如果< variable>是一个环境变量,并且当 Makefile 被执行时,“-e”参数没有被打开。
“file”如果< variable>这个变量被定义在 Makefile 中。
“command line”如果< variable>这个变量是被命令行定义的。
“override”如果< variable>是被 override 指示符重新定义的。
“automatic”如果< variable>是一个命令运行中的自动化变量。

练习

如果我的makefile中包含了文件make.def,在make.def中存在一个变量bletch,而我们的环境中也有一个环境变量叫做bletch。此时判断一下,如果变量来源于环境,那么我们就把变量重定义了;如果变量来自于make.def或者是命令行等环境,那我们就不重新定义

ifdef bletch

ifeq “$(origin bletch)” “environment”

bletch = bar, aa

endif

endif

这里如果使用override意思是覆盖变量的使用,但如果bletch是命令行的参数传参,就有可能被override覆盖

Shell函数

shell函数的参数就是操作系统shell的命令

也就是说shell函数把执行操作系统命令后的输出作为函数的返回

content := $(shell cat foo)

files := $(shell echo *.c)

但是过量使用shell函数是对系统性能是有害的

控制make的函数

当按下make时,也有一些函数能够控制make的使用,比如在make时打印出信息,并根据信息的反馈来决定是否要进行下一步make

$(error < text…>)

产生了一个致命的错误,错误信息打印在text中,这个函数并不是一使用就会打印错误信息

可以将错误信息定义在一个变量中,并在后续的脚本中使用这个变量

ifdef ERROR_01

$(error error is $(ERROR_01))

endif

当ERROR_01被定义时,才能执行error调用

还有一种情况是err被执行时才发生error调用:

ERR = $(error found an error)

.PHONY : err

err ; $(ERR)

就是把错误信息啥的都写在一个变量里,随时调用

最后当产生错误时make就会退出

$(warning < text…>)

这个函数很像error,但是出错时不会退出,只是警告而已

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孤独memories

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值