开源项目学习(4)---- Makefile 语句和函数

1. Makefile 的自动推导

Makefile 对于文件中的 .o 文件,会自动加入 .c 文件作为依赖,并且会自动推导出 cc -c whatever.c 生成 whatever.o 这样的代码

这样可以简化 Makefile 的书写,.o 文件可以自动加入 .c 文件作为依赖,但是依赖的头文件需要预先加入依赖列表

# 注意连接符 \ 后面不能再有字符
objects = main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o

edit : $(objects)
cc -o edit $(objects)

main.o : defs.h 
kbd.o : defs.h command.h
command.o : defs.h command.h
display.o : defs.h buffer.h
insert.o : defs.h buffer.h
search.o : defs.h buffer.h
files.o : defs.h buffer.h command.h
utils.o : defs.h

.PHONY : clean
clean :
rm edit $(objects)

 也可以将具有相同的头文件的目标进行合并,形成多目标的格式:

objects = main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o

edit : $(objects)
cc -o edit $(objects)

$(objects) : defs.h
kbd.o command.o files.o : command.h
display.o insert.o search.o files.o : buffer.h

.PHONY : clean
clean :
rm edit $(objects)

Makefile 支持通配符,比如:

~ 表示用户的主目录,~/test 用户主目录的 test 目录,~users/test 用户 users 目录下的 test 目录

*.o 表示当前目录下所有的 .o 文件,适用于命令,不适用于变量中,如果文件名中有字符和通配符同名,可以使用转义字符的方式实现

.PHONY clean
clean
    rm -rf *.o

Makefile 支持多目标的实现比如:

bigoutput littleouptut : text.g
    generate  text.g  -$(subst  output,, $@) > $@

等同于使用下面的命令: 

bigoutput: text.g
    generate text.g -big > bigoutput

littleoutput:text.g
    generate text.g -little > littleoutput

Makefile 的一些常用命令

make -n 只会显示命令,但是不会真正的执行

make -s 全面禁止命令的显示

make -w 显示makefile 进入或者离开某个目录

makefile 头文件的搜索路径:
1. 当前的执行目录下
2. make -I 目录   makefile 会在这个参数所包含的目录下去寻找

2. Makefile 的分支语句

 第一种形式:ifeq else endif

ifeq  ($(CC),gcc)
else
endif

举例: 注意有neq的用法
ifeq 'arg1' 'arg2'
ifeq “arg1” “arg2”
ifeq 'arg1' “arg2”
ifeq “arg1” 'arg2'

ifneq 'arg1' 'arg2'
ifneq “arg1” “arg2”
ifneq 'arg1' “arg2”
ifneq “arg1” 'arg2'

 第二种形式: ifdef else endif      ifndef else endif

ifdef foo  同样支持 ifndef
option1
else
option2
endif

第三者形式:ifeq  else ifeq  else ifeq endif

ifeq (arg1,arg2)
......
else ifeq
......
else ifeq
......
else
......
endif

 3.Makefile 中的函数

函数的基本形式为:

$(函数名 参数1,参数2,参数3)

  • 函数名和参数之间以空格分隔
  • 参数之间用逗号分隔
  • 参数可以使用变量

Makefile 中的常用函数如下:

3.1 字符串处理函数

$(subst <from>, <to>,<text>)
• 名称:字符串替换函数 subst
• 功能:把字串<text> 中的<from> 字符串替换成<to>
• 返回:函数返回被替换过后的字符串
• 示例:
$(subst ee,EE,feet on the street)

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

$(strip <string>)

  • 名称:去空格函数——strip
  • 功能:去掉<string> 字串中开头和结尾的空字符
  • 返回:返回被去掉空格的字符串值

示例代码:

CURRENTDIT = $(shell pwd)
OBJECTS := $(wildcard $(CURRENTDIT)/*.cpp )

# "wildcard \/cygdrive/d/Ubuntu/source_code/cygwin/makefile_test/*.cpp
# /cygdrive/d/Ubuntu/source_code/cygwin/makefile_test/a.cpp 
# /cygdrive/d/Ubuntu/source_code/cygwin/makefile_test/b.cpp 
# /cygdrive/d/Ubuntu/source_code/cygwin/makefile_test/c.cpp"
 
#$(warning "wildcard \$(CURRENTDIT)/*.cpp = $(OBJECTS)")
#$(error "wildcard \$(CURRENTDIT)/*.cpp = $(OBJECTS)")


# /cygdrive/d/Ubuntu/source_code/cygwin/makefile_test/a.o
# /cygdrive/d/Ubuntu/source_code/cygwin/makefile_test/b.o 
# /cygdrive/d/Ubuntu/source_code/cygwin/makefile_test/c.o"
OBJECTS_O := $(subst .cpp,.o, $(OBJECTS))
$(warning "subst OBJECTS = $(OBJECTS_O)")

PATSUBST := $(patsubst %.cpp, %.o, $(OBJECTS))
$(warning "PATSUBST = $(PATSUBST)")

# 注意中间不能有空格
SIMPLE := $(OBJECTS:%.cpp=%.o)
$(warning "SIMPLE = $(strip $(SIMPLE))")

$(warning origin func is $(origin OBJECT))
$(warning origin func is $(origin PATH))

3.2 文件名操作函数

$(dir <names...>)
名称:取目录函数——dir
功能:从文件名序列<names> 中取出目录部分。目录部分是指最后一个反斜杠(“/”)之
前的部分。如果没有反斜杠,那么返回“./”。
返回:返回文件名序列<names> 的目录部分


$(suffix <names...>)
名称:取后缀函数——suffix。
功能:从文件名序列<names> 中取出各个文件名的后缀。
返回:返回文件名序列<names> 的后缀序列,如果文件没有后缀,则返回空字串
示例:$(suffix src/foo.c src-1.0/bar.c hacks) 返回值是 .c .c 


$(basename <names...>)
名称:取前缀函数——basename
功能:从文件名序列<names> 中取出各个文件名的前缀部分
返回:返回文件名序列<names> 的前缀序列,如果文件没有前缀,则返回空字串
示例:$(basename src/foo.c  src-1.0/bar.c hacks) 返回值是 src/foo src-1.0/
bar hacks 


$(addsuffix <suffix>,<names...>)
名称:加后缀函数——addsuffix
功能:把后缀<suffix> 加到<names> 中的每个单词后面
返回:返回加过后缀的文件名序列
示例:$(addsuffix .c , foo bar) 返回值是 foo.c bar.c 

$(addprefix <prefix>,<names...>)
名称:加前缀函数——addprefix

功能:把前缀<prefix> 加到<names> 中的每个单词后面
返回:返回加过前缀的文件名序列
示例:$(addprefix src/, foo bar) 返回值是 src/foo src/bar 


$(join <list1>,<list2>)
名称:连接函数——join

功能:把<list2> 中的单词对应地加到<list1> 的单词后面如果<list1> 的单词
个数要比<list2> 的多,那么,<list1> 中的多出来的单词将保持原样如果<list2>
的单词个数要比<list1> 多,那么,<list2> 多出来的单词将被复制到<list2> 中
返回:返回连接过后的字符串
示例:$(join aaa bbb , 111 222 333) 返回值是 aaa111 bbb222 333 

DIR := $(dir $(OBJECTS))
NOTDIR := $(notdir $(OBJECTS))
SUFFIX := $(suffix $(OBJECTS))
BASENAME := $(basename $(OBJECTS))

ADDSUFFIX := $(addsuffix _f, $(OBJECTS))
ADDPREFIX := $(addprefix _FUNC_, $(OBJECTS))
JOIN := $(join hello, world)

# /cygdrive/d/Ubuntu/source_code/cygwin/makefile_test/
# /cygdrive/d/Ubuntu/source_code/cygwin/makefile_test/
# /cygdrive/d/Ubuntu/source_code/cygwin/makefile_test/
$(warning "dir DIR = $(DIR)")

# a.cpp
# b.cpp
# c.cpp
$(warning "notdir NOTDIR = $(NOTDIR)")

# .cpp
# .cpp
# .cpp
$(warning "suffix SUFFIX = $(SUFFIX)")

# /cygdrive/d/Ubuntu/source_code/cygwin/makefile_test/a
# /cygdrive/d/Ubuntu/source_code/cygwin/makefile_test/b
# /cygdrive/d/Ubuntu/source_code/cygwin/makefile_test/c"
$(warning "prefix BASENAME = $(BASENAME)")


# /cygdrive/d/Ubuntu/source_code/cygwin/makefile_test/a.cpp_f
# /cygdrive/d/Ubuntu/source_code/cygwin/makefile_test/b.cpp_f
# /cygdrive/d/Ubuntu/source_code/cygwin/makefile_test/c.cpp_f"
$(warning "suffix  ADDSUFFIX = $(ADDSUFFIX)")


# _FUNC_/cygdrive/d/Ubuntu/source_code/cygwin/makefile_test/a.cpp 
# _FUNC_/cygdrive/d/Ubuntu/source_code/cygwin/makefile_test/b.cpp 
# _FUNC_/cygdrive/d/Ubuntu/source_code/cygwin/makefile_test/c.cpp"
$(warning "prefix ADDPREFIX = $(ADDPREFIX)")

# join = helloworld
$(warning "join = $(JOIN)")

3.3 origin 函数

origin 函数用于标识变量的来源
$(origin <variable>;)
注意,<variable>; 是变量的名字,不应该是引用 所以你最好不要在<variable>; 中使
用 $ 字符 Origin 函数会以其返回值来告诉你这个变量的出生情况 ,下面是origin
函数的返回值:
undefined  如果<variable>; 从来没有定义过,origin 函数返回这个值 undefined  
default  如果<variable>; 是一个默认的定义,比如 CC 这个变量,这种变量我们将在
后面讲述 
environment  如果<variable>; 是一个环境变量,并且当Makefile 被执行时, -e 参
数没有被打开 
file  如果<variable>; 这个变量被定义在Makefile 中 
command line  如果<variable>; 这个变量是被命令行定义的 
override  如果<variable>; 是被override 指示符重新定义的 
automatic  如果<variable>; 是一个命令运行中的自动化变量

3.4 Shell 函数

shell 函数也不像其它的函数。顾名思义,它的参数应该就是操作系统Shell 的命令。它
和反引号有相同的功能,这就是说,shell 函数把执行操作系统命令后的输出作为函数返
回。于是,我们可以用操作系统命令以及字符串处理命令awk,sed 等等命令来生成一个变量,
如:

contents := $(shell cat foo)
files := $(shell echo *.c)

注意,这个函数会新生成一个Shell 程序来执行命令,所以你要注意其运行性能,如果你
的Makefile 中有一些比较复杂的规则,并大量使用了这个函数,那么对于你的系统性能是有
害的, 特别是Makefile 的隐晦的规则可能会让你的shell 函数执行的次数比你想像的多得

3.5 控制Make 的函数

$(error <text ...>;)
产生一个致命的错误,<text ...>; 是错误信息。注意,error 函数不会在一被使用就会
产生错误信息,所以如果你把其定义在某个变量中,并在后续的脚本中使用这个变量,那么也
是可以的

$(warning <text ...>;)
这个函数很像 error 函数,只是它并不会让 make 退出,只是输出一段警告信息,而 make
继续执行

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值