makefile脚本基本语法

l Makefile脚本流程

Shell脚本——make命令和Makefile

make命令是一个常用的编译命令,尤其在C/C++开发中,make命令通过makefile文件中描述源程序之间的依赖关系进行自动编译;makefile文件是按照规定格式编写,需说明如何编译各个源文件并连接生成可执行文件,并要求定义源文件之间的依赖关系;首次执行make命令时,编译所有相关文件,之后再执行make命令时,以增量方式进行编译,即只对修改的源文件相关的目标文件进行编译;

注:许多tarball格式的开源软件,解压后先执行./configure,再执行make,然后执行make install进行安装;

makefile文件支持include,即把一些基本依赖规则写在一个公共文件中,其他makefile文件包含此文件;

通常公共makefile文件命名为common.mk;

一、make命令

make命令后接参数,称为目标;

1 常见目标

make all:编译所有目标

make install:安装已编译的程序

make uninstall:卸载已安装的程序

make clean:删除由make命令产生的文件,通常删除目标文件.o

make distclean:删除由./configure产生的文件

make check:测试刚编译的软件

make installcheck:检查安装的库和程序

make dist:重新打包成packname-version.tar.gz

执行make命令时,需要一个Makefile文件,以告诉make命令如何编译和链接程序;

2 参数

-B:重新建立所有目标

-d:打印调试信息

-C:切换到指定路径下寻找Makefile

-f:将指定文件看做Makefile

-j:同时运行命令的个数,即多线程执行Makefile,后接的个数可由nproc命令返回值来指定

注:nproc命令打印当前进程可用的处理数(线程数);

二、程序的编译和链接

一般在C/C++开发中,首先将源文件编译成目标文件(Windows下.obj文件,Unix下.o文件)——编译compile,再将目标文件合成执行文件——链接link;

三、make命令如何工作?

1 make在当前目录下寻找“Makefile”或“makefile”文件

2 若找到,查找文件中的第一个目标文件.o

3 若目标文件不存在,根据依赖关系查找.s文件

4 若.s文件不存在,根据依赖关系查找.i文件

5 若.i文件不存在,根据依赖关系查找.c文件,此时.c文件一定存在,于是生成一个.o文件,再去执行

四、Makefile文件格式

1 概述

Makefile文件由一系列规则rules构成,每条规则形式如下:

:

[Tab]

第一行冒号前为目标,冒号后为前置条件;第二行必须由一个Tab键起首,后接命令;目标是必须的,不可省略;前置条件和命令是可选的,但两者必须至少存在一个;每条规则明确两件事——构建目标的前置条件是什么?如何构建?

2 目标target

目标可以是文件名,指明make命令所要构建的对象;也可以是某个操作名称,称“伪目标”;

clean:

       rm *.o

以上代码目标是clean,命令是rm *.o;执行make clean命令,实现对象文件的删除;为避免设置的伪目标名称在当前路径下有相同名称的文件,make命令发现该名称的文件已存在,便不再构建,也就不执行rm操作的情况发生,先将该名称声明为伪目标,因此make命令不会检查是否存在该名称的文件,每次执行对应的操作;

.PHONY:clean

clean:

       rm *.o

若make命令没有指定目标,默认执行Makefile文件中第一个目标;

3 前置条件prerequisites

前置条件通常是一组文件名,用空格隔开;指定目标是否重新构建的判断标准——只要有一个前置条件不存在或有更新,则该目标需重新构建;

result.txt:source.txt

cp source.txt result.txt

若当前路径下source.txt存在,make result.txt可正常执行,否则需再写一条规则,用于生成source.txt;

source.txt:

       echo "This is a source file." > source.txt

source.txt没有前置条件,与其他文件文官,只要该文件不存在,每次执行make source.txt命令都会生成该文件;

若要生成多个文件,写法如下:

source:file1 file2 file3

source是伪目标,只有3个前置条件,没有对应命令;执行make source命令后一次性生成file1 file2 file3文件,比如下写法方便:

make file1

make file2

make file3

4 命令commands

命令表示如何更新目标文件,由一行或多行shell命令组成;

注:

shell命令一定是写在命令中,否则会被make忽略;每行命令前必须有一个Tab键;每行命令在一个独立的shell中执行,shell之间没有继承关系,因此上一行为的变量赋值,在下一行无效;若前后两条命令有共享数据,可写在一行,用分号隔开;

var-kept:

       export foo=bar;echo "foo=[$$foo]"或,在换行符前加反斜杠\进行转义;

var-kept:

       export foo=bar;\

       echo "foo=[$$foo]"或,加上.ONSHELL命令;

.ONESHELL:

var-kept:

       export foo=bar;

       echo "foo=[$$foo]"

五、Makefile文件语法

1 注释

每行以#开头的为注释;

2 回声echoing

正常情况下,make打印每条命令,再执行该命令,称回声;在命令前加@,关闭回声,即只输出命令的执行结果,出错则停止执行;

注:

前缀-表示命令执行有错,忽略错误,继续执行;不加前缀输出执行的命令和命令执行的结果,出错则停止执行;

3 通配符

通配符指定一组符合条件的文件;Makefile通配符与bash一致;

*:任意0个或多个字符

 

?:任意一个字符

[...]:方括号内任意一个字符

4 模式匹配

make命令允许对文件名进行类似正则运算的匹配,主要用到%;

5 变量和赋值符

自定义变量,使用=赋值;调用变量,将变量名放在$()中;

Makefile提供四种赋值运算符——=、:=、?=、+=;

(1)=

递归展开赋值,默认赋值方式;

var2=$(var1)

var1="TEST"

all:

       echo $(var2)

输出:TEST

(2):=

直接赋值,不会递归展开,若引用的变量不存在,则为空串;

var2:=$(var1)

var1="TEST"

all:

       echo $(var2)

输出:(空串)

(3)?=

若未初始化,则赋值;

var1="test"

var1?="TEST"

var2?="TEST"

all:

       echo $(var1) and $(var2)

输出:test and TEST

(4)+=

将值追加到现有内容末尾;

var1="TEST"

var1+="test"

all:

       echo var1

输出:TESTtest

六、内置变量

make命令提供一系列内置变量,如$(CC)指向当前使用的编译器,$(MAKE)指向当前使用的make工具;

RM:rm -f

AR:ar

CC:cc

CXX:g++

七、自动变量

自动变量的值与当前规则有关;

1 $@

表示当前目标;

2 $<

表示第一个前置条件;

3 $?

表示所有比目标更新的前置条件;

4 $^

表示所有前置条件;

5 $(@D)和$(@F)

$(@D)表示$@的目标名,$(@F)表示$@的文件名;

八、判断

Makefile文件使用bash语法,完成判断;

<条件语句>

<条件为真,执行程序段>

else

<条件为假,执行程序段>

endif

1 条件语句

(1)ifeq 比较两个参数值是否相等

ifeq (arg1, arg2)

ifeq 'arg1' 'arg2'

ifeq "arg1" "arg2"

ifeq 'arg1' "arg2"

ifeq "arg1" 'arg2'

注:参数还可用make函数,如ifeq ($(strip $(foo)),);

(2)ifneq 比较两个参数值是否不等

ifneq (arg1, arg2)

ifneq 'arg1' 'arg2'

ifneq "arg1" "arg2"

ifneq 'arg1' "arg2"

ifneq "arg1" 'arg2'

(3)ifdef 判断变量是否有值

ifdef var

(4)ifndef 判断变量是否无值

ifndef var

举例1:

bar=

foo=$(bar)

ifdef foo

frobozz=yes

else

frobozz=no

endif

#frobozz值为yes

举例2:

foo=

ifdef foo

frobozz=yes

else

frobozz=no

endif

#frobozz值为no

注:以上举例说明ifdef只是测试一个变量是否有值,而非把变量扩展到当前位置!

九、循环

Makefile文件使用bash语法,完成判断;

1 写法一

LIST变量是Makefile变量,引用Makefile变量需使用$()括起来;

而all目标后的命令是shell命令,其中定义的变量也是shell变量,引用shell变量需使用$$作为开头,但shell变量不需括号;

LIST = one two three

