Makefile学习之路5——通过函数增强功能
通过函数能显著增强Makefile的功能。对于simple项目的Makefile,尽管使用了模式规则,但还是有一件比较麻烦的事情,就是要在Makefile中指明每一个项目源文件。下面介绍几个后期会使用到的函数,更多请参考《GUN Make》。
1.abspath函数
从命名就应该能够猜出它的作用。abspath函数用于将_name中的各路径名转化成绝对路径,并将转化后的结果返回。调用形式为:
$(abspath _name)
.PHONY: all
root :=$(abspath /uer/../lib)
all:
@echo $(root)

2.addprefix函数
addprefix函数用于给名字列表_name中的每一个名字增加前缀_prefix,并将增加了前缀的名字列表返回,调用形式为:
$(addprefix _prefix,_name)
.PHONY: all
without_dir=main.c foo.c
with_dir :=$(addprefix objs/,$(without_dir))
all:
@echo $(with_dir)

3.addsuffix函数
和前面addprefix刚好相反,addsuffix函数为_name增加后缀_suffix,调用形式为:
$(addsuffix _suffix,_name)
.PHONY: all
without_dir=main foo
with_dir :=$(addsuffix .c,$(without_dir))
all:
@echo $(with_dir)

4.filter函数
filter函数被用于从一个名字列表_text中根据模式_patterm得到满足需要的名字列表并返回,其形式是:
$(filter _pattern,_text)
.PHONY: all
sources =foo.o bar.c main.c hell.s
sources :=$(filter %.c %.s,$(sources))
all:
@echo $(sources)

5.eval函数
eval函数的存在使得Makefile具有动态语言的特征。eval函数使得make将再一次解析_text语句。eval返回空字符串,调用形式为:
$(eval _text)
.PHONY: all
sources =foo.o bar.c main.c hell.s
$(eval sources :=$(filter %.c %.s,$(sources)))
all:
@echo $(sources)

虽然它和上面第四个函数运行结果完全一样,但是在某些场合却必须用eval。可参考:http://bbs.chinaunix.net/thread-2321462-3-1.html
eval的二次展开,是递归的一种形式,因为有时候在Makefile的表达式中,最后得出来的可能还是Makefile的表达式而非真正我们想要传递的值,需要再展开Makefile的表达式得到最终的结果。
6.filter-out函数
该函数用于从名字列表_text中根据模式_pattern滤除一部分名字并将滤除后的列表返回,其形式为:
$(filter-out _pattern,_text)
.PHONY: all
objs =foo.o main.o main1.o main2.o
result :=$(filter-out main%.o,$(objs))
all:
@echo $(result)

7.notdir函数
该函数用来从路径_name中抽取文件名,并将文件名返回。其形式为:
$(notdir _name)
.PHONY: all
file_name :=$(notdir c/d/e/f/a.c q/w/e/r/b.c)
all:
@echo $(file_name)

8.patsubst函数
该函数用来将名字列表_text中符合_pattern模式的名字替换成_replacement,并将替换后的名字列表返回。其形式为:
$(patsubst _pattern,_replacement,_text)
.PHONY: all
mixed=foo.c bar.c main.o
objs :=$(patsubst %.c,%.o,$(mixed))
all:
@echo $(objs)

9.realpath函数
该函数用于获取_name所对应的真实路径名。其形式为:
$(realpath _name)
.PHONY: all
root :=$(realpath ./)
all:
@echo $(root)

10.strip函数
如果希望清除名字列表中的多余空格,strip函数是最佳选择,它将_string中的多余空格去除后返回。其形式为:
$(strip _string)
.PHONY: all
ori=foo.c main.c
res:=$(strip $(ori))
all:
@echo "$(ori)"
@echo "$(res)"

这里对echo命令做了一点变动,细心的人已经发现加了一个双引号,如果不加双引号,这里的两个输出将是相同的。
双引号用于保持引号内所有字符的字面值(回车和空格也不例外)。
11.wildcard函数
该函数是通配符函数,通过它可以得到当前工作目录中满足_pattern模式的文件或目录名列表。其形式为:
$(wildcard _pattern)
.PHONY:all
srcs=$(wildcard *.c)
all:
@echo $(srcs)

有了上面函数的基础之后,我们来看看之前的simple项目,对它进行改进:
之前的代码:
.PHONY: clean CC = gcc
RM = rm EXE =simple
OBJS =main.o foo.o $(EXE): $(OBJS)
$(CC) -o $@ $^
%.o : %.c
$(CC) -o $@ -c $^
clean:
$(RM) -rf $(EXE) $(OBJS)
还是要手动添加源文件,麻烦,运用函数之后,改进如下:
.PHONY: clean CC = gcc
RM = rm EXE =simple
SRCS =$(wildcard *.c)
OBJS =$(patsubst %.c, %.o, $(SRCS))
$(EXE): $(OBJS)
$(CC) -o $@ $^
%.o : %.c
$(CC) -o $@ -c $^
clean:
$(RM) -rf $(EXE) $(OBJS)

