文章目录
<Makefile实战>https://github.com/wangbojing/NtyCo
1. 规则格式
缩进要用TAB键,不能用空格
1.1 规则
目标 : 依赖文件集合
命令1
命令2
.。。。。。。。。。。。
1.2例子
main : main.o input.o calcu.o
gcc -o main main.o input.o calcu.o
命令必须以TAP键开始,不能用空格
2. 原理
2.1 依赖原理
一个规则是由目标(targets)、先决条件(prerequisites)以及命令(commands)所组成出的是,目标和先决条件之间表达的就是依赖关系(dependency)
simple:main.o foo.o
gcc -o simple main.o foo.o
main.o:main.c
gcc -o main.o -c main.c
foo.o:foo.c
gcc -o foo.o -c foo.c
clean:
rm simple main.o foo.o
2.2 通过文件时间戳,判断是否需要重新构建
main.c 和 foo.c 呢?答案很简单,通过文件的时间戳!当 make 在运行一个规则时,我们前面已经提到
了目标和先决条件之间的依赖关系,make 在检查一个规则时,采用的方法是:如果先决条件中相关的文 件的时间戳大于目标的时间戳,即先决条件中的文件比目标更新,则知道有变化,那么需要运行规则当中 的命令重新构建目标。
这条规则会运用到所有与我们在 make时指定的目标的依赖树中的每一个规则。比
如,对于 simple 项目,其依赖树中包括三个规则(如图1.21),make 会检查所有三个规则当中的目标
3.伪目标
伪目标不是真正的目标名,为了防止执行命令的目标和实际文件目标名字冲突
- 例子
-
之前
clean: rm *.o rm main
如果在文件夹中touch clean ,执行make clean,Makefile提示:make: “clean”已是最新。
-
添加伪目标
.PHONY:clean clean: rm *.o rm main
使用.PHONY声明之后的目标,Makefile不会把它当做一个文件来处理,而是当做一个概念上的目标,所以每次make这个佳目标都会执行
- 常见伪目标
- all 是所有目标的伪目标,功能是编译所有目标
- clean 删除所有被make创建的文件
- install 安装已经编译好的程序,其实就是把目标执行文件拷贝到指定目标中
- print 这个伪目标的功能是列出改变过的源文件
- tar 把源程序打包备份,就是一个tar文件
- dist 创建一个压缩文件,一般吧tar文件压缩成Z文件或gz文件
- TAGS 更新所有目标,以备完整的重编译使用
- check/test 测试makefile流程
4. Makefile变量
4.1 why,how使用变量??
注释要用#,和shell一样
变量使用 $(变量名)也和shell一样
变量定义直接写
.PHONY:clean
CC=gcc
RM=rm
EXE=simple
OBJS=main.o foo.o
$(EXE):$(OBJS)
$(CC) -o $(EXE) $(OBJS)
main.o:main.c
$(CC) -o main.o -c main.c
foo.o:foo.c
$(CC) -o foo.o -c foo.c
clean:
$(RM) $(EXE) $(OBJS)
命令是什么。还有就是引入了 EXE 和 OBJS 两个变量,一个用于存放可执行文件名,可另一个则用于放
置所有的目标文件名。采用变量的话,当我们需要更改编译器时,只需更改变量斌值的地方,非常方便,
如果不采用变量,那我们得更改每一个使用编译器的地方,很是麻烦。显然,变量的引入增加了 Makefil的可维护性。
4.2自动化变量
“$@” ,表示一个规则之中的目标,当一个规则有多个目标时,“$@” 指其中任何造成命令运行的目标
“$<” ,表示所有依赖的第一个值,如果依赖目标是以模式(即"%")定义的,那么"$<"将是符合模式的一系列的文件集。注意,其是一个一个取出来的。
”$^“ , 所有的依赖目标的集合。以空格为分隔,如果依赖目标中存在有多个重复的,那这个变量会去除重复的依赖目标,只保留一份
-
例子
.PHONY:clean CC=gcc RM=rm EXE=simple OBJS=main.o foo.o $(EXE):$(OBJS) $(CC) -o $@ $^ main.o:main.c $(CC) -o $@ -c $^ foo.o:foo.c $(CC) -o $@ -c $^ clean: $(RM) $(EXE) $(OBJS)
4.3 特殊变量
- $(MAKE) = make ,当我们在一个Makefile文件之中打算make另一个文件时需要使用
- $(MAKECMDGOALS) ,指的是用户输入的目标
4.4 变量的类别
-
“=”是递归扩展变量, 不能对自己赋值,会出现死循环
- 可以将变量的值推到后面去定义-
例子:
name = lak curName = $(name) name = liankang print: @echo currname: $(curName)
#结果为: liankang
-
-
“:=”是简单扩展变量,make只对其进行一次扫描和替换
-
相当于正常的=,不会使用后面定义的值,
-
例子:
name = lak curName := $(name) name = liankang print: @echo currname: $(curName)
#结果为:lak
-
-
?=
name = lak- name ?= liankang
- name1 = liankang
结果:name = lak name1 = liankang - 意思是如果name上面被赋值就是之前的值,没有赋值就是赋值为liankang
-
+=
- 给字符串追加
4.5 变量来源和值
- 自动变量,通过上下文自动获取
- make bar = x ,make执行时覆盖Makefile之中变量的值
- 来自shell环境
4.6 override指令
可以使Makefile之中变量不会被输入make 覆盖
5. 模式
- “%”
- 表示长度任意的字符串,类似shell中的“*”
例子1:
%.o : %.c
gcc -c $< -o $@
把所有的c文件编译生成对应的o文件,$<代表每次取的c文件,$@代表每次c文件对应的目标文件
- “$(@D)”, $@的目录部分
- “$(@F)"$@的文件部分
"$%", 表示函数库文件中
- 用于打包静态库,的.o文件 集合
”$+“, 所有依赖目标的集合,不去除重复目标
”$*“, 表示目标模式 % 及其之前的部分,如果目标是”dir/a.foo.b", 并且目标模式是“a.%.b",那么 ”$*"表示的值就是“dir/a.foo"
”$?“所有比目标新的依赖目标集合,以空格分开
6. 函数
-
addprefix,添加前缀。$(addprefix prefex, names…)
-
filter , 从字符串之中获取符合格式的字符串,$(filter pattern…, text)
-
filter-out, 从字符串之中过滤掉一部分字符串, $(filter-out pattern… , text)
-
patsubst, 用来做字符串替换,$(patsubst pattern, replacement, text)
-
strip 去除多余的空格,只保留一个空格, $(strip string)
-
wildcard , 通配符,$(wildcard, pattern)
7. 创建目录
.PHONY:all
MKDIR=mkdir
RM=rm
RMFLAGS=-rf
DIRS=objs exes
all:$(DIRS)
$(DIRS):
$(MKDIR) $@
clean:
$(RM) $(RMFLAGS) $(DIRS)
结果:
mi@mi-OptiPlex-7060:~/test/complicated$ make
make: 对“all”无需做任何事。
mi@mi-OptiPlex-7060:~/test/complicated$ make clean
rm -rf objs exes
mi@mi-OptiPlex-7060:~/test/complicated$ make all
mkdir objs
mkdir exes
mi@mi-OptiPlex-7060:~/test/complicated$ make
make: 对“all”无需做任何事。
.PHONY:all
MKDIR=mkdir
RM=rm
RMFLAGS=-rf
DIRS=objs exes
CC=gcc
EXE=complicated
SRCS=$(wildcard *.c)
OBJS=$(SRCS:.c=.o)
all:$(DIRS) $(EXE)
$(DIRS):
$(MKDIR) $@
$(EXE):$(OBJS)
$(CC) -o $@ $^
%.o:%.c
$(CC) -o $@ -c $^
clean:
$(RM) $(RMFLAGS) $(DIRS) $(EXE) $(OBJS)
8.将文件放进目录之中
mi@mi-OptiPlex-7060:~/test/makefile/complicated$ make clean
rm -rf exes objs
mi@mi-OptiPlex-7060:~/test/makefile/complicated$ ls
foo.c foo.h main.c Makefile
mi@mi-OptiPlex-7060:~/test/makefile/complicated$ make
mkdir exes
mkdir objs
gcc -o objs/foo.o -c foo.c
gcc -o objs/main.o -c main.c
gcc -o exes/complicated objs/foo.o objs/main.o
mi@mi-OptiPlex-7060:~/test/makefile/complicated$ cat Makefile
.PHONY:all
MKDIR=mkdir
RM=rm
RMFLAGS=-rf
DIR_OBJS=objs
DIR_EXES=exes
DIRS=$(DIR_EXES) $(DIR_OBJS)
CC=gcc
EXE=complicated
EXE:=$(addprefix $(DIR_EXES)/, $(EXE))
SRCS=$(wildcard *.c)
OBJS=$(SRCS:.c=.o)
OBJS:=$(addprefix $(DIR_OBJS)/, $(OBJS))
all:$(DIRS) $(EXE)
$(DIRS):
$(MKDIR) $@
$(EXE):$(OBJS)
$(CC) -o $@ $^
$(DIR_OBJS)/%.o:%.c
$(CC) -o $@ -c $^
clean:
$(RM) $(RMFLAGS) $(DIRS)
9. 更复杂的依赖
-
当不依赖头文件时,头文件修改,make并不会检查头文件的时间戳,认为没有必要重新make
-
修改,在 %c后面添加头文件,并且将下面自动变量设为取第一个依赖
$(DIR_OBJS)/%.o:%.c foo.h
$(CC) -o $@ -c $< -
采用gcc -MM foo.c 可以查看foo.c所依赖的文件,将所有头文件添加到依赖选项上
.PHONY:all MKDIR=mkdir RM=rm RMFLAGS=-rf DIR_OBJS=objs DIR_EXES=exes DIR_DEPS=deps DIRS=$(DIR_EXES) $(DIR_OBJS) $(DIR_DEPS) CC=gcc EXE=complicated EXE:=$(addprefix $(DIR_EXES)/, $(EXE)) SRCS=$(wildcard *.c) OBJS=$(SRCS:.c=.o) OBJS:=$(addprefix $(DIR_OBJS)/, $(OBJS)) DEPS=$(SRCS:.c=.dep) DEPS:=$(addprefix $(DIR_DEPS)/, $(DEPS)) all:$(DIRS) $(DEPS) $(EXE) $(DIRS): $(MKDIR) $@ $(EXE):$(OBJS) $(CC) -o $@ $^ $(DIR_OBJS)/%.o: %.c $(CC) -o $@ -c $^ $(DIR_DEPS)/%.dep: %.c @echo "Making $@ ..." @set -e;\ $(RM) $(RMFLAGS) $@.tmp;\ $(CC) -E -MM $^ > $@.tmp;\ sed 's,\(.*\)\.o[:]*,objs/\1.o:,g' < $@.tmp > $@; \ $(RM) $(RMFLAGS) $@.tmp clean: $(RM) $(RMFLAGS) $(DIRS)
10.包含文件include
mi@mi-OptiPlex-7060:~/test/makefile/complicated$ make
Makefile:18: deps/foo.dep: 没有那个文件或目录
Makefile:18: deps/main.dep: 没有那个文件或目录
Making deps/main.dep ...
/bin/sh: 3: cannot create deps/main.dep.tmp: Directory nonexistent
Makefile:26: recipe for target 'deps/main.dep' failed
make: *** [deps/main.dep] Error 2
- 原因:make对于include的处理先于all目标构建
- 改进:在include前加上一个‘-'号,如果文件不存在就忽略这一个错误,
Makefile中的死循环问题
https://blog.csdn.net/mantis_1984/article/details/72598848
.PHONY:all clean
MKDIR=mkdir
RM=rm
RMFLAGS=-rf
DIR_OBJS=objs
DIR_EXES=exes
DIR_DEPS=deps
DIRS=$(DIR_EXES) $(DIR_OBJS) $(DIR_DEPS)
CC=gcc
EXE=complicated
EXE:=$(addprefix $(DIR_EXES)/, $(EXE))
SRCS=$(wildcard *.c)
OBJS=$(SRCS:.c=.o)
OBJS:=$(addprefix $(DIR_OBJS)/, $(OBJS))
DEPS=$(SRCS:.c=.dep)
DEPS:=$(addprefix $(DIR_DEPS)/, $(DEPS))
all: $(EXE)
ifeq ("$(wildcard $(DIR_DEPS))", "")
DEP_DIR_DEPS:=$(DIR_DEPS)
endif
-include $(DEPS)
$(DIRS):
$(MKDIR) $@
$(EXE):$(DIR_EXES) $(OBJS)
$(CC) -o $@ $(filter %.o, $^)
$(DIR_OBJS)/%.o:$(DIR_OBJS) %.c
$(CC) -o $@ -c $(filter %.c, $^)
$(DIR_DEPS)/%.dep:$(DEP_DIR_DEPS) %.c
@echo "Making $@ ..."
@set -e;\
$(RM) $(RMFLAGS) $@.tmp;\
$(CC) -E -MM $(filter %.c, $^) > $@.tmp;\
sed 's,\(.*\)\.o[:]*,objs/\1.o:,g' < $@.tmp > $@; \
$(RM) $(RMFLAGS) $@.tmp
clean:
$(RM) $(RMFLAGS) $(DIRS)
11. 再复杂点的依赖关系
依赖的头文件foo.h 依赖于 define.h ,define.h再依赖于other.h ,当other.h 改变时,make会提示没有修改。
但是sed ‘s,(.).o[:],objs/\1.o $@
:,g’ < $@.tmp > $@;
增加 $ @
,就好了。
这里不是很懂???
.PHONY:all clean
MKDIR=mkdir
RM=rm
RMFLAGS=-rf
DIR_OBJS=objs
DIR_EXES=exes
DIR_DEPS=deps
DIRS=$(DIR_EXES) $(DIR_OBJS) $(DIR_DEPS)
CC=gcc
EXE=complicated
EXE:=$(addprefix $(DIR_EXES)/, $(EXE))
SRCS=$(wildcard *.c)
OBJS=$(SRCS:.c=.o)
OBJS:=$(addprefix $(DIR_OBJS)/, $(OBJS))
DEPS=$(SRCS:.c=.dep)
DEPS:=$(addprefix $(DIR_DEPS)/, $(DEPS))
all: $(EXE)
ifeq ("$(wildcard $(DIR_DEPS))", "")
DEP_DIR_DEPS:=$(DIR_DEPS)
endif
-include $(DEPS)
$(DIRS):
$(MKDIR) $@
$(EXE):$(DIR_EXES) $(OBJS)
$(CC) -o $@ $(filter %.o, $^)
$(DIR_OBJS)/%.o:$(DIR_OBJS) %.c
$(CC) -o $@ -c $(filter %.c, $^)
$(DIR_DEPS)/%.dep:$(DEP_DIR_DEPS) %.c
@echo "Making $@ ..."
@set -e;\
$(RM) $(RMFLAGS) $@.tmp;\
$(CC) -E -MM $(filter %.c, $^) > $@.tmp;\
sed 's,\(.*\)\.o[:]*,objs/\1.o $@:,g' < $@.tmp > $@; \
$(RM) $(RMFLAGS) $@.tmp
clean:
$(RM) $(RMFLAGS) $(DIRS)
12. 条件语法
当 make 看到条件语法时将立即对其进行分析,这包括 ifdef、ifeq、ifndef 和 ifneq 四种语句形式。
-
ifeq、ifneq
mi@mi-OptiPlex-7060:~/test/makefile/condition$ cat Makefile .PHONY: all sharp = square desk = square table = circle ifeq ($(sharp), $(desk)) result1 = "desk == sharp" endif ifneq "$(table)" 'square' result2 = "table != square" endif all: @echo $(result1) @echo $(result2) mi@mi-OptiPlex-7060:~/test/makefile/condition$ make desk == sharp table != square
-
ifdef、ifndef
mi@mi-OptiPlex-7060:~/test/makefile/condition$ cat Makefile .PHONY: all foo = define Z ifdef foo result1 = "foo is defined" endif ifndef bar result2 = "bar is not define" endif all: @echo $(result1) @echo $(result2) mi@mi-OptiPlex-7060:~/test/makefile/condition$ make foo is defined bar is not define
-
make clean 也依赖文件夹生成,添加条件判断,让没文件夹时不再重新生成再clean
修改前mi@mi-OptiPlex-7060:~/test/makefile/complicated$ make clean rm -rf exes objs deps mi@mi-OptiPlex-7060:~/test/makefile/complicated$ make clean mkdir deps Making deps/main.dep ... Making deps/foo.dep ... rm -rf exes objs deps
使用条件语句修改依赖
mi@mi-OptiPlex-7060:~/test/makefile/complicated$ cat Makefile .PHONY:all clean MKDIR=mkdir RM=rm RMFLAGS=-rf DIR_OBJS=objs DIR_EXES=exes DIR_DEPS=deps DIRS=$(DIR_EXES) $(DIR_OBJS) $(DIR_DEPS) CC=gcc EXE=complicated EXE:=$(addprefix $(DIR_EXES)/, $(EXE)) SRCS=$(wildcard *.c) OBJS=$(SRCS:.c=.o) OBJS:=$(addprefix $(DIR_OBJS)/, $(OBJS)) DEPS=$(SRCS:.c=.dep) DEPS:=$(addprefix $(DIR_DEPS)/, $(DEPS)) all: $(EXE) ifeq ("$(wildcard $(DIR_DEPS))", "") DEP_DIR_DEPS:=$(DIR_DEPS) endif ifeq ($(MAKECMDGOALS), clean) DEP_DIR_DEPS:= "" endif -include $(DEPS) -include $(DEPS) $(DIRS): $(MKDIR) $@ $(EXE):$(DIR_EXES) $(OBJS) $(CC) -o $@ $(filter %.o, $^) $(DIR_OBJS)/%.o:$(DIR_OBJS) %.c $(CC) -o $@ -c $(filter %.c, $^) $(DIR_DEPS)/%.dep:$(DEP_DIR_DEPS) %.c @echo "Making $@ ..." @set -e;\ $(RM) $(RMFLAGS) $@.tmp;\ $(CC) -E -MM $(filter %.c, $^) > $@.tmp;\ sed 's,\(.*\)\.o[:]*,objs/\1.o $@:,g' < $@.tmp > $@; \ $(RM) $(RMFLAGS) $@.tmp clean: $(RM) $(RMFLAGS) $(DIRS) mi@mi-OptiPlex-7060:~/test/makefile/complicated$ make clean rm -rf exes objs deps mi@mi-OptiPlex-7060:~/test/makefile/complicated$ make clean rm -rf exes objs deps
13. 更复杂的项目
-
文件目录
mi@mi-OptiPlex-7060:~/test/makefile/huge$ tree . ├── build │ └── libs └── source ├── foo │ ├── inc │ └── src │ ├── foo.c │ └── Makefile └── hug └── src
-
修改Makefile
mi@mi-OptiPlex-7060:~/test/makefile/huge/source/foo/src$ cat Makefile .PHONY:all clean MKDIR = mkdir RM = rm RMFLAGS = -rf # 需要学习ar工具的使用 AR = ar ARFLAGS = crs DIR_OBJS = objs DIR_EXES = ../../../build/exes DIR_DEPS = deps DIR_LIBS = ../../../build/libs DIRS = $(DIR_EXES) $(DIR_OBJS) $(DIR_DEPS) $(DIR_LIBS) RMS = $(DIR_OBJS) $(DIR_DEPS) CC = gcc ifneq ($(EXE), "") EXE := $(addprefix $(DIR_EXES)/, $(EXE)) RMS += $(EXE) endif LIB = libfoo.a ifneq ($(LIB), "") LIB := $(addprefix $(DIR_LIBS)/, $(LIB)) RMS += $(LIB) endif SRCS = $(wildcard *.c) OBJS = $(SRCS:.c=.o) OBJS := $(addprefix $(DIR_OBJS)/, $(OBJS)) DEPS = $(SRCS:.c=.dep) DEPS := $(addprefix $(DIR_DEPS)/, $(DEPS)) ifneq ($(EXE), "") all: $(EXE) endif ifneq ($(LIB), "") all: $(LIB) endif ifeq ("$(wildcard $(DIR_DEPS))", "") DEP_DIR_DEPS := $(DIR_DEPS) endif ifeq ($(MAKECMDGOALS), clean) DEP_DIR_DEPS := "" endif -include $(DEPS) $(DIRS): $(MKDIR) $@ $(EXE):$(DIR_EXES) $(OBJS) $(CC) -o $@ $(filter %.o, $^) $(LIB):$(DIR_LIBS) $(OBJS) $(AR) $(ARFLAGS) $@ $(filter %.o, $^) $(DIR_OBJS)/%.o:$(DIR_OBJS) %.c $(CC) -o $@ -c $(filter %.c, $^) $(DIR_DEPS)/%.dep:$(DEP_DIR_DEPS) %.c @echo "Making $@ ..." @set -e;\ $(RM) $(RMFLAGS) $@.tmp;\ $(CC) -E -MM $(filter %.c, $^) > $@.tmp;\ sed 's,\(.*\)\.o[:]*,objs/\1.o $@:,g' < $@.tmp > $@; \ $(RM) $(RMFLAGS) $@.tmp clean: # 删除生成的文件,不删除文件 $(RM) $(RMFLAGS) $(RMS) mi@mi-OptiPlex-7060:~/test/makefile/huge/source/foo/src$ make mkdir deps Making deps/foo.dep ... mkdir objs gcc -o objs/foo.o -c foo.c ar crs ../../../build/libs/libfoo.a objs/foo.o mi@mi-OptiPlex-7060:~/test/makefile/huge/source/foo/src$ make clean rm -rf objs deps ../../../build/libs/libfoo.a
14. 提高复用性
Makefile
- 分离Makefile文件
├── huge
│ ├── build
│ │ ├── exes
│ │ │ └── huge
│ │ ├── libs
│ │ └── make.rule
│ └── source
│ ├── foo
│ │ ├── inc
│ │ └── src
│ │ ├── foo.c
│ │ └── Makefile
│ └── hug
│ └── src
│ ├── deps
│ │ └── main.dep
│ ├── main.c
│ ├── Makefile
│ └── objs
│ └── main.o
- 分解公共部分到make.rule 放在build文件夹之中,每个src之中只写相关部分,并且引用make.rule
- 执行时,cd到makefile/huge/ 目录,export ROOT=
pwd
#/huge/build/make.rule
.PHONY:all clean
MKDIR = mkdir
RM = rm
RMFLAGS = -rf
AR = ar
ARFLAGS = crs
DIR_OBJS = objs
DIR_EXES = $(ROOT)/build/exes
DIR_DEPS = deps
DIR_LIBS = $(ROOT)/build/libs
DIRS = $(DIR_EXES) $(DIR_OBJS) $(DIR_DEPS) $(DIR_LIBS)
RMS = $(DIR_OBJS) $(DIR_DEPS)
CC = gcc
ifneq ($(EXE), "")
EXE := $(addprefix $(DIR_EXES)/, $(EXE))
RMS += $(EXE)
endif
ifneq ($(LIB), "")
LIB := $(addprefix $(DIR_LIBS)/, $(LIB))
RMS += $(LIB)
endif
SRCS = $(wildcard *.c)
OBJS = $(SRCS:.c=.o)
OBJS := $(addprefix $(DIR_OBJS)/, $(OBJS))
DEPS = $(SRCS:.c=.dep)
DEPS := $(addprefix $(DIR_DEPS)/, $(DEPS))
ifneq ($(EXE), "")
all: $(EXE)
endif
ifneq ($(LIB), "")
all: $(LIB)
endif
ifeq ("$(wildcard $(DIR_DEPS))", "")
DEP_DIR_DEPS := $(DIR_DEPS)
endif
ifeq ($(MAKECMDGOALS), clean)
DEP_DIR_DEPS := ""
endif
-include $(DEPS)
$(DIRS):
$(MKDIR) $@
$(EXE):$(DIR_EXES) $(OBJS)
$(CC) -o $@ $(filter %.o, $^)
$(LIB):$(DIR_LIBS) $(OBJS)
$(AR) $(ARFLAGS) $@ $(filter %.o, $^)
$(DIR_OBJS)/%.o:$(DIR_OBJS) %.c
$(CC) -o $@ -c $(filter %.c, $^)
$(DIR_DEPS)/%.dep:$(DEP_DIR_DEPS) %.c
@echo "Making $@ ..."
@set -e;\
$(RM) $(RMFLAGS) $@.tmp;\
$(CC) -E -MM $(filter %.c, $^) > $@.tmp;\
sed 's,\(.*\)\.o[:]*,objs/\1.o $@:,g' < $@.tmp > $@; \
$(RM) $(RMFLAGS) $@.tmp
clean:
$(RM) $(RMFLAGS) $(RMS)
-
加入源程序
-
增加头文件目录变量–INC_DIRS,在make.rule中增加一个条件语句模块,去掉多余空格,然后加上-I(i大写)参数
-
然后在编译中加上头文件依赖
.PHONY:all clean MKDIR = mkdir RM = rm RMFLAGS = -rf AR = ar ARFLAGS = crs DIR_OBJS = objs DIR_EXES = $(ROOT)/build/exes DIR_DEPS = deps DIR_LIBS = $(ROOT)/build/libs DIRS = $(DIR_EXES) $(DIR_OBJS) $(DIR_DEPS) $(DIR_LIBS) RMS = $(DIR_OBJS) $(DIR_DEPS) CC = gcc ifneq ($(EXE), "") EXE := $(addprefix $(DIR_EXES)/, $(EXE)) RMS += $(EXE) endif ifneq ($(LIB), "") LIB := $(addprefix $(DIR_LIBS)/, $(LIB)) RMS += $(LIB) endif SRCS = $(wildcard *.c) OBJS = $(SRCS:.c=.o) OBJS := $(addprefix $(DIR_OBJS)/, $(OBJS)) DEPS = $(SRCS:.c=.dep) DEPS := $(addprefix $(DIR_DEPS)/, $(DEPS)) ifneq ($(EXE), "") all: $(EXE) endif ifneq ($(LIB), "") all: $(LIB) endif ifeq ("$(wildcard $(DIR_DEPS))", "") DEP_DIR_DEPS := $(DIR_DEPS) endif ifeq ($(MAKECMDGOALS), clean) DEP_DIR_DEPS := "" endif include $(DEPS) ifneq ($(INC_DIRS), "") INC_DIRS := $(strip $(INC_DIRS)) INC_DIRS := $(addprefix -I, $(INC_DIRS)) endif $(DIRS): $(MKDIR) $@ $(EXE):$(DIR_EXES) $(OBJS) $(CC) -o $@ $(filter %.o, $^) $(LIB):$(DIR_LIBS) $(OBJS) $(AR) $(ARFLAGS) $@ $(filter %.o, $^) $(DIR_OBJS)/%.o:$(DIR_OBJS) %.c $(CC) $(INC_DIRS) -o $@ -c $(filter %.c, $^) $(DIR_DEPS)/%.dep:$(DEP_DIR_DEPS) %.c @echo "Making $@ ..." @set -e;\ $(RM) $(RMFLAGS) $@.tmp;\ $(CC) $(INC_DIRS) -E -MM $(filter %.c, $^) > $@.tmp;\ sed 's,\(.*\)\.o[:]*,objs/\1.o $@:,g' < $@.tmp > $@; \ $(RM) $(RMFLAGS) $@.tmp clean: $(RM) $(RMFLAGS) $(RMS) EXE = huge LIB = INC_DIRS = $(ROOT)/source/foo/inc include $(ROOT)/build/make.rule .PHONY:all clean EXE = LIB = libfoo.a INC_DIRS = $(ROOT)/source/foo/inc include $(ROOT)/build/make.rule
-
Makefile 调试
-
使用info/warning/error增加调试信息
1. 方法1: $(info “here add the debug info”)但是此不能打印出.mk的行号
2. 方法2: $(warning “here add the debug info”)
3. 方法3: ( e r r o r " e r r o r : t h i s w i l l s t o p t h e c o m p i l e " ) 这个可以停止当前 m a k e f i l e 的编译 4. 方法 4 : 打印变量的值 (error "error: this will stop the compile")这个可以停止当前makefile的编译 4. 方法4: 打印变量的值 (error"error:thiswillstopthecompile")这个可以停止当前makefile的编译4.方法4:打印变量的值(info $(TARGET_DEVICE) ) -
使用echo增加调试信息(echo只能在target:后面的语句中使用,且前面是个TAB)
1. 方法1: @echo “start the compilexxxxxxxxxxxxxxxxxxxxxxx”
2. 方法2: @echo $(files) -
增加链接库
-
修改make.rule ,使用LINK_LIBS, 通过gcc 的-L 搜索
-
在src中添加LINK_LIBS = foo ,库名为libfoo.a
.PHONY: all clean DIRS = $(ROOT)/source/foo/src \ $(ROOT)/source/bar/src \ $(ROOT)/source/hug/src RM = rm RMFLAGS = -rf RMS = $(ROOT)/build/exes $(ROOT)/build/libs all: @set -e; \ for dir in $(DIRS); \ do \ cd $$dir && $(MAKE); \ done @echo "" @echo ":-) Completed" @echo "" clean: @set -e; \ for dir in $(DIRS); \ do \ cd $$dir && $(MAKE) clean; \ done @echo "" @echo ":-) Completed" @echo "".PHONY: all clean DIRS = $(ROOT)/source/foo/src \ $(ROOT)/source/bar/src \ $(ROOT)/source/hug/src RM = rm RMFLAGS = -rf RMS = $(ROOT)/build/exes $(ROOT)/build/libs all: @set -e; \ for dir in $(DIRS); \ do \ cd $$dir && $(MAKE); \ done @echo "" @echo ":-) Completed" @echo "" clean: @set -e; \ for dir in $(DIRS); \ do \ cd $$dir && $(MAKE) clean; \ done @echo "" @echo ":-) Completed" @echo "" .PHONY:all clean MKDIR = mkdir RM = rm RMFLAGS = -rf AR = ar ARFLAGS = crs DIR_OBJS = objs DIR_EXES = $(ROOT)/build/exes DIR_DEPS = deps DIR_LIBS = $(ROOT)/build/libs DIRS = $(DIR_EXES) $(DIR_OBJS) $(DIR_DEPS) $(DIR_LIBS) RMS = $(DIR_OBJS) $(DIR_DEPS) CC = gcc ifneq ($(EXE), "") EXE := $(addprefix $(DIR_EXES)/, $(EXE)) RMS += $(EXE) endif ifneq ($(LIB), "") LIB := $(addprefix $(DIR_LIBS)/, $(LIB)) RMS += $(LIB) endif SRCS = $(wildcard *.c) OBJS = $(SRCS:.c=.o) OBJS := $(addprefix $(DIR_OBJS)/, $(OBJS)) DEPS = $(SRCS:.c=.dep) DEPS := $(addprefix $(DIR_DEPS)/, $(DEPS)) ifneq ($(EXE), "") all: $(EXE) endif ifneq ($(LIB), "") all: $(LIB) endif ifeq ("$(wildcard $(DIR_DEPS))", "") DEP_DIR_DEPS := $(DIR_DEPS) endif ifeq ($(MAKECMDGOALS), clean) DEP_DIR_DEPS := "" endif include $(DEPS) ifneq ($(INC_DIRS), "") INC_DIRS := $(strip $(INC_DIRS)) INC_DIRS := $(addprefix -I, $(INC_DIRS)) endif ifneq ($(LINK_LIBS), "") # $(info $(LINK_LIBS)) LINK_LIBS := $(strip $(LINK_LIBS)) # $(info $(LINK_LIBS)) LINK_LIBS := $(addprefix -l, $(LINK_LIBS)) # $(info $(LINK_LIBS)) endif $(DIRS): $(MKDIR) $@ $(EXE):$(DIR_EXES) $(OBJS) $(CC) -L$(DIR_LIBS) -o $@ $(filter %.o, $^) $(LINK_LIBS) $(LIB):$(DIR_LIBS) $(OBJS) $(AR) $(ARFLAGS) $@ $(filter %.o, $^) $(DIR_OBJS)/%.o:$(DIR_OBJS) %.c $(CC) $(INC_DIRS) -o $@ -c $(filter %.c, $^) $(DIR_DEPS)/%.dep:$(DEP_DIR_DEPS) %.c @echo "Making $@ ..." @set -e;\ $(RM) $(RMFLAGS) $@.tmp;\ $(CC) $(INC_DIRS) -E -MM $(filter %.c, $^) > $@.tmp;\ sed 's,\(.*\)\.o[:]*,objs/\1.o $@:,g' < $@.tmp > $@; \ $(RM) $(RMFLAGS) $@.tmp clean: $(RM) $(RMFLAGS) $(RMS)
#mi@mi-OptiPlex-7060:~/test/makefile/huge/source/hug/src$ cat Makefile
EXE = huge
LIB =
INC_DIRS = $(ROOT)/source/foo/inc
LINK_LIBS = foo
include $(ROOT)/build/make.rule
- 添加一个bar模块,添加一个libbar.a的库
- mi@mi-OptiPlex-7060:~/test/makefile/huge/source$ mkdir bar
- mi@mi-OptiPlex-7060:~/test/makefile/huge/source$ cd bar/
- mi@mi-OptiPlex-7060:~/test/makefile/huge/source/bar$ mkdir src
- mi@mi-OptiPlex-7060:~/test/makefile/huge/source/bar$ mkdir inc
- mi@mi-OptiPlex-7060:~/test/makefile/huge/source/bar$ cd inc/
- mi@mi-OptiPlex-7060:~/test/makefile/huge/source/bar/inc$ vim bar.h
- mi@mi-OptiPlex-7060:~/test/makefile/huge/source/bar/inc$ cd …/src/
- mi@mi-OptiPlex-7060:~/test/makefile/huge/source/bar/src$ vim bar.c
- mi@mi-OptiPlex-7060:~/test/makefile/huge/source/bar/src$ vim Makefile
- mi@mi-OptiPlex-7060:~/test/makefile/huge/source/bar/src$ make
- 在hug/src/main.c 中引用bar()函数,include “bar.h”
- 在hug/src/Makefile中修改INC_DIRS 和LINK_LIBS,如下
├── build
│ ├── exes
│ │ └── huge
│ ├── libs
│ │ ├── foo.a
│ │ ├── libbar.a
│ │ └── libfoo.a
│ └── make.rule
└── source
├── bar
│ ├── inc
│ │ └── bar.h
│ └── src
│ ├── bar.c
│ ├── deps
│ │ └── bar.dep
│ ├── Makefile
│ └── objs
│ └── bar.o
├── foo
│ ├── inc
│ │ ├── define.h
│ │ ├── foo.h
│ │ └── other.h
│ └── src
│ ├── deps
│ │ └── foo.dep
│ ├── foo.c
│ ├── Makefile
│ └── objs
│ └── foo.o
└── hug
└── src
├── deps
│ └── main.dep
├── main.c
├── Makefile
└── objs
└── main.o
#mi@mi-OptiPlex-7060:~/test/makefile/huge/source/hug/src$ cat Makefile
EXE = huge
LIB =
INC_DIRS = $(ROOT)/source/foo/inc \
$(ROOT)/source/bar/inc
LINK_LIBS = foo bar
include $(ROOT)/build/make.rule
- 简化Make操作
- 新建一个文件huge/source/build/Makefile
- 文件夹要分先后,先写lib库的路径,再写可执行程序路径,因为Makefile要分先后
.PHONY: all clean
DIRS = $(ROOT)/source/foo/src \
$(ROOT)/source/bar/src \
$(ROOT)/source/hug/src
RM = rm
RMFLAGS = -rf
RMS = $(ROOT)/build/exes $(ROOT)/build/libs
all:
@set -e; \
for dir in $(DIRS); \
do \
cd $$dir && $(MAKE); \
done
@echo ""
@echo ":-) Completed"
@echo ""
clean:
@set -e; \
for dir in $(DIRS); \
do \
cd $$dir && $(MAKE) clean; \
done
@echo ""
@echo ":-) Completed"
@echo ""
-
完整编译
cd makefile/huge export ROOT=`pwd` cd build make