makefile文件简介及编写

Makefile在嵌入式系统开发中扮演关键角色,通过定义编译规则实现源文件的自动化编译,极大提高软件开发效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

makefile简介

在基于Linux嵌入式系统开发的过程中,构建一个工程中的源文件不计其数,按类型、功能、模块分别放在若干个目录中,Makefile定义了一系列的规则来制定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至进行更复杂的功能操作。因为Makefile就像一个shell脚本一样,其中也可以执行操作系统的命令。Makefile带来的好处就是“自动化编译”。一旦写好了makefile文件,只需要一个make命令,整个工程便会完全自动进行编译,极大地提高了软件开发的效率。make是一个命令工具,是一个解释makefile中指令的命令工具。

所要完成的Makefile文件描述了整个工程的编译、链接等规则,其中包括:工程中的那些源文件需要编译以及如和编译,需要创建那些库文件以及如何创建这些库文件,如何产生想要的可执行文件。尽管看起来可能是很复杂的事情,但是为工程编写Makefile的好处是能够使用一行命令来完成“自动化编译”。一旦提供一个(通常对于一个工程来说会是多个)正确的Makefile,编译整个工程所要做的唯一的一件事就是在shell提示符下输入make命令。整个工程完全自动编译,极大地提高了效率。

Makefile文件编写规则

一个Makefile文件包含一系列规则,样式如下:


目标(target)…:依赖(prerequisites
<tab>命令(command)

目标通常是要生成的文件的名称,可以是可执行文件或.o文件,也可以是一个执行的动作名称,如“clean”。依赖(依赖条件、依赖关系)是用来产生目标的材料(比如源文件),一个目标经常有几个依赖。命令是生成目标时执行的动作,一个规则可以含有几个命令,每个命令占一行。每个命令行前必须是一个Tab字符,即命令行第一个字符是由Tab键产生的空格(不能用多个空格组成)。
规则一般用于解释怎样和何时重建目标。make首先调用命令处理依赖,进而才能创建或更新目标。一个规则也可以是用于解释怎样和何时执行一个动作,即打印提示信息。一个Makefile文件也可以包含规则以外的其他文本。

Makefile文件里的赋值

Makefile文件里,变量定义的语法形式如下:

	immediate = deferred
	immediate ?= deferred
	immediate := immediate
	immediate += deferred or immediate
	define immediate
	deferred
	endef

在GNU make中对变量赋值有两种方式,延时变量立即变量。区别在于它们的定义方式和扩展是的方式不同,前者在这个变量使用时才可以展开,即当真正使用时这个变量的值才确定;后者在定义是它的值就已经确定了。使用“:=”定义的变量是立即变量。“?=”仅仅在变量还没有定义的情况下有效,即“?=”被用来定义第一次出现的变量。
对于“+=”,右边的变量如果在前面已经使用“?=”定义为立即变量,则它也是立即变量,否则为延时变量。

Makefile函数

Makefile文件里,函数调用的格式如下:
$(function arguments)
“function”是函数名,“arguments”是该函数的参数,参数和函数之间用空格或Tab隔开,如果有多个参数,它们之间用逗号隔开。

常用函数
字符串处理函数
  1. List ite
    subst
    $(subst , , )
    字符串替换函数,把字符串text中的from字符串替换为to,返回被替换过的字符串。
  2. .patsubst
    $(patsubst , , )
    模式字符串替换函数,查找text中的单词是否符合pattern,如果匹配,则以replacement替换。pattern可以使用%通配符,表示任意长度的字串
    objects = foo.o bar.o bb.c
    $(patsubst %.o, %.c, $(objects)) 结果是foo.c bar.c bb.c
  3. strip
    $(strip )
    去掉string字串中开头和结尾的空格字符。注意只去掉开头和结尾的。
  4. findstring
    $(findstring , )
    查找字符串函数,在字符串in中查找find字符串,如果找到,返回find,否则返回空字符串
    $(findstring a, a b c) //返回a
    $(findstring a, b c) //返回“”空字符串
  5. filter
    $(filter , )
    过滤函数,以pattern模式过滤text字符串中的单词,保留符合模式pattern的单词。返回符合模式pattern的字串
    source := foo.c bar.c baz.c ugh.h
    foo : $(source)
    cc $(filter %.c %.s, $(source)) -o foo
    $(filter %.c %.s, $(source))的返回值是foo.c bar.c baz.c
  6. filter-out
    $(filter-out , )
    反过滤函数,以pattern模式过滤text字符串中的单词,去除符合pattern的单词
  7. sort
    $(sort )
    排序函数,给list中的单词排序(升序),返回排序后的字符串,sort函数会去掉list中相同的单词
  8. word
    $(word , )
    取单词函数,取字符串中的n个单词,从1开始数。如果n比text中的单词数大,返回空字符
  9. wordlist
    $(wordlist , , )
    取单词串函数,从字符串text中从s到e的单词串,如果s比text中的单词要大,则返回空字符串
    $(wordlist 2, 3, foo bar baz),返回值为“bar baz”
  10. words
    $(words ) 统计字符串中的单词个数,返回字符串中的单词数。
    k.firstword
    $(firstword ) 取字符串text中的第一个单词
文件名操作函数
  1. dir
    $(dir ) 从名字序列中取出目录部分,各个名字用空格分隔
  2. notdir
    $(notdir ) 从名字列表中取出非目录部分,就是取出文件名
  3. suffix
    $(suffix ) 取后缀函数,从文件名序列中取出各个文件名的后缀,比如.c .h等。
  4. basename
    $(basename ) 取前缀名字,从文件名序列中取出各个文件名的前缀部
    $(basename src/foo.c src/bar.c hacks) 返回值为src/foo src/bar hack
  5. addsuffix
    $(addsuffix < suffix >, < names >) 加后缀函数, 将后缀suffix加到names中的每个单词的后面,返回加过后缀的文件名序列 $(addsuffix .c, foo bar)返回值为foo.c bar.c
  6. addprefix
    $(addprefix , ) 加前缀函数,把前缀prefix加到names中的每个单词后面。示例:
    $(addprefix src/,foo bar),返回值为src/foo src/barg.join
    $(join , ) 链接函数,将list2中的单词对应的加到list1的单词后面。如果list1中的单词个数要比list2中的多,那么list1中多出来的单词保持原样,如果list2的单词个数比list1多,则list2中多出来的单词复制到list1中。
    $(join aaa bbb, 111 22 333) 返回值为aaa111 bbb222 333
foreach函数

foreach函数是用来做循环用的,$(foreach < var >,< list >,< text >)函数的意思是把参数list中的单词逐一取出放到var所指定的变量中,然后再执行text所包含的表达式。每一次text会返回一个字符串,循环过程中,text所返回的每个字符串都会以空格分隔,最后当整个循环结束后,text所返回的每个字符串所组成的整个字符串将会是foreach函数的返回值。所以var最好是一个变量名,list可以是一个表达式,text中一般会使用var这个参数来依次枚举list中的单词。例子:
names := a b c d
files := $(foreach n, $(names), ( n ) . o ) 上 面 的 例 子 中 , n a m e s 中 的 单 词 会 被 挨 个 取 出 , 并 存 在 n 中 , (n).o) 上面的例子中,names中的单词会被挨个取出,并存在n中, (n).o)namesn(n).o每次计算出一个值,这些值以空格分隔,所以最后files的值为 a.o b.o c.o d.o

