博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Makefile文件语法
阅读量:5876 次
发布时间:2019-06-19

本文共 5247 字,大约阅读时间需要 17 分钟。

概述

本文将介绍Makefile种注释、回显、通配符、变量、循环判断、函数

注释

Makefile中只有单行注释,没有多行注释,注释以 # 开头。以下Makefile注释片段节选自的Makefile

# Makefile for installing Lua# See doc/readme.html for installation and customization instructions.# == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT =======================# Your platform. See PLATS for possible values.PLAT= none

echoing(回显)

通常,make在执行命令行之前会把要执行的命令行进行输出。我们称之为“回显”,就好像我们输入命令执行一样。

@

如果要执行的命令行以字符“@”开始,则make在执行时这个命令就不会被回显。典型的用法是我们在使用“echo”命令输出一些信息时。如:

@echo 开始编译XXX模块......

make执行时,将输出“开始编译XXX模块......”这个信息。如果在命令行之前没有字符“@”,那么,make的输出就是:

echo编译XXX模块......编译XXX模块......

-n”或“--just-print”

如果使用make的命令行参数“-n”或“--just-print”,那么make执行时只显示所要执行的命令,但不会真正的去执行这些命令。只有在这种情况下make才会打印出所有make需要执行的命令,其中也包括了使用“@”字符开始的命令。这个选项对于我们调试Makefile非常有用,使用这个选项我们可以按执行顺序打印出Makefile中所有需要执行的命令。

-s”或“--slient”

make参数“-s”或“--slient”则是禁止所有执行命令的显示,就好像所有的命令行均使用“@”开始一样。

.SILENT

这个关键字的行为很像.PHONY,.PHONY标记的target可以理解成一个无条件执行的动作。被.SILENT标价的target,为完成该target执行的所有command都是没有回显的。

.SILENT:clean.PHONY:cleanclean:    rm -rf *.o

很显然这里面控制回显最灵活的方式就是@,推荐使用“@”来控制命令的回显。

通配符(Wildcard 

概述

Makefile中使用的通配符与Bash下面的filename wildcards一样,但似乎Makefile主要使用‘*’, ‘?’ 和 ‘[…]

~字符也有特殊意义,~ 或者 ~/file name 代表home directory

~       展开为  /home/you         你的家目录~/bin   展开为  /home/you/bin     你的加目录下边的bin目录

~后面不接/则表示别人的家目录

~john       展开为  /home/john         john的家目录~john/bin   展开为  /home/john/bin     john的家目录下边的bin目录

targets 和 prerequisites中的通配符,有make工具负责展开。commands中的通配符则由shell负责展开。除此之外的其他情况,要想展开通配符则需要显式调用wildcard 函数。

由于*默认情况下具有通配符的特殊含义,如果需要按照普通字符理解他,则需要使用 \* 转义。

通配符举例

在commands中使用通配符

此时通配符展开工作由shell负责

clean:        rm -f *.o

在prerequisites 中使用通配符

此时通配符展开由make负责,在target中也可以使用通配符,依然是由amke负责展开。

print: *.c        lpr -p $?        touch print

这个例子除了表明通配符用法外,同时展示了empty target的用法。empty target是phony target的变体,empty target中的target可以存在,也可以不存在。其特色是在commands最后会touch更新target。

在定义变量时使用通配符

objects = *.o

  变量objects的值就是*.o,但是当你把objects的值用于target、prerequisite时,make工具会展开;用于commands时,shell会展开。表面看上去,这似乎没啥问题,看如下代码

objects = *.ofoo : $(objects)        cc -o foo $(CFLAGS) $(objects)

objects的值就是*.o,单独看他就是一个名字古怪的文件。但是用在target、prerequisite、commands时,make或shell会自动将其展开为有意义的具体xxx.o文件名,因此上面代码看上去没有问题。但是如果,当前目录下并没有.o文件,target、prerequisite、commands展开时也找不到.o文件,他就会找*.o这个文件,当然*.o文件也是没有的,于是会报"cannot figure out how to make *.o."错误。

解决这个陷阱的方法是使用wildcard函数

wildcard函数通常和patsubst函数一起使用,这是因为在函数内部通配符也不会自动展开

objects := $(patsubst %.c,%.o,$(wildcard *.c))foo : $(objects)        cc -o foo $(objects)

变量

自定义变量与赋值符

Makefile 允许使用等号自定义变量。

var = Hello Worldtest:    @echo $(var)

上面代码中,变量 var等于 Hello World。调用时,变量需要放在 $( ) 之中。

调用Shell变量,需要在美元符号前,再加一个美元符号,这是因为Make命令会对美元符号转义。

test:    @echo $$HOME

有时,变量的值可能指向另一个变量。

v1 = $(v2)

上面代码中,变量 v1 的值是另一个变量 v2。这时会产生一个问题,v1 的值到底在定义时扩展(静态扩展),还是在运行时扩展(动态扩展)?如果 v2 的值是动态的,这两种扩展方式的结果可能会差异很大。

为了解决类似问题,Makefile一共提供了四个赋值运算符 (=、:=、?=、+=),它们的区别请看。

VARIABLE = value# 在执行时扩展,允许递归扩展。VARIABLE := value# 在定义时扩展。VARIABLE ?= value# 只有在该变量为空时才设置值。VARIABLE += value# 将值追加到变量的尾端。

内置变量(Implicit Variables)

Make命令提供一系列内置变量,(感觉上和gcc/g++的预定义宏差不多)比如,$(CC) 指向当前使用的编译器,$(MAKE) 指向当前使用的Make工具。这主要是为了跨平台的兼容性,详细的内置变量清单见。

output:    $(CC) -o output input.c

自动变量(Automatic Variables)

Make命令还提供一些自动变量,它们的值与当前规则有关。主要有以下几个。

(1)$@

$@指代当前目标,就是Make命令当前构建的那个目标。比如,make foo的 $@ 就指代foo。

a.txt b.txt:     touch $@

等同于下面的写法。

a.txt:    touch a.txtb.txt:    touch b.txt

(2)$<

$< 指代第一个前置条件。比如,规则为 t: p1 p2,那么$< 就指代p1。

a.txt: b.txt c.txt    cp $< $@

等同于下面的写法。

a.txt: b.txt c.txt    cp b.txt a.txt

(3)$?

$? 指代比目标更新的所有前置条件,之间以空格分隔。比如,规则为 t: p1 p2,其中 p2 的时间戳比 t 新,$?就指代p2。

(4)$^

$^ 指代所有前置条件,之间以空格分隔。比如,规则为 t: p1 p2,那么 $^ 就指代 p1 p2 。

(5)$*

$* 指代匹配符 % 匹配的部分, 比如% 匹配 f1.txt 中的f1 ,$* 就表示 f1。

(6)$(@D) 和 $(@F)

$(@D) 和 $(@F) 分别指向 $@ 的目录名和文件名。

比如,$@是 src/input.c,那么$(@D) 的值为 src ,$(@F) 的值为 input.c。

(7)$(<D) 和 $(<F)

$(<D) 和 $(<F) 分别指向 $< 的目录名和文件名。

所有的自动变量清单,请看。下面是自动变量的一个例子。

dest/%.txt: src/%.txt    @[ -d dest ] || mkdir dest    cp $< $@

上面代码将 src 目录下的 txt 文件,拷贝到 dest 目录下。首先判断 dest 目录是否存在,如果不存在就新建,然后,$< 指代前置文件(src/%.txt), $@ 指代目标文件(dest/%.txt)。

判断和循环

循环和判断应用在commands处,而commands的解析则有shell负责。因此Makefile的循环和判断其实也就是shell的循环和判断,其语法与shell完全一样。

ifeq ($(CC),gcc)  libs=$(libs_for_gcc)else  libs=$(normal_libs)endif

上面代码判断当前编译器是否 gcc ,然后指定不同的库文件。

LIST = one two threeall:    for i in $(LIST); do \        echo $$i; \    done# 等同于all:    for i in one two three; do \        echo $i; \    done

上面代码的运行结果。

onetwothree

函数

Makefile 还可以使用函数,格式如下。

$(function arguments)# 或者${
function arguments}

