通过函数能显著增强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——通过函数增强功能的更多相关文章

  1. Makefile学习之路6——让编译环境更加有序

    在大多项目中都会合理设计目录结构来提高维护性,在编译一个项目时会产生大量中间文件,如果中间文件直接和源文件放在一起,就显得杂乱而不利于维护.在为现在这个complicated项目编写makefile之 ...

  2. IOS学习之路-- 指针&宏函数

    如果*p被()包住,说明指针变量p将来指向的是函数 //声明一个指针变量 //int (*p)(int, int) = sum; int (*p)(int, int); p = sum; // 如果* ...

  3. Python3学习之路~3.1 函数基本语法及特性、返回值、参数、局部与全局变量

    1 函数基本语法及特性 定义: 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可 特性: 减少重复代码 使程序变的可扩展 使程序变得易维护 语法定义: d ...

  4. Makefile学习之路——4

    变量的类别有递归扩展变量和简单扩展变量.只用一个“=”符号定义的变量被称为递归扩展变量.通过下面例子观察递归扩展变量的特点. .PHONY: all foo=$(bar) bar=$(ugh) ugh ...

  5. Makefile学习之路——2

    让你的makefile更专业. 在上一个Makefile所在目录下通过touch命令创建一个clean文件,执行make clean,将发现make总是提示clean文件是最新的,而不是按我们期望的那 ...

  6. Makefile学习之路——3

    特殊变量: 在Makefile中,有两个变量特殊变量会经常用到:MAKE和MAKECMDGOALS.MAKE变量表示的是当前处理Makefile的命令名是什么.当需要在Makefile中运行另一个Ma ...

  7. Makefile学习之路——1

    编写makefile,不是一个猛子扎进去试着写一个规则并对之调试,而应该先采用面向依赖关系的思考方法勾勒出makefile要表达怎样的依赖关系,这一点尤为重要.通过不断地练习这种思考方法,才可能达到流 ...

  8. php学习之路:php在iconv功能 详细解释

    iconv函数库可以完毕各种字符集间的转换,是php编程中必不可少的基础函数库. 使用方法例如以下: $string = "亲爱的朋友欢迎訪问胡文芳的博客.希望给您带来一点点的帮助!&quo ...

  9. Python3学习之路~0 目录

    目录 Python3学习之路~2.1 列表.元组操作 Python3学习之路~2.2 简单的购物车程序 Python3学习之路~2.3 字符串操作 Python3学习之路~2.4 字典操作 Pytho ...

随机推荐

  1. go语言基础之闭包的特点

    所谓闭包就是一个函数“捕获”了和它在同一作用域的其它常量和变量.这就意味着当闭包被调用的时候,不管在程序什么地方调用,闭包能够使用这些常量或者变量.它不关心这些捕获了的变量和常量是否已经超出了作用域, ...

  2. SQL 服务没有及时响应启动或控制请求”的解决方法

        解决方法很简单:卸载删除跟IIS相关的几个漏洞安全更新补丁即可,包括KB939373.KB2290570和KB2124261.卸载微软安全更新补丁的方法:打开控制面板的“添加删除程序”面板,勾 ...

  3. 【SSH三大框架】Hibernate基础第十一篇:对继承映射的操作

    在java中.类之间能够有继承关系.可是在数据库中是没有继承关系的.只是Hibernate是为了把面向对象的关系反映到数据库中.Hibernate为我们提供了3种方案: 第一.一个继承体系放在一张表中 ...

  4. 【Hadoop基础】hadoop fs 命令

    1,hadoop fs –fs [local | <file system URI>]:声明hadoop使用的文件系统,如果不声明的话,使用当前配置文件配置的,按如下顺序查找:hadoop ...

  5. 【JavaScript】2013年人气最高的JavaScript框架排名

    本文概述 本文介绍2013年人气急速上升,2014年必须知道的JavaScript框架排名.本文所介绍的排名为Google根据全世界2013年的搜索关键词所做出的统计结果. MVC框架 JavaScr ...

  6. Android DataBinding库(MVVM设计模式)

    什么是MVVM 说到DataBinding,就有必要先提起MVVM设计模式.Model–View–ViewModel(MVVM) 是一个软件架构设计模式,相比MVVM,大家对MVC或MVP可能会更加熟 ...

  7. Python3.2官方文档翻译--迭代器

    6.9 迭代器 到眼下为止.你可能已注意到很多容器对象都能够用for语句进行循环: 这样的訪问风格清楚简洁方便. 迭代器的应用是python遍历统一.在这样的场景背后.for语句调用容器对象iter( ...

  8. Drag & drop a button widget

    In the following example, we will demonstrate how to drag & drop a button widget. #!/usr/bin/pyt ...

  9. profiler跟踪事件模板文件

    查找执行情况最差的查询. 例如,可以创建一个捕获与 TSQL 和 Stored Procedure 事件类(RPC:Completed 和SQL:BatchCompleted)相关的事件的跟踪.在此跟 ...

  10. 让Sql Server 2008 可以远程连接的方法

    1.先开防火墙TCP:1433 2.设置外围端口为:1433 注意一定不要忘记“启用”和IPALL的端口设置 3.重启SQL完成 如果要查看1433端口有没有启用并被监听,只要在cmd里使用netst ...