Makefile初探

Makefile总览

  • Makefile基本语句:

目标(target) : 依赖 (prerequisites)
[TAB]命令(command)

目标包括:执行文件(第一个目标文件),中间目标文件(执行文件的依赖),标签(类似clean)

  • Makefile文件的执行:
    • 使用make命令执行Makefile文件,默认第一条规则的目标为最终目标,也就是可执行文件,也可以在文件前面先指定目标的名称,到后面再完善它的依赖和命令;
    • make [目标名]:执行指定目标规则的命令;
    • 当目标文件不存在,或者某一个依赖文件比目标文件新的时候,执行命令。
    • 执行其他目录下的Makefile文件:make -c /dir -f make.built:执行/dir目录下名为make.built的编译文件(-c:指定目录,-f:指定Makefile文件名称,-I:指定包含的的其他文件目录)
    • make命令中也可以用=指定Makefile中定义的宏,实现条件编译;
make BOOT_MEDIA=emmc AMP_TYPE=linux all #指定两个条件,编译目标all
  • Makefile文件执行:make程序会把整个Makefile文件一次性读进去,再对文件进行解析。

  • Makefile变量:

    • Makefile中的变量都是字符串,和C/C++中的宏是一个意思。
    • 调用变量时,使用变量的引用操作符:$(变量名称);
    • Makefile输出字符串命令:echo $(变量名);
    • 取消终端打印命令:在命令前添加@
    • Makefile中的注释:以#开头。
  • Makefile中对变量有两种赋值方式:
    包括:即时变量和延时变量

    • 赋值符号=:延时变量,变量的值在使用时才被确定,在定义时并没有确定;
    • 赋值符号:=:即使变量,变量的值在定义时就被确定(即时确定);
    • 赋值符号?=:延时变量,变量如果未被赋值,则使用赋予新值,如果赋值了,则使用之前的值,不使用等号后面的值;
    • 变量追加+=:在原有的变量后面追加新的变量字符串。

Makefile里的函数

  • $(var : a = b):对于var中以a结尾的,把结尾a替换为b
value = a.o b.o c.o 
value1 = $(value : .o = .c)
value = a.o b.o c.o 
value1 = $(value : %.o = %.c)#使用%时,变量必须都具有相同的模式

value1的值均为:a.c,b.c,c.c

  • $(a)_$(b):将变量a和变量b组合成a_b,类似这种字符串的拼接可以进行任意组合,
  • $(subst a, b, value):字符串替换函数,将value中的字符a替换为字符b
value = value1
res = $(subst 1, 2, $(value))

变量res的值为value2

  • $(foreach var, list, text):对list里的每一个变量执行text格式的转换
A = a b c
B = $(foreach f, $(A), $(f).o)

则B = a.o b.o c.o

  • $(filter pattern, text):过滤函数,取出text中符合pattern格式的变量
    $(filter-out pattern, text):反过滤函数,取出text中不符合pattern格式的变量
A = a b c d/
B = $(filter %/, $(A))
C = $(filter-out %/, $(A))

则B的结果为:d/;C的结果为:a b c

  • $(wildcard pattren):列出当前目录下符合pattern格式的文件
files = a.c b.c c.c d.o
files1 = $(wildcard *.c)
files2 = $(wildcard $(file))    #取出file中真实存在的文件

则files1的值为:a.c b.c c.c;files2的值为:a.c b.c c.c d.o

  • $(patsubst pattern, repalcement, $(var)):模式字符串替换函数,支持通配符,把列表var中符合pattern格式的变量替换成replacement格式的变量
file = a.c b.c c.c d.o
dep_flies = $(patsubst %.c, %.d, $(files))

则dep_files的值为:a.d b.d c.d d.o,符合格式的就替换,不符合格式的就不替换,之后存入对应的变量中。

Makefile举例:

main: a.o b.o c.o
    gcc -o main $^
%.o : %.c
    gcc -c -o $@ $<
clean: 
    rm *.o main 
.PHONY: clean 
  • %:文件通配符,如%.o : %.c目标和依赖都是一系列文件,依赖中%所代表的字符串取决于目标中%所代表的字符串。
  • 使用了通配符时,命令中用$@表示所有目标,使用$>表示依赖的第一个文件(使用$^表示所有的依赖)
  • 若使用make clean则执行目标clean的命令;但此时若目录下有名为clean的文件,则会覆盖clean命令的执行,(因为根据Makefile的执行规则,clean文件已存在,而且clean没有依赖,无法通过时间判断文件是否更新,所以不执行clean的命令);
    所以把clean定义为假想目标.PHONY:,这样Makefile在执行时就直接执行目标'clean'的命令;
  • 伪目标只是一个标签,并不是文件。

包含头文件的问题

main : a.o b.o c.o 
    gcc -o main $^
%.o : %.c
    gcc -c -o $@ $<
  • 问题的原因:.o文件的依赖只有.c文件,若只修改头文件而不修改.c文件,则编译时并不会准确修改编译的结果,相当于修改的头文件并没有起到效果;
    • 比如:修改c.h,则添加规则
      c.o : c.c c.h:表示c.o的依赖是c.cc.h,命令为空;
  • 但Linux中头文件过于庞大,手写规则会过于复杂,所以用以下命令添加规则
gcc -MM c.c   #打印出c.c的依赖文件
gcc -MM -MF c.d c.c   #将c.c的依赖写进c.d
gcc -c -o c.o c.c -MD -MF   #把依赖写进c.d,编译生成c.o

或者编译前make clean,再进行编译,也可以编译出新的.o文件

  • 包含头文件问题的解决:
objs = a.o b.o c.o

dep_files := $(patsubst %, .%.d, $(objs)) #将变量名修改为为.x.o.d并赋值给dep_files,用于存储各个.c文件的依赖
#dep_files := $(foreach f, $(objs), .$(f).d)也可以使用foreach函数
dep_files := $(wildcard $(dep_files)) #取出dep_files中真实存在的文件,存入dep_files中,若不存在则dep_files为空

main : $(objs)
    gcc -o main $^

ifneq ($(dep_files), )  #如果dep_files非空
include $(dep_files)    #则包含依赖dep_fiels
endif

%.o : %.c
    gcc -c -o $@ $< -MD -MF .$@.d #编译文件,并将依赖分别写进.x.o.d文件中
    
clean :
    rm *.o main
distclean:
    rm $(dep_files)
  • 依赖关系:.o依赖于.d文件,.d文件依赖于.c文件。
  • include关键字:
    • 可用于在一个Makefile中包含另一个Makefile,典型的用法就是包含子目录的Makefile文件;
    • 在后面的文件名中可以包含路径,通配符,变量的引用;
    • include前面不能用TAB键,include后面可以有空格

补充:由于编译的要求,Makefile可能会用到CFLAGS添加编译参数,包括:输出警告信息CFLAGS = -Wall;编译debug版本CFLAGS = -g;编译优化CFLAGS = -O;将警告当成错误CFLAGS = -Werror

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

推荐阅读更多精彩内容