Make学习

Make基础知识

Make的内容组成

一个Makefile文件通常由五种类型的内容组成:显式规则、隐式规则、变量定义、指令和注释

显式规则(explicit rules):显式指明何时以及如何生成或更新目标文件,显式规则包括目标、依赖和更新方法三个部分,型如:

target … (目标): prerequisites …(依赖)
        recipe(方法)
        …
        …

也可以有如下形式:

target … (目标): prerequisites …(依赖); recipe(方法) ;…

隐式规则(implicit rules):根据文件自动推导如何从依赖生成或更新目标文件。

变量定义(variable definitions):定议变量并指定值,值都是字符串,类似C语言中的宏定义(#define),在使用时将值展开到引用位置

指令(directives):在make读取Makefile的过程中做一些特别的操作,包括:

1、读取(包含)另一个makefile文件(类似C语言中的#include)

2、确定是否使用或略过makefile文件中的一部分内容(类似C语言中的#if)

3、定义多行变量

注释(comments):一行当中 # 后面的内容都是注释,不会被make执行。make当中只有单行注释。如果需要用到#而不是注释,用#。

目标和伪目标

Makefile中会有很多目标,但最终目标只有一个,其他所有内容都是为这个最终目标服务的,写Makefile的时候先写出最终目标,再依次解决总目标的依赖

一般情况第一条规则中的目标会被确立为最终目标,第一条规则默认会被make执行

通常来说目标是一个文件,一条规则的目的就是生成或更新目标文件。

make会根据目标文件和依赖文件最后修改时间判断是否需要执行更新目标文件的方法。如果目标文件不存在或者目标文件最后修改时间早于其中一个依赖文件最后修改时间,则重新执行更新目标文件的方法。否则不会执行。

除了最终目标对应的更新方法默认会执行外,如果Makefile中一个目标不是其他目标的依赖,那么这个目标对应的规则不会自动执行。需要手动指定,方法为

make <target>  # 如 make clean , make hello.o

可以使用.DEFAULT_GOAL来修改默认最终目标

.DEFAULT_GOAL = main

all: 
    @echo all

main:
    @echo main

如果一个标并不是一个文件,则这个目标就是伪目标。例如前面的clean目标。如果说在当前目录下有一个文件名称和这个目标名称冲突了,则这个目标就没法执行。这时候需要用到一个特殊的目标 .PHONY,将上面的clean目标改写如下

.PHONY: clean
clean:
    rm block.o command.o input.o main.o scene.o test.o
    rm sudoku.exe

这样即使当前目录下存在与目标同名的文件,该目标也能正常执行。

如果一条规则的依赖文件没有改动,则不会执行对应的更新方法。如果需要每次不论有没有改动都执行某一目标的更新方法,可以把对应的目标添加到.PHONY的依赖中,例如下面这种方式,则每次执行make都会更新test.o,不管其依赖文件有没有改动

test.o: test.cpp test.h
        g++ -c test.cpp

.PHONY: clean test.o

指定依赖搜索路径

make默认在Makefile文件所在的目录下查找依赖文件,如果找不到就会报错,这时就需要用VPATH和vpath指定搜索路径

VPATH用法如下:

VPATH = <dir1>:<dir2>:<dir3>...

 例如
VPATH = include:src

多个目录之间冒号隔开,这时make会在VPATH指定的这些目录里面查找依赖文件。

ath比VPATH使用更灵活,可以指定某个类型的文件在哪个目录搜索。

用法如下:

vpath <pattern> <directories>

vpath %.h include  # .h文件在include目录下查找
vpath %.h include:headers  # .h文件在include或headers文件下查找

vpath % src   # 所有文件都在src下查找

vpath hello.cpp src  # hello.cpp文件在src查找

更新方法

更新方法实际上是一些Shell指令,通常以Tab开头,或直接放在目标-依赖列表后面,用分号隔开。这些指令都需要交给Shell执行,所以需要符合Shell语法。默认使用的Shell是sh。默认的执行方式为一条指令重新调用一个Shell进程来执行。有时为了提高性能或其他原因,想让这个目标的所有指令都在同一进程中执行,可以在Makefile中添加 .ONESHELL

 .ONESHELL:

通常make在执行一条Shell语句前都会先打印这条语句,如果不想打印可以在语句开头在@

@echo hello
@g++ -o hello hello.cpp

也可以使用.SILENT来指定哪些目标的更新方法指令不用打印

.SILENT: main all

如果一条规则当中包含多条Shell指令,每条指令执行完之后make都会检查返回状态,如果返回状态是0,则执行成功,继续执行下一条指令,直到最后一条指令执行完成之后,一条规则也就结束了。
如果过程中发生了错误,即某一条指令的返回值不是0,那么make就会终止执行当前规则中剩下的Shell指令。
例如

clean:
    rm main.o hello.o
    rm main.exe

这时如果第一条rm main.o hello.o出错,第二条rm main.exe就不会执行。类似情况下,希望make忽视错误继续下一条指令。在指令开头-可以达到这种效果。

clean:
    -rm main.o hello.o
    -rm main.exe

变量

Makefile中的变量有点类似C语言中的宏定义,即用一个名称表示一串文本。但与C语言宏定义不同的是,Makefile的变量值是可以改变的。变量定义之后可以在目标、依赖、方法等Makefile文件的任意地方进行引用。Makefile中的变量值只有一种类型: 字符串

定义方式

 <变量名> = <变量值>  <变量名> := <变量值>  <变量名> ::= <变量值>
files = main.cpp hello.cpp
objects := main.o hello.o
var3 ::= main.o

变量名区分大小写,可以是任意字符串,不能含有":", “#”, “=”

使用方式

#$(<变量名>) 或者 ${<变量名>}
main.o : $(files)  或者 ${files}
    ...

如果变量名只有一个字符,使用时可以不用括号,如a,
b, 但不建议这样用,不管是否只有一个字符都写成(a),
(b)这种形式

变量赋值

递归展开赋值(延迟展开)
变量和函数的展开如果发生在第一阶段,就称作立即展开,否则称为延迟展开。立即展开的变量或函数在第一个阶段,也就是Makefile被读取解析的时候就进行展开。延迟展开的变量或函数将会到用到的时候才会进行展开。
第一种方式就是直接使用=,这种方式如果赋值的时候右边是其他变量引用或者函数调用之类的,将不会做处理,直接保留原样,在使用到该变量的时候再来进行处理得到变量值(Makefile执行的第二个阶段再进行变量展开得到变量值)

bar2 = ThisIsBar2No.1
foo = $(bar)
foo2 = $(bar2)

all:
    @echo $(foo)  # Huh?
    @echo $(foo2)  # ThisIsBar2No.2
    @echo $(ugh)   # Huh?

bar = $(ugh)
ugh = Huh?
bar2 = ThisIsBar2No.2

简单赋值(立即展开)
简单赋值使用:=或::=,这种方式如果等号右边是其他变量或者引用的话,将会在赋值的时候就进行处理得到变量值。(Makefile执行第一阶段进行变量展开)

bar2 := ThisIsBar2No.1
foo := $(bar)
foo2 := $(bar2)

all:
    @echo $(foo)    # 空串,没有内容
    @echo $(foo2)    # ThisIsBar2No.1
    @echo $(ugh)    # 

bar := $(ugh)
ugh := Huh?
bar2 := ThisIsBar2No.2

条件赋值
条件赋值使用?=,如果变量已经定义过了(即已经有值了),那么就保持原来的值,如果变量还没赋值过,就把右边的值赋给变量。

var1 = 100
var1 ?= 200

all:
    @echo $(var1) # 100 注释var1 = 100之后为200
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值