编译的四个阶段
预处理 编译 汇编 链接
Makefile
一、Makefile的作用
Makefile是一种用于自动化编译和构建软件项目的文件
Makefile的规则
语法规则:
target(目标) ... : prerequisites (前提、依赖的文件)...
command ... ...
eg.
debug:
@echo "hello world"
会输出hello world
如果编译一个c文件
#include <stdio.h>
int main()
{
printf("hello world\n");
return 0;
}
其Makefile文件可以这样写
debug:
@echo "hello world"
hello:
@gcc -o hello hello.c
在指令面前加上 “@”能不打印处指令。
伪目标
如果一个目标(debug,hello)和一个实际文件同名,那么make会认为该目标已经是最新的,不需要重新生成,也不会执 行其命令。通过将目标声明为伪目标,可以避免这种情况,强制执行其命令。
debug:
@echo "hello world"
hello:
@gcc -o hello hello.c
clean:
@rm hello
.PHONY:clean
如果当前目录下有命名为clean文件,需要在makefile后面加上 .PHONY:clean 可以。这个是强制执行clean 这个目标
Makefile变量赋值和预定义变量
四种运算符分别是=、:=、?=和+=, $符号表示取变量的值,当变量名多于一 个字符时,使用"( )":
= 表示延迟展开赋值,即变量的值是在使用时才确定,可能会受到后面的赋值影响。
:= 表示直接赋值,即变量的值是在定义时就确定,不会受到后面的赋值影响。
+= 表示追加赋值,即将等号后面的值追加到变量原来的值之后,形成一个新的值。
TARGET = hello
cc := gcc
cc ?= g++ #如果前面没有定义cc 就定义为g++
TARGET1 = ${cc}${TARGET}
cc += -g #后面加参数
# :=立即赋值, =
由于 TARGET1 = ${cc}${TARGET} 所以 TARGET1 = gcc -g hello
$符的其他用法:
$^ 表示所有的依赖文件
$@ 表示生成的目标文件
$< 代表第一个依赖文件
注释和换行
采用#进行一行注释
采用\作为续行符
变量的替换引用
语法格式:$(var:a=b)或${var:a=b}
src :=hello.c b.c
obj :=${src:.c = .o}
结果是把.c改成了.o
eg。
TARGET = hello
cc := gcc
src := hello.c
debug:
echo "hello world"
${TARGET}:${src}
#${cc} -o ${TARGET} ${src}
$(CC) -o $@ $<
# $@ 生成的目标文件(TAERGET)
# $< 第一个依赖文件(src)
# $^ 所有的依赖文件
compile:
${TARGET}
clean:
rm clean
.PHONY:clean
二、常见函数
Makefile函数的基本格式是:$(<function> <arguement> )或者是${<function> <arguement> },其中,function是函数名,arguement是函数的参数,参数之间要用逗号分隔 开,参数和函数名之间使用空格分开。调用函数的时候要使用字符“$”,后面可以跟小括号或者大括号。
1)wildcard !
akefile中的wildcard 是一个函数,用于扩展通配符,返回与通配符匹配的文件列表。通配符是一种特 殊的字符,可以表示多个文件名或目录名,常见的通配符有 * 和 ?.
比如*.c 表示所有以 .c 结尾的文件名,a?.txt 表示所有以 a 开头,中间有一个任意字符,以 .txt 结尾的文 件名。例如:
SRC = $(wildcard src/*.c)
#查看src文件夹所有的.C文件
2)shell !
${shell <命令> <参数列表>} //返回值是命令执行结果
查询当前目录下 命名中含有.c的文件
SRC := $(shell find . -name *.c)
3)patsubst替换函数 !
${paysubst pattern,replacement,text}
pattern: 是一个包含通配符 % 的模式,表示匹配任意长度的任意字符
replacement: 是一个替换字符串,也可以包含 %,表示用 pattern 中匹配的字符替换。 text: 是一个要处理的文本,可以包含多个以空格分隔的单词。
返回值:patsubst 函数会在 text 中找到所有符合 pattern 的单词,并用 replacement 替换它们,然后 返回替换后的文
本。
src := a.c b.c c.c. d.c
obj := $(patsubst %.c,%.o,$(src))
4) subst替换函数 !
$(subst from,to,text)
from: 是要被替换的字符或单词
to: 是替换后的字符或单词
text: 是要处理的字符串。
返回值:subst 函数会在 text 中找到所有的 from,并用 to 替换它们,然后返回替换后的字符串。
把”from“ 改成“
to” 在text中
$(subst ee,EE,feet on the street)
5)dir函数:!
dir 函数是一个用于从文件名序列中提取目录部分的函数
$(dir NAMES...)
SRC_DIR := $(dir $(SRC))
把src中文件的路径提出来
结合以上内容写一个makefile
编译src文件下的.c文件,生成的可执行文件放在obj目录下。
cc := gcc
SRC :=${shell find . -name *.c}
SRC_DIR :=${dir ${SRC}}
mid1:=${subst .c, ,$(SRC)}
mid2:=$(subst main,hello,$(mid1))
OBJ:=$(patsubst ./src/%,./obj/%,${mid2})
#OBJ:=$(patsubst ./src/%,./obj/%,${mid2})
#=====================================================
defult:
echo "hello world"
echo ${SRC}
echo ${OBJ}
# echo ${OBJ1}
${OBJ}:${SRC}
mkdir -p obj
${cc} -o $@ $^
ok:${OBJ}
clean:
rm ${OBJ}
.PHONY:clean
====上面是为了奏出想要的指令。
6)suffix函数
$(suffix <name....>)
功能:从文件名序列中取出各个文件名的后缀。
返回值:返回文件名序列的后缀序列,如果文件没有后缀,则返回空字串。
$(suffix src/foo.c src-1.0/bar.c hacks)
返回值:.c .c
7)basename函数
$(basename )
功能:从文件名序列中取出各个文件名的前缀部分。
返回值:返回文件名序列的前缀序列,如果文件没有前缀,则返回空字符串。
${basename src/foo.c src-1.0/bar.c hacks}
返回:
src/foo src-1.0/bar hacks
8)addsuffix函数
$(addsuffix ,<suffix>,<name>)
功能:把后缀(suffix)加到中的每个单词(name)后面。
返回:返回加过后缀的文件名序列。
$(addsuffix .c,foo bar)
返回值:foo.c bar.c”
9)addprefix函数
$(addprefix src/,foo bar)
功能:把前缀加到中的每个单词后面。
返回值:返回加过前缀的文件名序列。
$(addprefix src/,foo bar)
返回值 :src/foo src/bar
10)foreach函数!
和循环差不多:不断分割var,用每个var片段执行text操作
$(foreach <var>,<list>,<text>)
把list中使用空格分割的单词依次取出并赋值给变量var, 然后执行text表达式
${foreach var, ${INCLUDE}, -I$(var)}
INCLUDE := /usr/include \
/usr/local/include
I_FLAGS:=${foreach var, ${INCLUDE}, -I $(var)}
结果 : -I /usr/include -I /usr/local/include
11)条件判断语言
ifeq/ifneq语句:
ifeq语句 : 判断参数 是否相等,相等为 true, 否则是 false.
ifneq语句:判断参数 是否不等,不等为 true, 否则为 false.
ifeq (arg1, arg2)
#arg1 arg2 相等执行这里的语句
else
#arg1 arg2 不相等执行这里的语句
endif
ifneq (arg1, arg2)
#arg1 arg2 不相等执行这里的语句
else
#arg1 arg2 相等执行这里的语句
endif
ifdef/ifndef语句
ifdef 语句: 判断参数 是否有值 ,有值为 true, 否则是 false
ifndef : 判断参数 是否没有值 ,没有值为 true, 否则为 false.
ifdef var #如果定义了var,执行这里的内容 else #如果没定义var,执行这里的内容 endif infdef var #如果没定义var,执行这里的内容 else #如果定义var,执行这里的内容 endif