Makefile入门

make是一个自动化构建工具,广泛应用于Unix及其类Unix系统中。make最先应用于编译C语言项目,不仅如此,只要某个文件发生变化就需要重新构建的项目都可以使用make工具进行构建。

Makefile是可以被make解析的特定格式的文本文件。其语法简单,当我们构建一个程序时,其工作原理大致为:make首先解析Makefile,查找构建应用的一系列依赖,并检查每个依赖文件是否过期(是否发生变化),如果发生过期,即重新构建变化的依赖文件。

语法规则

语法规则很简单,Makefile文件是由一系列规则(rule)组成,每个规则语法如下:

<target> : <prerequisites> 
[tab]  <commands>

对每个规则,target是必须的,prerequisites和commands是可选的,commands前面必须是一个tab。Makefile文件中至少有一个规则。

shell> cat Makefile
tutorial:
  echo "this is Makefile tutorial"

我们可以通过make来执行上面规则:

shell> make tutorial
echo "this is Makefile tutorial"
this is Makefile tutorial

默认情况下,如果我们没有指定目标(target),make命令会执行第一条规则。上面例子中,target为tutorial,前置条件(prerequisites)为空,命令(commands)为echo "this is Makefile tutorial"。我们发现上面例子中除了输出结果,还把命令也输出,这叫回显,可以在命令前加上@关闭回显,如:@echo "this is Makefile tutorial"

目标

一个目标即构成一条规则,目标通常是文件名,指明make命令要构建的对象。目标可以是一个文件名,也可以是多个文件名,中间用空格分隔。如:

a.o b.o: a.h a.cpp a.h b.cpp
  g++ -c a.cpp b.cpp

除了文件名,目标还可以是某个操作的名字,如上面例子中的tutorial

前置条件

前置条件通常是一组文件名,之间用空格分隔。它指定了"目标"是否重新构建的判断标准:只要有一个前置文件不存在,或者有过更新(前置文件的last-modification时间戳比目标的时间戳新),"目标"就需要重新构建。下面规则是创建一个source.txt文件:

shell> cat Makefile
source.txt:
  echo "this is source file" >> source.txt

result.txt: source.txt
  cp source.txt result.txt

第一次执行make result.txt,会创建source.txt,并将source.txt中的内容拷贝到result.txt中,当我们再次执行make result.txt时,终端会输出:

make: `result.txt' is up to date.

这是由于source.txt已经创建,且没有变化,所以不会执行任何操作。如果我们修改一下source.txt,如:

touch source.txt

再执行make source.txt 试试看。

命令

命令(commands)表示如何更新目标文件,由一行或多行的shell命令组成。它是构建"目标"的具体指令,它的运行结果通常就是生成目标文件。

需要注意的是:

  • 每个命令前需要有一个tab;
  • 每行命令在一个单独的shell中执行。这些shell之间没有继承关系。

如:

var-lost:
    export foo=bar
    echo "foo=[$$foo]"

上面代码执行后make var-lost,取不到foo的值。因为两行命令在两个不同的进程执行。一个解决办法是将两行命令写在一行,中间用分号分隔。

var-kept:
    export foo=bar; echo "foo=[$$foo]"

或在换行符前加反斜杠转义。

var-kept:
    export foo=bar; \
    echo "foo=[$$foo]"

变量与注释

变量和注释不是必须的,但当Makefile文件比较大时,变量和注释将会非常有用,毕竟代码首先是给人读的。

自定义变量

Makefile中的变量没有类型,全是字符型,定义一个变量也比较简单,如下:

CFLAGS = -g -Wall
CC = g++
RM = /bin/rm -f

当定义好变量后,如果使用变量中存储的值呢?获取变量的值跟shell类似:

${varname}

注释

注释只需要在前面加上#即可,如:

#this is a comment

内置变量

除了自定义的变量外,make命令提供一系列内置变量,比如,$(CC) 指向当前使用的编译器,$(MAKE) 指向当前使用的make工具。这主要是为了跨平台的兼容性,详细的内置变量清单见手册

自动变量

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

  • $@

指代当前目标,即make构建时指定的目标,如make main$@为main。

main: main.o
    ${CC} ${CFLAGS} -o $@ $^
  • $<

指代第一个前置条件,如规则rule: p1 p2中的$<为p1。

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

指代所有前置条件,中间是空格隔开。如规则rule: p1 p2中的$^为p1 p2。

main.o: main.cpp
    ${CC} ${CFLAGS} -c $^
  • $?

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

  • $*

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

更多自动变更参考Automatic-Variables.

实例

我们以构建一个c++的hello world程序为例:

shell> cat main.cpp
#include <iostream>

using namespace std;

int main() {
    std::cout << "hello world" << std::endl;
}

Makefile内容如下:

shell> cat Makefile
CFLAGS = -g -Wall
CC = g++
RM = /bin/rm -f

all: main

main: main.o
    ${CC} ${CFLAGS} -o $@ $^

main.o: main.cpp
    ${CC} ${CFLAGS} -c $^

clean:
    ${RM} *.o main

接下来我们就可以利用make进行构建了:

shell> make

没有指定规则时,默认执行第一条规则,在这个例子中为all
当需要清除产生的中间文件和可执行文件执行:

shell> make clean

进一步学习

  • 在实际项目中,项目文件成千上万个,而且分布在不同目录下,如果编写规则进行构建呢?
  • 当我们有很多依赖时,是不是需要我们逐个手写这些规则呢?
  • make只能编译c/c++吗?

有了以上一些基础知识,就可以继续学习更多高级用法了。你会发现make会让你的构建过程更高效、自动化。

参考

  1. https://www.wooster.edu/_media/files/academics/areas/computer-science/resources/makefile-tut.pdf

2.http://www.gnu.org/software/make/manual/make.html#Makefile-Contents

3.https://thoughtbot.com/blog/the-magic-behind-configure-make-make-install#what-does-all-of-this-do

4.https://gist.github.com/isaacs/62a2d1825d04437c6f08

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容