if函数

if函数很像make的条件语句ifeq,if的语法为:
$(if < condition >,< then-part >)或者是 $(if < condition >,< then-part >,< else-part >)
condition参数是if的表达式,如果其返回的为非空字符串,那么这个表达式相当于真。

call函数

call函数是唯一 一个可以用来创建新的参数化的函数,这个表达式中,你可以定义许多参数,然后你可以用call函数来向这个表达式传递参数。
$ (call < expression >, < parm1 >,< parm2 > …) 当执行这个函数时,expression中的变量,如$(1), $(2), $(3)等,会被parm1, parm 2, parm3依次取代。而expression的返回值就是call函数的返回值。例如:
reverse = $(1) $(2)
foo = $(call reverse, a, b) 那么foo的值就是a b。

origin函数

origin函数并不操作变量的值,他只是告诉你这个变量是哪里来的, 语法为:
$ (origin < variable >) 注意variable是变量的名字,不是引用,所以不要用$号。
返回值:
undefined : 没有被定义过
default : 默认的定义,如CC
file: 在makefile中被定义
command line : 被命令行定义
override : 被override指示符重新定义的
automatic : 自动化变量。

shell函数

shell函数就是执行shell的命令,它的参数就是操作系统shell的命令,shell函数把执行操作系统命令后的输出作为函数返回。这里要注意,makefile中不是任何地方都能直接运行shell命令的,我们从前面的介绍会发现,只有target后面跟的command才能直接运行shell函数,其他地方都需要利用shell函数来运行shell command。
例子:
contents := $(shell cat foo)
files := $(shell echo *.c)//注意这里不会真正打印到屏幕,而是将echo命令的返回值赋值给files变量
注意,shell函数会生成一个shell程序来执行命令,所以要注意其性能。

控制make的函数
  1. error
    $(error <text …>)error函数会产生一个致命错误,当执行该函数时,会打印出text信息,然后终止执行
  2. warning
    $(warning <text …>) 和error函数类似,但是它只是输出一段warning,不会让make终止。
make的运行

make的退出码
make命令有三个退出码:
0 - 表示成功执行
1 - 如果make运行时出现任何错误,返回1
2 - 如果使用了make的-q选项,并且make使得一些目标不需要更新,那么返回2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值