Makefile 作为编译c/c++ 的脚本语言,需要了解一下他的规则。
- 语法规则
- @ $^ 等是什么意思
@
-
代表什么意义- 部分api,eg:subpath【替换字符串】 addfix【添加前缀】
- ?= := 等
- .phony 的意义
- 执行make的流程
以下源码,放到我的github上面,有需要的可以上面去查看
语法规则
语法:
目标: 依赖项
<tab键> 执行项
例子:
say_hello:
@echo "Hello World"
generate:say_hello
@echo "Creating empty text files..."
touch file-{1..10}.txt
clean:
@echo "Cleaning up..."
rm *.txt
执行流程
默认执行第一个目标
可以通过 .DEFAULT_GOAL := generate
来进行修改
或者 all: say_hello generate
来修改
变量
# 声明变量
a = 1
b := 1
# 使用变量
echo ${a}
echo $(a)
逻辑语句
conditional-directive-one
text-if-one-is-true
else conditional-directive-two
text-if-two-is-true
else
text-if-one-and-two-are-false
endif
# conditional-directive 为下面四种方法的任意一种
ifeq 'arg1' 'arg2' # 这两种写法都是可以的 带括号和不带括号
ifneq (arg1, arg2)
ifdef variable-name # 判断某个值是否有值
ifndef variable-name
如果要在目标中写条件语句,则使用shell语法的条件判断。唯一不同,则是每一行都需要写分号,查看这里
eg:
# 不在目标项中
ifeq ("x${x}", "x")
@echo "judge success"
endif
t2:
# 注意都每个执行命令都需要 ";"
if [ x = x"${xx}" ] ; then \
@echo "same"; \
else \
@echo "different"; \
fi
$<
$@
$^
等是什么意思
$@:目标的名字
$^:依赖项的所有名字
$<:依赖项的第一个名字
$?:构造所需文件列表中更新过的文件
%: %.o
@echo "Checking.."
${CC} ${LINKERFLAG} $< -o $@
% 表示%
can match any target name
假定有一个目标是:foo,则上例被翻译成
foo: foo.o
@echo "Checking.."
gcc -lm foo.o -o foo
@
-
代表什么意义
@
表示不会打印出即将执行的命令
-
表示即使该执行语句出错,也可以继续运行
t1:
@echo hello # 不会打印该语句,只会打印结果
-mkdir test # 如果创建不了,则会报错
t2:
echo hello # 不仅会打印该语句,还会打印结果
mkdir test # 如果创建不了,则会报错,并停止运行
=
:=
区别
=
表明定义的变量使用的时候才展开
:=
表明立即展开,不用等到使用的时候再展开
eg:
FOO = $(BAR) # 延迟赋值,使用到的时候,会去判断BAR的值在哪里,如果找到则赋值
BAR = bar
CC = gcc
CC = ${CC} # 这个地方会导致死循环,堆栈溢出
all:
@echo ${CC}
和
FOO := $(BAR) # 立即赋值,此时为空
BAR = bar
CC := gcc
CC := ${CC}
all:
@echo ${CC}
.phony
的意义
.PHONY
, 伪目标项,不论是否有同名的文件
如果你没有加伪目标项,那么如果有和目标项同名的文件,则不会执行该目标项,会报: make: 'xxx' is up to date.
如果增加 .PHONY
则一定会执行Makefile 的目标项
常用函数,部分api
${function arguments} # or $(function arguments)
$(subst 要被替换的字符串,用来替换的字符串,被处理的字符串)
$(subst from**,to,text)**
$(patsubst pattern**,replacement,var)** 可以通过模式匹配进行替换
$(var:pattern=replacement) 和上面是一个意思
$(wildcard 寻找的文件):
$(wildcard pattern**)** 按照模式匹配进行查找
$(abspath names**…)** 绝对路径
$(addprefix prefix**,names…) **表示添加前缀
$(addsuffix suffix**,names…)** 表示添加后缀
$(foreach var,list,text **) ** 遍历
dirs := a b c d files := $(foreach dir,$(dirs),$(wildcard $(dir)/*))
# 表示将$(LOCAL_SRC_FILES) 中的.cpp 替换成 .o 并且增加前缀 $(OUT_OBJ_DIR)/
LOCAL_OBJ_FILES = $( addprefix $(OUT_OBJ_DIR)/,$(LOCAL_SRC_FILES) )
LOCAL_DEP_FILES = $( patsubst %.o,%.o.d,$(LOCAL_OBJ_FILES) )
经验:
如果执行的语句有先后关系,则可以使用 ;
进行递进,如果不是同一行 ,则需要使用 \
进行连接
t1:
cd t1; \
-mkdir t2 # 表示进入到t1 文件夹再创建t2 文件夹
FAQ
**() **的区别
这个问题可以查看 这里 ,大意是,在make中没有区别,只在makefile传递给make的时候有区别,?() 表示会在shell中先执行() 里面的东西,然后我们可以使用返回值
你可以新建一个Makefile ,里面的target长的像下面这个样子:然后你就会发现不同
all: @echo ${pwd} @echo $${pwd} @echo $(pwd) @echo ?(pwd) # 只有这个会执行 @echo $(shell pwd) # 和上面一致,是使用shell的命令
参考
嘿关注一波微信公众号呗
今天的文章一文了解MakeFile分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/19397.html