一、make
编译过程
//预处理,#开头的代码全被解决掉(预编译,包含库,宏定义等等)hello.i上千行.
gcc -E hello.c >> hello.i
//编译,检查语法错误,生成.s文件,汇编代码,大概26行.
gcc -S hello.i
//汇编。产生后缀.o的object目标文件,二进制,不可以运行,缺少库信息.
gcc -c hello.s
- 总结:预处理
.i
=> 编译.s
=> 汇编.o
=> 链接
二、常见参数
-f
:执行make的时候,带上-f <文件名>
参数,来指定make命令从哪里读取makefile文件;而如果我们不显式指定,则make就会在当前目录下依次查找名字为GNUmakefile
, makefile
,和 Makefile
的文件来作为其makefile
文件.
-
:让make忽略该命令的错误,例如,通常在Makefile
中使用-include
来代替include
,忽略由于包含文件不存在或者无法创建时的错误提示,make继续执行。
@
:关闭回显。不显示命令,只显示结果.而make参数-s
或--slient
则是禁止所有执行命令的显示.
$(shell pwd)
:获取当前目录的绝对路径 例如:-include $(shell pwd)/src/C_SRC
?=
:变量在之前没有赋值的情况下才会对这个变量进行赋值.
:=
:直接展开定义变量.
=
:递归展开,可能陷入无限循环.
$@
"代表规则中的目标文件名.
$<
"代表规则的第一个依赖的文件名.
$^
"代表规则中所有依赖文件的列表,文件名用空格分割.
如果一行以Tab
字符开始,make程序将此行作为一个命令行来处理.
三、内嵌函数
1、filter
过滤
C_SRC = $(filter %.c, $(SOURCES))
CPP_SRC = $(filter %.cpp,$(SOURCES))
替换引用
C_OBJS = $(C_SRCS:%.c=../obj/%.o)
CPP_OBJS = $(CPP_SRCS:%.cpp=../obj/%.o)
2、wildcard
扩展通配符
$(wildcard PATTERN)
:列出当前目录下所有符合模式“PATTERN”
格式的文件名.
$(wildcard *.c)
返回值为当前目录下所有.c
源文件列表.
C_SRC = $(wildcard *.c) $(wildcard src/*.c)
获取根目录、子目录src下的所有.c源文件。
3、patsubst
替换通配符
$(patsubst <pattern>,<replacement>,<text> )
:查找<text>
中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)是否符合模式<pattern>
,如果匹配的话,则以<replacement>
替换.
$(patsubst %.c,%.o, a.c b.c)
:把字串“a.c b.c”符合模式[%.c]的单词替换成[%.o],返回结果是“a.o b.o”
OBJS_FILE := $(patsubst %,obj/%,$(OBJS))
:把字符串 OBJS
替换到obj
目录下.用于生成的目标文件统一汇总到目录下obj下.
objects := $(patsubst %.c,%.o,$(wildcard *.c))
:先使用wildcard
函数获取工作目录下的.c文件列表;之后将列表中所有文件名的后缀.c替换为.o。这样我们就可以得到在当前目录可生成的.o文件列表。
4、notdir
去除路径
现有如下文件结构:
proj
│──── pj1.c
│──── pj2.c
└──── src
│─── sr1.c
└─── sr2.c
makefile如下:
C_SRC=$(wildcard *.c ./src/*.c)
NODIR=$(notdir $(C_SRC))
OBJS=$(patsubst %.c,%.o,$(NODIR) )
all:
@echo $(C_SRC)
@echo $(NODIR)
@echo $(OBJS)
输出显示:
pj1.c pj2.c ./src/sr1.c ./src/sr2.c
pj1.c pj2.c sr1.c sr2.c
pj1.o pj2.o sr1.o sr2.o
四、makefile
的静态模式
静态模式规则是这样一个规则:规则存在多个目标,并且不同的目标可以根据目标文件的名字来自动构造出依赖文件。静态模式规则比多目标规则更通用,它不需要多个目标具有相同的依赖。但是静态模式规则中的依赖文件必须是相类似的而不是完全相同的。
首先,我们来看一下静态模式规则的基本语法:
targets …: target-pattern: prereq-patterns …
COMMANDS
...
Each target
is matched against the target-pattern
to extract a part of the target name, called the stem
. This stem is substituted into each of the prereq-patterns
to make the prerequisite names (one from each prereq-pattern).
用%
从目标模式targets
的目标名字中抽取一部分字符串(称为“茎”,即抽取的%
匹配的部分)。使用“茎”替代依赖模式prereq-patterns
中的相应部分来产生对应目标的依赖文件。例如:
objects = foo.o bar.o
all: $(objects)
$(objects): %.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
上例中,规则描述了所有的.o文件的依赖文件为对应的.c文件,对于目标“foo.o”,取其茎“foo”替代对应的依赖模式“%.c”中的模式字符“%”之后可得到目标的依赖文件“foo.c”。这就是目标“foo.o”的依赖关系“foo.o: foo.c”,
再例如:
SOURCES := home.c etc.c src/sr1.c mod/mod.cpp
C_SRCS = $(filter %.c, $(SOURCES))
CPP_SRCS = $(filter %.cpp,$(SOURCES))
#目标文件统一输出到obj目录,字符串增加../obj/
C_OBJS = $(C_SRCS:%.c=../obj/%.o)
CPP_OBJS = $(CPP_SRCS:%.cpp=../obj/%.o)
#构建时需要再还原回去,字符串去掉../obj/
$(C_OBJS):../obj/%.o:%.c
@mkdir -p ../obj
@mkdir -p $(dir $@) #创建子目录
$(CC) -c $(CFLAGS) $< -o $@
$(CPP_OBJS):../obj/%.o:%.cpp
@mkdir -p ../obj
@mkdir -p $(dir $@)
$(CXX) -c $(CFLAGS) $< -o $@
参考资料:
GNU make