Makefile 规则

本文介绍了make工具在编译大型工程中的作用,以及cmake、qmake、ninja和automake等高级构建系统的出现,详细讲解了它们的功能、工作原理和配置文件。同时,涵盖了Makefile的关键概念,如预处理、赋值规则和条件判断等。
摘要由CSDN通过智能技术生成

引入:

为什么 -- 产生前景

之前的编译都是直接使用gcc对代码进行编译,这对简单的工程是可以的,但当我们遇到复杂的工程时,每次用gcc等编译工具去操作就会显得很低效。

有什么用 -- 作用

因此make工具就出现了, make的出现是为了解决手动编译和链接大型工程的问题
它可以避免重复的工作,提高效率,保证正确性

make 工具介绍:


make工具就根据makefile中的命令进行编译和链接的。  但是当工程非常大的时候,手写  makefile也是非常麻烦的,如果换了个平台makefile又要重新修改,因此更高级的一些构建系统或者工具,像cmake、qmake、ninja和auto make就出现了,它们可以根据一些配置文件来自动化编译和链接软件项目。


 

cmake是一个跨平台的构建系统,它可以根据CMakeLists.txt中的指令来生成不同平台和工具的工程文件,例如Makefile、Visual Studio解决方案、Ninja文件等。cmake可以支持多种语言和多种架构,它还提供了一些高级功能,如测试、打包、安装等


qmake是一个用于Qt项目的构建系统,它可以根据.pro或.pri中的指令来生成Makefile或其他形式的工程文件。

ninja是一个小巧而快速的构建工具,它可以根据ninja.build中的规则来执行编译和链接命令。ninja主要关注于性能和效率,它可以利用多核处理器和并行处理来加速构建过程。ninja通常不需要用户直接编写配置文件,而是由其他构建系统(如cmake)来生成

auto make是一个用于生成Makefile.in文件的工具,Makefile.in是一种用于auto conf的配置文件格式,auto conf是一个用于生成configure脚本的工具。configure脚本是一个用于检测系统环境并生成最终的Makefile文件的脚本Makefile.am是一种用于auto make的配置文件格式,它包含了一些指令和变量,用于定义程序或库的源文件、目标文件、依赖关系和编译选项等


make是一个经典而通用的构建工具,它可以根据Makefile中的规则来执行编译和链接命令。make可以支持多种平台和工具,它还提供了一些高级功能,如条件判断、函数调用、模式匹配。


Makefile 编译四阶段: 


 预处理(Pre-Processing)、编译(Compiling)、汇编 (Assembliang)、链接(Linking)


Makefile 规则:


四种赋值规则: 

= 表示延迟展开赋值,即变量的值是在使用时才确定,可能会受到后面的赋值影响。例如,VAR_A = A,VAR_B = $(VAR_A) B,VAR_A = AA,那么最后VAR_B的值是AA B,而不是A B。


:= 表示直接赋值,即变量的值是在定义时就确定,不会受到后面的赋值影响。例如,VAR_A := A,VAR_B := $(VAR_A) B,VAR_A := AA,那么最后VAR_B的值是A B,而不是AA B。


?=表示条件赋值,即只有当变量没有被赋值时,才使用等号后面的值作为变量的值。例如,VAR ?=new_value,如果VAR在之前没有被赋值,那么VAR的值就为new_value,否则保持原来的值不变。


+= 表示追加赋值,即将等号后面的值追加到变量原来的值之后,形成一个新的值。例如,VAR +=
new_value,如果VAR在之前没有被赋值,那么VAR的值就为new_value,如果VAR在之前被赋值为old_value,那么VAR的值就为old_value new_value

case : 

#  号是注释
# 规则一 赋值
TARGET = hello # = 立即赋值 TARGET 赋值为hello, 需要 $(TARGET)  这种形式引用
CC := gcc # := 延迟赋值
CC ?= g++ # if 前面没有定义CC 这个变量的额话,就定义为 g++,否则就不定义
CC += -g  # 在CC 后面 加上 -g 的参数


debug : 
    @echo "hello world"
hello:
    $(CC) -o $(TARGET)  hello.c    
#    gcc -o ${TARGET}  hello.c
clean: 
    @rm hello

.PHONY: clean        


 $符号表示取变量的值,当变量名多于一
个字符时,使用"( )":


= 和 := 的区别


#  号是注释
# 规则一 赋值
TARGET = hello # = 立即赋值 TARGET 赋值为hello, 需要 $(TARGET)  这种形式引用
CC := gcc # := 延迟赋值
#TARGET1 = $(CC)  $(TARGET)
TARGET1 := $(CC)  $(TARGET)

