基本格式
targets:
[tab键]command
target:目标文件
command:是 make 需要执行的命令,
基本规则
- make 会在当前目录下找到一个名字叫 Makefile 或 makefile 的文件
- 如果找到,它会找文件中第一个目标文件(target),并把这个文件作为最终的目标文件
- 如果 target 文件不存在,或是 target 文件依赖的 .o 文件(prerequities)的文件修改时间要比 target 这个文件新,就会执行后面所定义的命令 command 来生成 target 这个文件
变量
变量定义
cpp := src/main.cpp
obj := objs/main.o
变量引用
cpp := src/main.cpp
obj := objs/main.o
$(obj) : ${cpp}
@g++ -c $(cpp) -o $(obj)
compile : $(obj)
预定义变量
cpp := src/main.cpp
obj := objs/main.o
$(obj) : ${cpp}
@g++ -c $< -o $@
@echo $^
compile : $(obj)
.PHONY : compile
makefile常用符号
= 赋值符
:= 立即赋值运算符 定义后不更改
?= 默认赋值运算符 已经定义则不进行任何操作
+= 累加
\ 续航符
* 匹配任意字符串
% 匹配任意字符串并作为变量使用
makefile常用函数
$(fn, arguments) or ${fn, arguments}
- fn: 函数名
- arguments: 函数参数,参数间以逗号 , 分隔,而函数名和参数之间以“空格”分隔
$(shell <command> <arguments>)
名称:shell 命令函数 —— shell
功能:调用 shell 命令 command
返回:函数返回 shell 命令 command 的执行结果
示例
# shell 指令, 获取计算机架构
HOST_ARCH := $(shell uname -m)
$(subst <from>,<to>,<text>)
名称:字符串替换函数——subst
功能:把字串 <text> 中的 <from> 字符串替换成 <to>
返回:函数返回被替换过后的字符串
示例
cpp_srcs := $(shell find src -name "*.cpp")
cpp_objs := $(subst src/,objs/,$(cpp_objs))
$(patsubst <pattern>,<replacement>,<text>)
名称:模式字符串替换函数 —— patsubst
功能:通配符 %,表示任意长度的字串,从 text 中取出 patttern, 替换成 replacement
返回:函数返回被替换过后的字符串
示例
cpp_srcs := $(shell find src -name "*.cpp") #shell指令,src文件夹下找到.cpp文件
cpp_objs := $(patsubst %.cpp,%.o,$(cpp_srcs)) #cpp_srcs变量下cpp文件替换成 .o文件
makefile条件分支
- ifeq/else/endif (ifneq/else/endif ifdef/else/endif相同用法 )
ifeq ($(XXX),XXX)
else ifeq ($(XXX),XXX)
else ifeq ($(XXX),XXX)
endif
compile
# 使用shell命令在src目录下查找所有的.cpp文件,并将结果赋值给cpp_srcs变量。
cpp_srcs := $(shell find src -name *.cpp)
# 将cpp_srcs中的每个.cpp文件名替换成对应的.o文件名,并将结果赋值给cpp_files变量
cpp_files := $(patsubst src/%.cpp,src/%.i,$(cpp_srcs))
# 这段代码是一个规则,意思是将src目录下的每个.cpp文件进行预处理,
# 使用g++编译器进行预处理,生成对应的.o文件。
src/%.o : src/%.cpp
@g++ -E $^ -o $@
# 定义一个名为preprocess的目标,依赖于pp_files中的所有文件。
# 当执行make preprocess时,会先生成cpp_files中的所有文件,然后再执行后续的操作。
preprocess : $(cpp_files)
clean :
@rm -f src/*.i
debug :
@echo $(pp_files)
.PHONY : debug preprocess clean
- 编译选项
-m64: 指定编译为 64 位应用程序
-std=: 指定编译标准,例如:-std=c++11、-std=c++14
-g: 包含调试信息
-w: 不显示警告
-O: 优化等级,通常使用:-O3
-I: 加在头文件路径前
fPIC: (Position-Independent Code), 产生的没有绝对地址,全部使用相对地址,代码可以被加载到内存的任意位置,且可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的 - 链接选项
-l: 加在库名前面
-L: 加在库路径前面
-Wl,<选项>: 将逗号分隔的 <选项> 传递给链接器
-rpath=: “运行” 的时候,去找的目录。运行的时候,要找 .so 文件,会从这个选项里指定的地方去找
链接库
静态链接
g++ [main.o] -o [可执行文件] -l[库名] -L[库路径]
动态链接
g++ [main.o] -o [可执行文件] -l[库名] -L[库路径] -Wl,-rpath=[库路径]
makefile中的特殊字符含义
$@ 表示目标文件
$^ 表示所有的依赖文件
$< 表示第一个依赖文件
$? 表示比目标还要新的依赖文件列表
# 简单的makefile模板
OBJ := test
CFLAGS := -Wall -g -L../lib -lXXX
APP_SRC := ../src/main.c
INC := -I../include/
CC := arm-linux-gcc
$(OBJ) : $(APP_SRC)
${CC} $(APP_SRC) -o $@ $(CFLAGS) ${INC}
.PHONY : clean
clean:
rm -f $(OBJ)