一文了解MakeFile

Makefile 做为编译c/c++ 的脚本语言,须要了解一下他的规则。html

  1. 语法规则
  2. <@ $^ 等是什么意思
  3. @ - 表明什么意义
  4. 部分api,eg:subpath【替换字符串】 addfix【添加前缀】
  5. ?= := 等
  6. .phony 的意义
  7. 执行make的流程

如下源码,放到个人github上面,有须要的能够上面去查看c++

语法规则

语法:git

目标: 依赖项
<tab键> 执行项
复制代码

例子:github

say_hello:
        @echo "Hello World"
generate:say_hello
        @echo "Creating empty text files..."
        touch file-{1..10}.txt
clean:
        @echo "Cleaning up..."
        rm *.txt
复制代码

执行流程

默认执行第一个目标shell

能够经过 .DEFAULT_GOAL := generate 来进行修改api

或者 all: say_hello generate 来修改bash

变量

# 声明变量
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
复制代码

$< $@ $^ 等是什么意思

$@:目标的名字ui

$^:依赖项的全部名字

$<:依赖项的第一个名字

$?:构造所需文件列表中更新过的文件

%: %.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的命令
复制代码

参考

make file

makefile 官网

嘿关注一波微信公众号呗

相关文章
相关标签/搜索