CC ?= g++ # if 前面没有定义CC 这个变量的额话,就定义为 g++,否则就不定义
CC += -g  # 在CC 后面 加上 -g 的参数


debug : 
    @echo "hello world"
    echo $(TARGET1)
hello:
    $(CC) -o $(TARGET)  hello.c    
#    gcc -o ${TARGET}  hello.c
clean: 
    @rm hello

.PHONY: clean        

说明
上面是 = 延迟赋值的结果 ,收到后续CC 改变的影响
下面是 := 立即赋值的结果,不受影响

------------------

细节补充

1. \ --  换行符 -- 表示下一行的内容 也是这行的

2.make 后面   没有加参数   就默认执行第一个


比如这里我就是执行debug1:

------------------------


$符的其他用法:


$^ 表示所有的依赖文件
$@ 表示生成的目标文件  -- 这里是指 $(TARGET) -- 目标文件
$< 代表第一个依赖文件

---------------------


 变量的替换引用


语法格式:


$(var:a=b)或${var:a=b}

case:

表示把变量var的值中的a后缀替换成b后缀。例如:
src := a.c b.c c.c
obj := $(src:c=o)

把变量src的值中的.c后缀替换成.o后缀,赋值给变量obj,结果是:
obj := a.o b.o c.o

赋值总case(含详细注释):

#  号是注释
# 规则一 赋值 --- 以下是四种赋值
TARGET = hello # = 立即赋值 TARGET 赋值为hello, 需要 $(TARGET)  这种形式引用
CC := gcc # := 延迟赋值
#TARGET1 = $(CC)  $(TARGET)
#TARGET1 := $(CC)  $(TARGET)
CC ?= g++ # if 前面没有定义CC 这个变量的额话,就定义为 g++,否则就不定义
CC += -g  # 在CC 后面 加上 -g 的参数

SRC = hello.c
OBJ = $(SRC:c=o)  # 替换SRC 中的 .c 文件为 .o的格式


debug1 : 
    @echo "hello mxj"
    @echo $(OBJ)

debug : 
    @echo "hello world"
#    echo $(TARGET1)
$(TARGET): $(SRC)   # 添加依赖,if没有 hello.o 文件,我们就去生成
    $(CC) -o $@ $^
#    $(CC) -o $(TARGET)      \  
#    hello.c    
#    gcc -o ${TARGET}  hello.c

compile: $(TARGET)

clean: 
    @rm hello  hello.o -r     #  -r 递归删除 ,递归后面子文件夹里面有这些文件,也被删除

.PHONY: clean        compile


========================


规则二  -- 常见函数

函数格式


Makefile函数的基本格式是:$(<func><argc> )或者是${ <func><argc>},其中,
func是函数名argc是函数的参数

参数之间要用逗号分隔开,参数和函数名之间使用空格分开。调用函数的时候要使用字符“$”,后面可以跟小括号或者大括号。


--------------------------------


1) wildcard 通配符:


Makefile中的wildcard 是一个函数,用于  扩展通配符,返回与通配符匹配的文件列表。通配符是一种特
殊的字符,可以表示多个文件名或目录名,常见的通配符有 * 和 ?,分别表示任意长度的任意字符和单个
任意字符。

格式如下:
$(wildcard argments)


