Makefile简介

Makefile基础

一、Makefile是什么

(1)目标文件依赖哪些文件?
(2)依赖的文件是否更新?
make 和makefile 并不是用来编译程序的,它只负责找出哪些文件有变化,并且根据依赖关系找出受影响的文件,然后执行事先在makefile 中定义好的命令规则。
因为make 就是在shell 下执行的,所以在makefile 中,位于命令规则里的那些命令,都是shell 命令。

二、Makefile基本语法

目标文件:依赖文件
[Tab键]命令
(1)目标文件是指此规则中想要生成的文件,可以是.o 结尾的目标文件,也可以是可执行文件,也可以是个伪目标,后面会介绍伪目标。
(2)依赖文件是指要生成此规则中的目标文件,需要哪些文件。通常依赖文件不是1 个,所以此处是个依赖文件的列表。
(3)命令是指此规则中要执行的动作,这些动作是指各种shell 命令。命令可以有多个,但一个命令要单独占用一行,在行首必须以Tab 开头。这是make 规定的用法,这样make 在解析到以Tab 开头的行时便知道这是要执行的命令

2.1 make 程序是怎样判断文件有过更新呢?

Linux 中,文件分为属性和数据两部分,每个文件有三种时间,分别用于记录与文件属性和文件数据相关的时间,这三个时间分别是atime、ctime、mtime。

时间 含义
atime access time 访问文件的时间,是读取就会改变,比如cat/less等命令访问文件就会更新atime,但ls查看文件不会更新atime
ctime change time 文件属性或数据修改时,就会被更新
mtime modify time 文件数据部分修改时,会被更新。如果mtime被更新,则ctime肯定也被更新了

make就是判断依赖文件和目标文件的mtime是否一致,如果依赖文件的mtime比目标文件的mtime新,则需要执行命令(命令不一定是编译命令,可以是任何shell命令)。比如如下这个makefile例子:

1:2
        @echo "2 is newer than 1"

然后新建两个文件1和2

# 首先touch 两个文件1和2,可以看到起mtime是一致的
[root@localhost test]# touch 1 2
[root@localhost test]# stat -c %y 1 2           #mtime一致
2021-03-31 23:11:32.926225333 -0400
2021-03-31 23:11:32.926225333 -0400
[root@localhost test]# make
make: '1' is up to date.                        #make命令并没有做什么
[root@localhost test]# vi 2                     #修改文件2的内容
[root@localhost test]# stat -c %y 1 2           #2的mtime要比1新了
2021-03-31 23:11:32.926225333 -0400
2021-03-31 23:11:56.588623644 -0400
[root@localhost test]# make                     #make执行了echo命令
2 is newer than 1

如果目标文件1的mtime新于依赖文件2会什么结果?

[root@localhost test]# vi 1                     #修改目标文件1的内容
[root@localhost test]# stat -c %y 1 2           #目标文件1的mtime新于依赖文件2
2021-03-31 23:13:56.341639459 -0400
2021-03-31 23:11:56.588623644 -0400
[root@localhost test]# make
make: '1' is up to date.

2.2 跳到目标处执行

如下makefile例子,当执行make时,执行完第一个目标后就退出了。

[root@localhost test]# cat Makefile
t1:1
        @echo "make t1"

t2:1
        @echo "make t2"

[root@localhost test]# make                 #执行完第一个目标就退出了
make t1

[root@localhost test]# make t2              #指定目标t2
make t2

[root@localhost test]# make t1              #指定目标t1
make t1

2.3 伪目标

通过上面的例子您看到了,规则中的命令并不总是被执行,有时候我们并不关心是否产生真实的目标文件,我们只希望make 不要考虑mtime,而是总能去执行一些命令。
对于这个需求还是有办法的,make 规定,当规则中不存在依赖文件时,这个目标文件名就称为—伪目标。

[root@localhost test]# cat Makefile
test:
        @echo "test ok"

[root@localhost test]# make
test ok

伪目标不能和真实目标文件同名,否则就失去伪目标的意义了,为了避免伪目标和真实目标文件同名的情况,可以用关键字“.PHONY”来修饰伪目标,格式为“.PHONY:伪目标名”,这样不管与伪目标同名的文件是否存在,make 照样执行伪目标处的命令。

通常需要显式用.PHONY 修饰伪目标的场合是删除编译过程中的.o 文件,这是为了避免因旧的.o 文件已存在而影响编译。如果您在Linux 下有过编译源码的经验,就会了解make clean 的作用了,通常clean就是伪目标,用来删除编译过程中的.o 文件。

怪不得clean和all同时存在也可以,因为执行完all就退出了,再执行make clean就只是clean清除

2.4 变量

makefile可以自定义变量,其也要一些系统定义好的变量。

[root@localhost test]# cat Makefile
all:
        @echo AR        :       $(AR)
        @echo AS        :       $(AS)
        @echo CC        :       $(CC)
        @echo CXX       :       $(CXX)
        @echo CPP       :       $(AR)
        @echo FC        :       $(FC)
        @echo GET       :       $(GET)
        @echo PC        :       $(PC)
        @echo MAKEINFO  :       $(MAKEINFO)
        @echo RM        :       $(RM)
        @echo TEX       :       $(TEX)
        @echo WEAVE     :       $(WEAVE)
        @echo YACC      :       $(YACC)
        @echo YACCR     :       $(YACCR)

        @echo ARFLAGS   :       $(ARFLGAS)
        @echo ASFLAGS   :       $(ASFLAGS)
        @echo CFLAGS    :       $(CFLAGS)
        @echo CXXFLAGS  :       $(CXXFLAGS)
        @echo CPPFLAGS  :       $(CPPFLAGS)
        @echo FFLAGS    :       $(FFLAGS)
        @echo LDFLAGS   :       $(LDFLAGS)
        @echo PFLAGS    :       $(PFLAGS)
        @echo YFLAGS    :       $(YFLAGS)
        
