以下的知识来源于网络,如有侵权,请联系我删除哈
内容介绍:
1、makefile文件的命名
2、make的基本语法
3、变量
4、条件判断
5、包含其它makefile文件
6、隐含(默认)规则
7、模式规则(匹配)
8、自动化变量
9、函数
内容详细介绍:
1、makefile文件的命名
默认的情况下, make 会在工作目录(执行 make 的目录)下按照文件名顺序寻找
makefile 文件读取并执行,查找的文件名顺序为:“ GNUmakefile”、“ makefile”、“ Makefile”。
墙裂推荐使用“ Makefile”
当 makefile 文件的命名不是这三个任何一个时,需要通过 make 的“ -f”或者“ --file”选项来指定 make 读取的 makefile 文件。给 make 指定 makefile 文件的格式为:“ -f NAME” 或者“ —file=NAME”, 它指定文件“ NAME” 作为执行 make 时读取的 makefile文件。
示例:
2、make的基本语法
目标:依赖
命令 # 在命令前加@,就能不打印本句命令在控制台上
例子:
all:
echo "hello world"
结果:
在执行命令语句前加@:
all:
@echo "hello world"
3、变量
- 系统变量(隐含变量):就是make程序内部提前定义好的的变量
all:
@echo "$(CC)" # 变量 CC: c语言编译器,默认是cc
@echo "$(AS)" # 变量 AS: c语言汇编器,默认是as
@echo "$(AR)" # 变量 AR: 静态库打包程序,默认是ar
@echo "$(MAKE)" # 变量 MAKE: Makefile的处理工具,默认是make
结果:
那么问题来了,cc、as、ar、make代表什么意思?这些应用程序在Linux的什么位置?
通过以下操作就可以知道了
他们的一一对应关系如下:
cc --> /usr/bin/gcc
as --> x86_64-linux-gnu-as
ar --> x86_64-linux-gnu-ar
make --> /usr/bin/make
- 变量的使用
通过$(var)来完成变量的引用
( $(command) 在shell脚本文件中为执行shell命令)
- 定义变量
Makefile文件中的变量定义很简单,主要是变量的赋值有些地方需要注意。
变量的赋值可以使用 =, :=, ?=, +=四种方式来给变量赋值,那么每种赋值方式有什么不一样呢?
:= 为立即赋值
= 为延时赋值
?= 为空赋值
+= 为追加赋值
make var=xxx 为命令行赋值
示例1:使用:=来赋值
var1:=hello
var2:=$(var1)world
var1:=shit
all:
@echo $(var2)
结果:
使用:=来给变量赋值,是立即赋值,在执行var1:=hello时,变量var1的值就已经确定下来了哈,所以最后打印的是helloworld, 而不是shitworld.
示例 2:使用=来赋值
var1=hello
var2=$(var1)world
var1=shit
all:
@echo $(var2)
结果:
使用=来给变量赋值,是延迟赋值,使用=来赋值是Makefile里面最后被被指定的值,因为我们最后给变量var1赋值为shit,所以最后打印为shitworld,而不是helloworld.
示例 3:使用?=来赋值
var1:=hello
var1?=shit
var2:=$(var1)world
all:
@echo $(var2)
结果:
在第一行代码中,使用:=立即赋值,所以var1的值为hello,执行到第二行代码,var1变量赋值过了,这里就不赋值了,直接跳过了(空赋值的意思是:如果变量前面赋值过了,就不再被赋值了)
如果没被赋值过,则被赋值
#var1:=hello 这句注释掉
var1?=shit
var2:=$(var1)world
all:
@echo $(var2)
结果:
示例 4:使用+=来赋值
var1:=hello
var1+=shit
var2:="$(var1) world"
all:
@echo $(var2)
结果:
使用+=来赋值,两个字符串会自动用空格来连接
示例 5:使用make var=xxx 来赋值
这个本质上也是延迟赋值哈,只是他赋值的位置比较特殊,在命令行上而已,照用不误
var1=hello
var2=$(var1)world
var1=shit
all:
@echo $(var2)
结果:
因为var是最晚赋值的,在执行命令的才定义,所以不管Makefile文件里面原先定义的是什么,var1都会替换成jj.
- 导出变量
//TODO
4、条件判断
条件判断的基本语法:任何一个条件表达式都必须以“ endif”结束。
CONDITIONAL-DIRECTIVE(条件表达式)中的关键字可以是ifeq、ifneq、ifdef、ifndef。(注意:这些关键字后面一定要紧跟一个空格,会报错的哈;另外在TEXT-IF-TRUE中是输出不了信息到控制台的,虽然没有报错哈)
CONDITIONAL-DIRECTIVE的写法:以ifeq为例
ifeq (ARG1, ARG2) #最常用,推荐时使用
ifeq 'ARG1' 'ARG2'
ifeq "ARG1" "ARG2"
ifeq "ARG1" 'ARG2'
ifeq 'ARG1' "ARG2"
①不带else的语法:
CONDITIONAL-DIRECTIVE
TEXT-IF-TRUE
endif
示例:
var1=hello
var2=world
#ifeq (hello, hello) #执行结果为:真
#ifeq 'hello' 'hello' #执行结果为:真
#ifeq "hello" "hello" #执行结果为:真
#ifeq "hello" 'hello' #执行结果为:真
#ifeq 'hello' "hello" #执行结果为:真
#ifeq ($(var1),hello) #执行结果为:真
#ifeq ($(var1),'hello') #执行结果为:假
#ifeq ($(var1),"hello") #执行结果为:假
#ifeq (hello,"hello") #执行结果为:假
#ifeq ('$(var1)','hello') #执行结果为:真
#ifeq ("$(var1)","hello") #执行结果为:真
#ifeq ("$(var1)",'hello') #执行结果为:假
ifeq ('$(var1)',"hello") #执行结果为:假
var1=shit
endif
all:
@echo "$(var1)$(var2)"
#打印结果:
#条件表达式为真,打印shitworld
#条件表达式为假,打印helloworld
个人总结:这个记忆方法只是我的记忆方式,仅供参考:
只要通过$()来使用变量的。在判断时,两者的字符串要完全完全一样才为真,否则为假;
如果两者仅仅是使用引号,两者引号内容一样且引号最多只能差一个就为真,否则为假;
②带else的语法格式:
var1=hello
var2=world
ifeq ($(var1),$(var2))
var1=shit
else
var1=my
endif
all:
@echo "$(var1)$(var2)"
5、包含其它makefile文件
Makefile 中包含其它文件所需要使用的关键字是“ include”,和 c 语言对头文件的包含方式一致。
include”指示符告诉 make 暂停读取当前的 Makefile,而转去读取“ include”指定的一个或者多个文件,
完成以后再继续当前 Makefile 的读取。 Makefile 中指示符“include”书写在独立的一行,
其形式如下:
include FILENAMES...
FILENAMES 是 shell 所支持的文件名(可以使用通配符)。
注意:符包含进来的Makefile中,如果存在变量或者函数的引用。它们将会在包含它们的Makefile中被展开
示例:
假设存在三个.mk 文件 a.mk、 b.mk、 c.mk,“ $(bar)”被扩展为“ bish bash”。则
include foo *.mk $(bar) <==等价于右边的哈==> include foo a.mk b.mk c.mk bish bash
6、隐含(默认)规则
一句话概括就是:
make对C文件的编译过程是由.c 源文件编译生成.o 目标文件。
当 Makefile 中出现一个.o 文件目标时,
make会使用这个通用的方式将后缀为.c 的文件编译称为目标的.o 文件
7、模式规则(匹配)
%.o:%.c
8、自动化变量
- $<:第一个依赖文件
- $^:全部的依赖文件
- $@:目标
示例:
blog.c文件:
//blog.c文件
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
char dest[50];
bzero(dest, 50);
sprintf(dest,"%s","我是马保国");
printf("%s\n", dest);
return 0;
}
Makefile文件:
# Makefile
all: blog.o
gcc $^ -o app
%.o:%.c
gcc -c $< -o $@
结果:
编译c程序的make隐含规则是: xxx.o自动由xxx.c生成。
9、函数
- 文本处理函数
subst函数:替换字符串
#语法格式:
$(subst FROM,TO,TEXT)
用法:
函数名称:字符串替换函数— subst。
函数功能:把字串“ TEXT”中的“ FROM”字符替换为“ TO”。
返回值:替换后的新字符串。
示例:
$(subst ee,EE,feet on the street)
效果:替换“ feet on the street”中的“ ee”为“ EE”,结果得到字符串“ fEEt on the strEEt”
结果:
patsubst函数:模式字符串替换
示例:
函数功能:把字符串 "a.c b.c"中以.c结尾的单词替换成以.o结尾的字符,函数的返回值是"a.o b.o"
var=$(patsubst %.c, %.o, a.c b.c)
all:
@echo "$(var)"
结果:
strip函数:去空格函数
语法格式:
$(strip STRINT)
函数功能:去掉字串开头和结尾的空字符,并将其中多个连续空字符合并为一个空字符。
函数说明:空字符包括空格、 [Tab]等不可显示字符。
示例:
str= a b c
ret = $(strip $(str))
all:
@echo $(ret)
结果:
findstring函数:查找字符串函数
语法格式:
$(findstring FIND,IN)
函数功能:搜索字串“ IN”,查找“ FIND”字串。
返回值:如果在“ IN”之中存在“ FIND”,则返回“ FIND”,否则返回空。
函数说明:字串“ IN”之中可以包含空格、 [Tab]。搜索需要是严格的文本匹配。
var1=$(findstring aa,aabbcc)
var2=$(findstring dd,aabbcc)
all:
@echo $(var1)
@echo $(var2)
结果:
filter函数:过滤函数
语法格式:
$(filter PATTERN…,TEXT)
示例:
sources := foo.c bar.c baz.s ugh.h
foo: $(sources)
cc $(filter %.c %.s,$(sources)) -o foo
使用“ $(filter %.c %.s,$(sources))”的返回值给 cc 来编译生成目标“ foo”,函数返回
值为“ foo.c bar.c baz.s”。
- 文件名处理函数
wildcard函数:获取匹配模式文件名函数
语法格式:
$(wildcard PATTERN) # wildcard 通配符
函数功能:列出当前目录下所有符合模式“ PATTERN”格式的文件名。
返回值:空格分割的、存在当前目录下的所有符合模式“ PATTERN”的文件名。
函数说明:“ PATTERN”使用shell可识别的通配符,包括“ ?”(单字符)、“ *”(多字符)等。
示例:
当前目录下的所有文件:
var=$(wildcard *.c)
all:
@echo $(var)
结果:
filter函数:过滤模式匹配的文件
$(filter PATTERN…,TEXT)
函数功能:过滤掉字串“ TEXT”中所有不符合模式“ PATTERN”的单词,保留所有符合此模式的单词。
可以使用多个模式。模式中一般需要包含模式字符“ %”。存在多个模式时,模式表达式之间使用空格分割。
返回值:空格分割的“ TEXT”字串中所有符合模式“ PATTERN”的字串。
函数说明:“ filter”函数可以用来去除一个变量中的某些字符串,我们下边的例子中就是用到了此函数。
示例:
var=$(filter %.c %.s, 1.d 2.b a.c b.c c.s d.s)
all:
@echo $(var)
结果:
dir函数:获取目录名称,取目录函数
语法格式:
$(dir NAMES…)
函数功能:从文件名序列“ NAMES…”中取出各个文件名的目录部分。
文件名的目录部分就是包含在文件名中的最后一个斜线(“ /”)(包括斜线)之前的部分。
返回值:空格分割的文件名序列“ NAMES…”中每一个文件的目录部分。
函数说明:如果文件名中没有斜线,认为此文件为当前目录(“ ./”)下的文件。
示例:
var=$(dir src/foo.c hacks)
all:
@echo $(var)
结果:
nodir函数:去除文件的目录名称,保留文件的函数
语法格式:
$(notdir NAMES…)
函数名称:取文件名函数—— notdir。
函数功能:从文件名序列“ NAMES…”中取出非目录部分。
目录部分是指最后一个斜线(“ /”)(包括斜线)之前的部分。
删除所有文件名中的目录部分,只保留非目录部分。
返回值:文件名序列“ NAMES…”中每一个文件的非目录部分。
函数说明:如果“ NAMES…”中存在不包含斜线的文件名,则不改变这个文件名。
以反斜线结尾的文件名,是用空串代替,因此当“ NAMES…”中存在多个这样的文件名时,
返回结果中分割各个文件名的空格数目将不确定!这是此函数的一个缺陷。
示例:
var=$(notdir src/foo.c hacks)
all:
@echo $(var)
结果:
addprefix函数:给名字列表添加前缀(一般是加目录名)
$(addprefix PREFIX,NAMES…)
函数名称:加前缀函数— addprefix。
函数功能:为“ NAMES…”中的每一个文件名添加前缀“ PREFIX”。参数“ NAMES…”
是空格分割的文件名序列,将“ SUFFIX”添加到此序列的每一个文件名
之前。
返回值:以单空格分割的添加了前缀“ PREFIX”的文件名序列
示例:
var=$(addprefix src/,foo bar)
all:
@echo $(var)
结果:
addsufix函数:给名字列表添加h后缀
语法格式:
$(addsuffix SUFFIX,NAMES…)
函数名称:加后缀函数— addsuffix。
函数功能:为“ NAMES…”中的每一个文件名添加后缀“ SUFFIX”。参数“ NAMES…”
为空格分割的文件名序列,将“ SUFFIX”追加到此序列的每一个文件名的末尾。
返回值:以单空格分割的添加了后缀“ SUFFIX”的文件名序列。
示例:
var=$(addsuffix .c,foo bar)
all:
@echo $(var)
结果:
- foreach函数:循环替换字符串
语法格式:
$(foreach VAR,LIST,TEXT)
函数功能: 这个函数的工作过程是这样的:如果需要(存在变量或者函数的引用),
首先展开变量“ VAR”和“ LIST”的引用;而表达式“ TEXT”中的变量引用不展开。
执行时把“ LIST”中使用空格分割的单词依次取出赋值给变量“ VAR”,然后执行“ TEXT”表达式。
重复直到“ LIST”的最后一个单词(为空时结束)。“ TEXT”中的变量或者函数引用在执行时才被展开,
因此如果在“ TEXT”中存在对“ VAR”的引用,那么“ VAR”的值在每一次展开式将会到的不同的值。
返回值: 空格分割的多次表达式“ TEXT”的计算的结果。
示例:
当前的目录结构:
dirs = a b c
files = $(foreach dir, $(dirs), $(wildcard $(dir)/*))
all:
@echo $(files)
结果:
if函数:if关键字不仅可以当分支判断还可以当函数使用
函数语法:
$(if CONDITION,THEN-PART[,ELSE-PART])
函数功能:第一个参数“ CONDITION”,在函数执行时忽略其前导和结尾空字符,
如果包含对其他变量或者函数的引用则进行展开。
如果“ CONDITION”的展开结果非空,则条件为真,就将第二个参数“ THEN_PATR”作为函数的计算表达式;
“CONDITION”的展开结果为空,将第三个参数“ ELSE-PART”作为函数的表达式,
函数的返回结果为有效表达式的计算结果。
返回值: 根据条件决定函数的返回值是第一个或者第二个参数表达式的计算结果。
当不存在第三个参数“ ELSE-PART”,并且“ CONDITION”展开为空,函数返回空。
函数说明: 函数的条件表达式“ CONDITION”决定了函数的返回值只能是“ THEN-PART”或者
“ ELSE-PART”两个之一的计算结果。
示例:
SRC_DIR =
REAL_SRC = $(if $(SRC_DIR), $(SRC_DIR), /home/zsd)
all:
@echo $(REAL_SRC)
结果:
SRC_DIR = /root
REAL_SRC = $(if $(SRC_DIR), $(SRC_DIR), /home/zsd)
all:
@echo $(REAL_SRC)
结果:
origin函数:
获取 参数 (VARIABLE) 相关的信息,告诉我们这个变量的出处(定义方式)。
$(origin VARIABLE)
函数功能: 函数“ origin”查询参数“ VARIABLE”(一个变量名)的出处。
函数说明:“ VARIABLE”是一个变量名而不是一个变量的引用。
因此通常它不包含“ $”(当然,计算的变量名例外)。
返回值: 返回“ VARIABLE”的定义方式。用字符串表示。
origin有多种返回值:
函数的返回情况有以下几种:
1. undefined
变量“ VARIABLE”没有被定义。
2. default
变量“ VARIABLE”是一个默认定义(内嵌变量)。如“ CC”、“ MAKE”、“ RM”等变量。
如果在Makefile中重新定义这些变量,函数返回值将相应发生变化。
3. environment
变量“ VARIABLE” 是一个系统环境变量, 并且make没有使用命令行选项“ -e”
(Makefile中不存在同名的 变量定义,此变量没有被替代)。参考 10.7 make的命令行选项 一节
4. environment override
变量“ VARIABLE”是一个系统环境变量,并且make使用了命令行选项“ -e”。
Makefile中存在一个同名的变量定义,使用“ make -e”时环境变量值替代了
文件中的变量定义。
5. file
变量“ VARIABLE”在某一个 makefile 文件中定义。
6. command line
变量“ VARIABLE”在命令行中定义。
7. override
变量“ VARIABLE”在 makefile 文件中定义并使用“ override”指示符声明。
8. automatic
变量“ VARIABLE”是自动化变量。
示例:看看以下的变量来自什么地方,实测一下哈
var=$(origin hello)
all:
@echo $(var)
var=$(origin MAKE)
all:
@echo $(var)
var=$(origin PATH)
all:
@echo $(var)
file=jj
var=$(origin file)
all:
@echo $(var)
var=$(origin file)
all:
@echo $(var)
shell函数:
语法格式:
$(shell command)
函数功能: 函数“ shell”所实现的功能和shell中的引用( ``)相同。实现对命令的扩展。
这就意味着需要一个shell 命令作为此函数的参数,函数的返回结果是此命令在shell中的执行结果。
返回值: 函数“ shell”的参数(一个 shell 命令)在 shell 环境中的执行结果。
函数说明: 函数本身的返回值是其参数的执行结果,没有进行任何处理。对结果的处理是由 make 进行的。
示例:
ret = $(shell pwd)
all:
@echo $(ret)
结果: