makefile中的函数

字符处理函数

函数说明:

  • wildcard : 扩展通配符。
  • notdir : 去除路径 。
  • patsubst :替换通配符。

示例

目录结构:

tree /F /A test

   D:\WL\TEST\T1\TEST_MAKEFILE\TEST
   |   a.c
   |   b.c
   |   Makefile
   |
   \---sub
           sa.c
           sb.c

Makefile

src=$(wildcard *.c ./sub/*.c)
dir=$(notdir $(src))
obj=$(patsubst %.c,%.o,$(dir) )

all:
   @echo $(src)
   @echo $(dir)
   @echo $(obj)
   @echo "end"

输出:

b.c a.c ./sub/sb.c ./sub/sa.c
b.c a.c sb.c sa.c
b.o a.o sb.o sa.o
end

说明:

  • wildcard把指定目录 ././sub/ 下的所有后缀是c的文件全部展开。
  • notdir 把展开的文件去除掉路径信息
  • $(patsubst %.c,%.o,$(dir) )中,patsubst把$(dir)中的变量符合后缀是.c的全部替换成.o。 或者可以使用obj=$(dir:%.c=%.o)效果也是一样的。

obj=$(dir:%.c=%.o)用到makefile里的替换引用规则,即用您指定的变量替换另一个变量。

它的标准格式是: $(var:a=b) 或 ${var:a=b} 它的含义是把变量var中的每一个值结尾用b替换掉a

wildcard

使用函数wildcard得到指定目录下所有的C语言源程序文件名的方法,这下好了,不用手工一个一个指定需要编译的.c文件了,方法如下:

SRC = $(wildcard *.c)

等于指定编译当前目录下所有.c文件,如果还有子目录,比如子目录为inc,则再增加一个wildcard函数,像这样:

SRC = $(wildcard *.c) $(wildcard inc/*.c)

也可以指定汇编源程序:ASRC = $(wildcard *.S)

patsubst

这是个模式替换函数

格式:$(patsubst <pattern>,<replacement>,<text> )

名称:模式字符串替换函数patsubst。

功能:查找<text>中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)是否符合模式<pattern>,如果匹配的话,则以替换。这里,<pattern>可以包括通配符“%”,表示任意长度的字串。如果<replacement>中也包含“%”,那么,<replacement>中的这个“%”将是<pattern>中的那个“%”所代表的字串。(可以用“\”来转义,以\%来表示真实含义的“%”字符)。

返回:函数返回被替换过后的字符串。

示例:$(patsubst %.c,%.o,x.c.c bar.c)

把字串x.c.c bar.c符合模式[%.c]的单词替换成[%.o],返回结果是x.c.o bar.o

变量替换引用 $(VAR:A=B)

对于一个已经定义的变量,可以使用“替换引用”将其值中的后缀字符(串)使用指定的字符(字符串)替换。

格式为: $(VAR:A=B)(或者 ${VAR:A=B} )

意思是: 替换变量“VAR”中所有“A”字符结尾的字为“B”结尾的字。“结尾”的含义是空格之前(变量值多个字之间使用空格分开)。而对于变量其它部分的“A”字符不进行替换。

例如:

foo := a.o b.o c.o
bar := $(foo:.o=.c)

在这个定义中,变量“bar”的值就为“a.c b.c c.c”。 使用变量的替换引用将变量“foo”以空格分开的值中的所有的字的尾字符“o”替换为“c”, 其他部分不变。如果在变量“foo”中如果存在“o.o”时,那么变量“bar”的值为“a.c b.c c.c o.c”而不是“a.c b.c c.c c.c”。

示例

获取当前执行的Makefile所在路径

参考文档: https://blog.csdn.net/codingcs/article/details/79055009

Linux下我们可以用pwd命令来获取当前所执行命令的目录,在Makefile中对应可用PWD := $(shell pwd)来获取。但是如果子Makefile 文件是从别处执行的(通过make -f .../Makefile 执行),那么$(shell pwd)得到的目录即为执行make -f命令的当前目录。在这种情况下, Makefile本身里面的命令不能对当前目录作出假设。那么如何获取被调用的Makefile文件所在目录呢?

根据gnu make定义,gnu make 会自动将所有读取的makefile路径都会加入到MAKEFILE_LIST变量中,而且是按照读取的先后顺序添加。所以可以通过:

  • $(abspath $(lastword $(MAKEFILE_LIST))) 返回当前正在被执行的Makefile的绝对路径。
  • mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST))) 获取当前正在执行的makefile的绝对路径。
  • cur_makefile_path := $(patsubst %/Makefile, %, $(mkfile_path)) 获取当前正在执行的makefile的绝对目录。

示例:

mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
cur_makefile_path := $(patsubst %/Makefile, %, $(mkfile_path))
#window / transe to \
cur_path := $(patsubst %/, %\,$(cur_makefile_path))
export GOPATH:= ${cur_path}

BUILDTAGS=debug

all: test

test:
@echo	${mkfile_path} "111"
@echo	${cur_makefile_path} "222"
@echo	${cur_path} "333"
GOOS="" GOARCH="" go get github.com/jteeuwen/go-bindata/go-bindata

输出:

D:/wl/Test/t1/test_makefile/Makefile 111
D:/wl/Test/t1/test_makefile 222
D:/wl/Test/t1/test_makefile 333
GOOS="" GOARCH="" go get github.com/jteeuwen/go-bindata/go-bindata

说明:在window 下直接设置 export GOPATH:= ${cur_makefile_path} 会报下面错误:

GOOS="" GOARCH="" go get github.com/jteeuwen/go-bindata/go-bindata
       go: GOPATH entry is relative; must be absolute path:
       	" D:/wl/Test/t1/test_makefile".
       For more details see: 'go help gopath'
       make: *** [Makefile:15: test] Error 2

解决方法:

# 执行替换,将/替换为\。
cur_path := $(patsubst %/, %\,$(cur_makefile_path))
export GOPATH:= ${cur_path}