[root@localhost test]# make
AR : ar
AS : as
CC : cc
CXX : g++
CPP : ar
FC : f77
GET : get
PC : pc
MAKEINFO : makeinfo
RM : rm -f
TEX : tex
WEAVE : weave
YACC : yacc
YACCR :
ARFLAGS :
ASFLAGS :
CFLAGS :
CXXFLAGS :
CPPFLAGS :
FFLAGS :
LDFLAGS :
PFLAGS :
YFLAGS :
命令相关的变量名 含义 默认
AR 打包程序 ar
AS 汇编语言编译器 as
CC C语言编译器 cc
CXX C++语言编译器 g++
CPP C预处理器,默认是$(CC) -E gcc -E
FC Fortan的编译器和预处理器 f77
GET 从SCCS文件中提取文件程序 get
PC Pascal语言编译器 pc
MAKEINFO 将texinfo文件转换为info文件 makeinfo
RM 删除命令 rm -f
TEX 从TeX源文件中创建TexDVI文件的程序 tex
WEAVE 将Web转换为TeX的程序 weave
YACC 处理C程序的Yacc词法分析器 yacc
YACCR 处理Ratfor程序的Yacc词法分析器 yacc -r

参数相关的系统变量(列举部分),几乎都没有默认值

变量名 含义 默认
ARFLAGS 打包程序$(AR)的参数 rv
ASFLAGS 汇编语言编译器参数
CFLAGS C语言编译器参数
CXXFLAGS C++编译器参数
CPPFLAGS C预处理器参数
FFLAGS Fortan语言编译器参数
LDFLAGS 链接器参数
PFLAGS Pascal语言编译器参数
YFLAGS Yacc词法分析器参数

2.5 隐含规则

一行写不下,用 \进行换行。

注释,用#进行注释。

什么是隐含规则?对于一些使用频率非常高的规则,make 把它们当成是默认的,不需要显式地写出来,当用户未在makefile 中显式定义规则时,将默认使用隐含规则进行推导。

隐含规则只限于那些编译过程中基本固定的依赖关系,比如C 语言代码文件扩展名为.c,编译生成的目标文件扩展名是.o,这一般是一对一的。而一个可执行程序可能是由多个.o 文件共同链接生成的,所以,从可执行程序到.o 文件的关系有可能是一对多,这种不确定性无法使之成为隐含的规则。所以,对于C语言的依赖关系是:文件名.o 依赖于文件名.c,仅限于源文件生成.o 目标文件,不存在.o 文件生成可执行程序的隐含规则。

2.6 自动化变量

变量名 含义
$@ 规则中的目标文件名集合
$< 规则中依赖文件中的第一个文件
$^ 规则中所有依赖文件的集合
$? 规则中,所有比目标文件mtime更新的依赖文件集合

2.7 将每个.c文件生成对应的二进制

# File paths
SRC_DIR := .
BUILD_DIR := .
OBJ_DIR := $(BUILD_DIR)

# Compilation flags
CC := gcc
LD := gcc
CFLAGS := -Wall

# Files to be compiled
SRCS := $(wildcard $(SRC_DIR)/*.c)
OBJS := $(SRCS:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
BUILD := $(OBJS:$(OBJ_DIR)/%.o=$(BUILD_DIR)/%)

# Don't remove *.o files automatically
.SECONDARY: $(OBJS)

all: $(BUILD)

# Compile each *.c file as *.o files
# @mkdir -p $(OBJ_DIR)
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
    @echo + CC $<
    @$(CC) $(CFLAGS) -c -o $@ $<

# Link each *.o file as executable files
# @mkdir -p $(BUILD_DIR)
$(BUILD_DIR)/%: $(OBJ_DIR)/%.o
    @echo + LD $@
    @$(LD) $(CFLAGS) -o $@ $<

.PHONY: all clean
clean:
    rm -rvf $(OBJS) $(BUILD)

参考:《操作系统真相还原》一书,网络博客

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

推荐阅读更多精彩内容

  • //联系人:石虎QQ:1224614774昵称:嗡嘛呢叭咪哄 一、Makefile概述: 1.对很多Winodw...
    石虎132阅读 796评论 0 8
  • Makefile是干嘛的? 就像dockerfile之于docker,makefile之于make.....mak...
    Katou_Megumi阅读 1,049评论 0 0
  • 通常一个大型程序由多个模块文件构成的,按照其功能划分,模块文件会分布在不同的目录中,模块文件之间有包含有头文件,调...
    wayyyy阅读 1,363评论 0 0
  • Makefile的作用 假设在工程operator文件夹下面有add.c、sub.c、mul.c、div.c、co...
    jackmxp阅读 585评论 0 0
  • makefile 基本语法 目标文件:依赖文件[Tab] 命令 上述makefile语法被称为一组规则 目标文件是...
    骑猪满天飞阅读 84评论 0 0