Makefile提供了许多,可供调用。下面是几个常用的内置函数。

(1)shell 函数

shell 函数用来执行 shell 命令

srcfiles := $(shell echo src/{
00..99}.txt)

(2)wildcard 函数

wildcard 函数用来在 Makefile 中,替换 Bash 的通配符。

srcfiles := $(wildcard src/*.txt)

(3)subst 函数

subst 函数用来文本替换,格式如下。

$(subst from,to,text)

下面的例子将字符串"feet on the street"替换成"fEEt on the strEEt"。

$(subst ee,EE,feet on the street)

下面是一个稍微复杂的例子。

comma:= ,empty:=# space变量用两个空变量作为标识符,当中是一个空格space:= $(empty) $(empty)foo:= a b cbar:= $(subst $(space),$(comma),$(foo))# bar is now `a,b,c'.

(4)patsubst函数

patsubst 函数用于模式匹配的替换,格式如下。

$(patsubst pattern,replacement,text)

下面的例子将文件名"x.c.c bar.c",替换成"x.c.o bar.o"。

$(patsubst %.c,%.o,x.c.c bar.c)

(5)替换后缀名

替换后缀名函数的写法是:变量名 + 冒号 + 后缀名替换规则。它实际上patsubst函数的一种简写形式。

min: $(OUTPUT:.js=.min.js)

上面代码的意思是,将变量OUTPUT中的后缀名 .js 全部替换成 .min.js 。

转载于:https://www.cnblogs.com/kelamoyujuzhen/p/10260128.html

你可能感兴趣的文章
MonoRail学习笔记七:页面交互的输入输出方式总结
查看>>
项目利益相关者
查看>>
android window.requestWindowFeature()常用方法
查看>>
【Javascript Demo】移动端访问PC端网页时跳转到对应的移动端网页
查看>>
走在网页游戏开发的路上(四)
查看>>
Linux内核【链表】整理笔记(2) 【转】
查看>>
android152 笔记 4
查看>>
全国各地电信DNS服务器地址
查看>>
jquery 拖动改变div 容器大小
查看>>
解决并清除SQL被注入<script>恶意病毒代码的语句
查看>>
Linux资源控制-CPU和内存
查看>>
对makefile中 $? 的理解
查看>>
HTML5 WebStorage
查看>>
TclError: no display name and no $DISPLAY environment variable
查看>>
Unity的AssetDatabase路径格式
查看>>
jrebel使用
查看>>
JavaScript prototype 属性
查看>>
RedHat系统的Yum安装
查看>>
IntelliJ IDEA CE Maven 使用方法
查看>>
WCF开发的几个频骤
查看>>