all:

       for i in $(LIST); do \

              echo $$i; \

       done

2 写法二

all:

       for i in one two three; do \

              echo $$i; \

       done

十、函数

 

1 函数的调用语法

函数调用,类似变量使用,语法如下:

$(func args) # 推荐!

# 或

${func args}

其中,args参数之间以","隔开,func和args之间以" "隔开;

2 字符串处理函数

(1)$(subst ,,)

字符串替换,将字符串中的转换成,返回替换后的字符串

(2)$(patsubst ,,)

模式字符串替换,查找字符串中符合模式的单词,并替换成

注:可包括通配符%,表示任意长度的字符串;

也包括%,则这里的%是中%代表的字符串;

(3)$(strip )

去空格,去掉中开头和结尾的空白符,返回去掉空格的字符串;

(4)$(findstring ,)

查找字符串,在字符串中查找字符串,若找到则返回,否则返回空字符串;

(5)$(filter ,)

过滤,以模式过滤字符串中的单词,保留符合模式的单词,返回符合模式的字符串;可有多个模式,模式之间以" "隔开;

(6)$(filter-out ,)

反向过滤,以模式过滤字符串中的单词,去掉符合模式的单词,返回不符合模式的字符串;可有多个模式,模式之间以" "隔开;

(7)$(sort )

排序,给字符串中的单词以升序排序,返回排序后的字符串;

(8)$(word ,)

取单词,获取并返回字符串中第个单词(从1开始),若中的单词数大,则返回空字符串;

(9)$(wordlist ,,)

取单词串,获取并返回字符串中第个到第个的单词串;

(10)$(words )

单词个数统计,统计并返回字符串中单词个数;

注:获取字符串中最后一个单词,使用$(word $(words ),)

(11)$(firstword )

首单词,获取并返回字符串中第一个单词;

注:等价于$(word 1,)

3 文件名处理函数

(1)$(dir )

取目录,从文件名序列中获取并返回目录部分;

注:目录部分指最后一个反斜杠之前的部分,若无反斜杠,则返回"./";

(2)$(notdir )

取文件,从文件名序列中获取并返回文件部分;

注:文件部分指最后一个反斜杠之后的部分;

(3)$(suffix )

取后缀,从文件名序列中获取并返回各文件的后缀序列,若无后缀,则返回空字符串;

(4)$(basename )

取前缀,从文件名序列中获取并返回各文件的前缀序列,若无前缀,则返回空字符串;

(5)$(addsuffix ,

加后缀,把加到中每个单词后面并返回;

(6)$(addprefix ,)

加前缀,把加到中每个单词前面并返回;

(7)$(join ,)

连接,将中的单词对应的加到中单词之后;

(8)$(wildcard )

拓展通配符,用于定义变量和引用函数时通配符失效的情况,获取符合模式的字符串并返回;

4 其他函数

(1)$(foreach ,,)

中单词逐一取出放到所指定的变量中,再执行所包含的表达式,每次执行都会返回一个字符串,执行完foreach后返回由多个字符串组成、空格隔开的字符串;

### Makefile 内容

targets := a b c d

objects := $(foreach i,$(targets),$(i).o)

 

all:

    @echo $(targets)

    @echo $(objects)

 

### bash 中执行 make

$ make

a b c d

a.o b.o c.o d.o

(2)$(if ,,)

### Makefile 内容

val := a

objects := $(if $(val),$(val).o,nothing)

no-objects := $(if $(no-val),$(val).o,nothing)

all:

    @echo $(objects)

    @echo $(no-objects)

### bash 中执行 make

$ make

a.o

nothing

(3)$(shell )

执行一个shell命令,将执行结果作为函数返回;

(4)make控制函数

$(error ):产生一个致命错误,Makefile停止执行

$(warning ):输出警告信息,Makefile继续执行

(5)$(call ,,,...)

表达式中的变量,如$(1)、$(2)、...等被参数、...依次取代,的返回值就是call函数的返回值;

### Makefile 内容

log = "====debug====" $(1) "====end===="

all:

    @echo $(call log,"正在 Make")

### bash 中执行 make

$ make

====debug==== 正在 Make ====end====

 


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章