比如*.c 表示所有以 .c 结尾的文件名,a?.txt 表示所有以 a 开头,中间有一个任意字符,以 .txt 结尾的文
件名。例如:
SRC = $(wildcard src/*.c)

--------------------------------------


2)shell:


$(shell <cmd> <args>)
cmd: 执行命令名称
args:参数列表
返回值: 返回命令执行结果

例如:
SRC = $(shell find . -name *.c)

--------------------------------------

3) patsubst替换函数:


$(patsubst pattern,replacement,text)
pattern: 是一个包含通配符 % 的模式,表示匹配任意长度的任意字符
replacement: 是一个替换字符串,也可以包含 %,表示用 pattern 中匹配的字符替换。
text: 是一个要处理的文本,可以包含多个以空格分隔的单词


返回值:patsubst 函数会在 text 中找到所有符合 pattern 的单词,并用 replacement 替换它们,然后
返回替换后的文本。

例如,如果有一个变量 src,它的值是:
src = a.c b.c c.c
想把它的值中的所有 .c 后缀替换成 .o 后缀,可以这样写:
obj = $(patsubst %.c,%.o,$(src))
这样,obj 的值就是:
obj = a.o b.o c.o

------------------------------------

4) subst替换函数


$(subst from,to,text)
from: 是要被替换的字符或单词
to: 是替换后的字符或单词
text: 是要处理的字符串。
返回值:subst 函数会在 text 中找到所有的 from,并用 to 替换它们,然后返回替换后的字符串。
例如
$(subst ee,EE,feet on the street)
返回:
fEEt on the strEEt

case: 两个替换函数 实现 创建文件:


#  号是注释
# 规则一 赋值 --- 以下是四种赋值
TARGET = hello # = 立即赋值 TARGET 赋值为hello, 需要 $(TARGET)  这种形式引用
CC := gcc # := 延迟赋值
#TARGET1 = $(CC)  $(TARGET)
#TARGET1 := $(CC)  $(TARGET)
# CC ?= g++ # if 前面没有定义CC 这个变量的额话,就定义为 g++,否则就不定义
CC += -g  # 在CC 后面 加上 -g 的参数

# SRC = hello.c
# SRC = $(wildcard src/*.c)
SRC:=$(shell find . -name *.c)

#TARGET := $(subst .c,,$(SRC)) # 把他的 后缀名替换为空就能生成 hello 文件
#TARGET:= $(patsubst ./src/%,./obj/%,$(subst .c,,$(SRC))); # 替换src 为 obj 就达到这obj下面创建hello文件的目的
TARGET := $(patsubst ./src/%,./obj/%,$(subst .c,,$(SRC)))

#TARGET := $(patsubst %.c, %,$(subst src,obj, $(SRC)))
TARGET_DIR = $(dir $(TARGET))

# OBJ = $(SRC:c=o)  # 替换SRC 中的 .c 文件为 .o的格式
# OBJ = $(patsubst %.c,%.o,$(SRC))
# OBJ = $(subst .c,.o,$(SRC))

debug: 
    @echo "hello mxj"
    echo $(SRC)
#    echo $(TARGET)
    echo $(TARGET)
    echo $(TARGET_DIR)

$(TARGET): $(SRC)   # 添加依赖,if没有 hello.o 文件,我们就去生成
    mkdir  $(TARGET_DIR)
    $(CC) -o $@ $<
#    $(CC) -o $(TARGET)      \  
#    hello.c    
#    gcc -o ${TARGET}  hello.c

compile: $(TARGET)

clean: 
    @rm  $(TARGET_DIR) -rf     

.PHONY: clean        compile

------------------------------------

5)dir函数:


$(dir NAMES...)
dir 函数是一个用于从文件名序列中提取目录部分的函数

------------------------------------------------

前后缀说明

先说明前后缀以 . 作为分割符号

举例:  hello.c  --->  前缀: hello  后缀:  .c

6)suffix函数 --  取出后缀 

$(suffix <names...>) 

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


------------------------------------------------

7)basename函数  - - 取出前缀


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

case : 打印前后缀

------------------------------------------------

8) addsuffix函数

$(addsuffix <suffix>,<names...>)
功能:把后缀加到中的每个单词后面。
返回:返回加过后缀的文件名序列。


例如:
$(addsuffix .c,foo bar)
返回值:
foo.c bar.c”


------------------------------------------------

9)addprefix函数

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

case: 添加前后缀


-----------------------------------------


10)foreach函数


$(foreach <var>,<list>,<text>)
把list中使用空格分割的单词依次取出并赋值给变量var, 然后执行text表达式
例如:
files := foo bar baz
files-with-c := $(foreach file,$(files),$(file).c)

case: 给文件路径统一加上参数 -I

======================================

规则三 -  Makefile 的条件判断语句:

ifeq/ifneq语句:

ifeq语句 : 判断参数 是否相等,相等为 true, 否则是 false

ifeq (arg1, arg2)
#arg1 arg2 相等执行这里的语句
else
#arg1 arg2 不相等执行这里的语句
endif

  

ifneq语句:判断参数 是否不等,不等为 true, 否则为 false

ifneq (arg1, arg2) 
#arg1 arg2 不相等执行这里的语句
else
#arg1 arg2 相等执行这里的语句
endif

注意: 


1. 参数 可以为空 ,就判断另一个参数 是否为空


2.还可以利用findstring()  和 ifneq 配合 


比如:  ifneq($(findstring  $(BOARD) , "orangepi-a64" "orang....." ), )
 if 字符串里面没有目标值就返回空,就执行endif
 有的话就返回非空不相等执行下面的 语句

------------------------------------

ifdef/ifndef语句


ifdef 语句: 判断参数 是否有值 ,有值为 true, 否则是 false
ifndef : 判断参数 是否没有值 ,没有值为 true, 否则为 false.

ifdef:


ifdef var
#如果定义了var,执行这里的内容
else
#如果没定义var,执行这里的内容
endif

ifndef:

infdef var
#如果没定义var,执行这里的内容
else
#如果定义var,执行这里的内容
endif

--------------------------------------


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值