此时我们增加一个源文件,touch bar.c,看看我们的Makefile需不需要修改。

从结果看,不用修改Makefile就可以增加源文件了,同理,删除也一样,这样的Makefile具有更好的鲁棒性。
Makefile学习之路5——通过函数增强功能的更多相关文章
- Makefile学习之路6——让编译环境更加有序
在大多项目中都会合理设计目录结构来提高维护性,在编译一个项目时会产生大量中间文件,如果中间文件直接和源文件放在一起,就显得杂乱而不利于维护.在为现在这个complicated项目编写makefile之 ...
- IOS学习之路-- 指针&宏函数
如果*p被()包住,说明指针变量p将来指向的是函数 //声明一个指针变量 //int (*p)(int, int) = sum; int (*p)(int, int); p = sum; // 如果* ...
- Python3学习之路~3.1 函数基本语法及特性、返回值、参数、局部与全局变量
1 函数基本语法及特性 定义: 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可 特性: 减少重复代码 使程序变的可扩展 使程序变得易维护 语法定义: d ...
- Makefile学习之路——4
变量的类别有递归扩展变量和简单扩展变量.只用一个“=”符号定义的变量被称为递归扩展变量.通过下面例子观察递归扩展变量的特点. .PHONY: all foo=$(bar) bar=$(ugh) ugh ...
- Makefile学习之路——2
让你的makefile更专业. 在上一个Makefile所在目录下通过touch命令创建一个clean文件,执行make clean,将发现make总是提示clean文件是最新的,而不是按我们期望的那 ...
- Makefile学习之路——3
特殊变量: 在Makefile中,有两个变量特殊变量会经常用到:MAKE和MAKECMDGOALS.MAKE变量表示的是当前处理Makefile的命令名是什么.当需要在Makefile中运行另一个Ma ...
- Makefile学习之路——1
编写makefile,不是一个猛子扎进去试着写一个规则并对之调试,而应该先采用面向依赖关系的思考方法勾勒出makefile要表达怎样的依赖关系,这一点尤为重要.通过不断地练习这种思考方法,才可能达到流 ...
- php学习之路:php在iconv功能 详细解释
iconv函数库可以完毕各种字符集间的转换,是php编程中必不可少的基础函数库. 使用方法例如以下: $string = "亲爱的朋友欢迎訪问胡文芳的博客.希望给您带来一点点的帮助!&quo ...
- Python3学习之路~0 目录
目录 Python3学习之路~2.1 列表.元组操作 Python3学习之路~2.2 简单的购物车程序 Python3学习之路~2.3 字符串操作 Python3学习之路~2.4 字典操作 Pytho ...
随机推荐
- 一些LR的经验,讲的还不错
https://blog.csdn.net/Dinosoft/article/details/50492309 记录一下.
- go语言基础之多个defer执行顺序
1. 多个defer执行顺序 如果一个函数中有多个defer语句,它们会以LIFO(后进先出)的顺序执行.哪怕函数或某个延迟调用发生错误,这些调用依旧会被执.示例: package main //必须 ...
- 搜索引擎爬虫蜘蛛的useragent
百度爬虫 * Baiduspider+(+http://www.baidu.com/search/spider.htm”) google爬虫 * Mozilla/5.0 (compatib ...
- 设计模式(一)简单工厂(创建型)(Java&&PHP)
面向对象设计的基本原则 单一职责系统中的每一个对象应该只有一个单独的职责,所有对象关注的应该是自身职责的完成. 基本思想:高内聚,低耦合. 开闭原则一个对象对扩展开放,对修改关闭.基本思想:对类的改动 ...
- Thinkphp学习笔记-编辑工具Sublime license
选择[help]-[enter license] 直接输入注册码就可以了 ----- BEGIN LICENSE ----- Andrew Weber Single User License EA ...
- Install certificates needed for Visual Studio offline installation
Visual Studio is primarily designed for installation from an internet-connected machine, since many ...
- 虚拟机chrome os 没有可用网络错误
从http://chromeos.hexxeh.net/ 下载了一个chrome os的VM版本的,在VM9上打开运行,一直提示没有可用网络 解决方案 查看虚拟机的网络设置设置为 NAT方式 查看主机 ...
- I/O复用的应用场合
I/O复用(select.poll)典型使用在下列网络应用场合: (1)当客户处理多个描述字(通常是交互式输入和网络套接口)时,必须使用I/O复用. (2)一个客户同时处理多个套接口是可能的,不过比较 ...
- it-tidalwave-semantic-aux-1.0.13.jar下载
今天来给大家分一下一下自己认为还是挺不错的jar包下载网址,it-tidalwave-semantic-aux-1.0.13.jar,作为java开发人员可能时时刻刻都在跟jar包打交道,即使这会用不 ...
- Python set特点
set的特点 set的内部结构和dict很像,唯一区别是不存储value,因此,判断一个元素是否在set中速度很快. set存储的元素和dict的key类似,必须是不变对象,因此,任何可变对象是不能放 ...