Makefile的简单编写

  • makefile的学习:(根本是根据文件创建的依赖关系实现各个命令来达到最终目的)
  • 文件编写规则:显式规则、隐晦规则、变量定义、文件指示和注释

targets : prerequisites

Command

targets : prerequisites ; command

Command

targets 是文件名,以空格分开,可以使用通配符。一般来说,我们的目标基本上是一个

文件,但也有可能是多个文件。

command 是命令行,如果其不与“target rerequisites”在一行,那么,必须以[Tab 键]

开头,如果和 prerequisites 在一行,那么可以用分号做为分隔。(见上)

prerequisites 也就是目标所依赖的文件(或依赖目标)。如果其中的某个文件要比目标

文件要新,那么,目标就被认为是“过时的”,被认为是需要重生成的。这个在前面已

经讲过了。

Eg:main.o : main.c defs.h            /*这里的main.o就是最终要生成的目标文件,其是依据main.c以及defs.h,这里的defs.h是用户自己的库文件*/

cc -c main.c         /*这里cc是Makefile文件中自带的gcc变量,此语句用来生成main.o文件*/        

-static 禁止使用动态库

编译出来的东西,一般都很大,也不需要什么动态连接库,就可以运行。

  1. 其他使用功能:通配符;“*”“?”“[...]”
  2. 文件搜寻:特殊变量(VPATH),VPATH=src:../headers   :两个目录  src和 ../headers,冒号分割

使用方法有三种:

1、vpath <pattern> <directories>

为符合模式<pattern>的文件指定搜索目录<directories>。

2、vpath <pattern>

清除符合模式<pattern>的文件的搜索目录。

3、vpath

清除所有已被设置好了的文件搜索目录。

3.伪目标:.PHONY  定义伪目标   

eg:

.PHONY: clean

clean:

rm *.o temp

使用  make clean    命令行输出: rm *.o temp

PHONY: cleanall cleanobj cleandiff

cleanall : cleanobj cleandiff

rm program

cleanobj :

rm *.o

cleandiff :

rm *.diff

“make clean”将清除所有要被清除的文件。“cleanobj”和“cleandiff”这两个伪目标有点

像“子程序”的意思。我们可以输入“make cleanall”和“make cleanobj”和“make

cleandiff”命令来达到清除不同种类文件的目的。

5.命令显示:在要执行的命令行之前加@,此命令行执行时屏幕上不会显示此命令。

6.命令执行:如果你要让上一条命令的结果应用在下一条命令时,你应该使用分号分隔这两条命令。

Eg:

exec:

cd /home/hchen; pwd

当我们执行“make exec”时,第一个例子中的 cd 没有作用,pwd 会打印出当前的

Makefile 目录,而第二个例子中,cd 就起作用了,pwd 会打印出“/home/hchen”。

7.命令出错:命令正常返回0后继续执行后面指令,错误则返回非0,,则终止当前运行。

为了做到这一点,忽略命令的出错,我们可以在 Makefile 的命令行前加一个减号“-”

(在 Tab 键之后),标记为不管命令出不出错都认为是成功的。如:

clean:

-rm -f *.o

8.嵌套执行make:我们有一个子目录叫 subdir,这个目录下有个 Makefile 文件,来指明了这个目录下文件的编译规则。那么我们总控的 Makefile 可以这样书写:

subsystem:

cd subdir && $(MAKE)    总控makefile的变量可以传递给下一级makefile,需用export声明

Eg:expor<variable>

9.静态模式:

<targets ...>;: <target-pattern>;: <prereq-patterns ...>;

<commands>;

targets定义了一系列的目标文件,可以有通配符。是目标的一个集合。

target-parrtern是指明了targets的模式,也就是的目标集模式。

prereq-parrterns是目标的依赖模式,它对target-parrtern形成的模式再进行一次依赖目标的定义。

Eg:

objects = foo.o bar.o

all: $(objects)

$(objects): %.o: %.c

$(CC) -c $(CFLAGS) $< -o $@

上面的例子中,指明了我们的目标从$object中获取,“%.o”表明要所有以“.o”结尾的目标,也就是“foo.o bar.o”,也就是变量$object集合的模式,而依赖模式“%.c”则取模式“%.o”的“%”,也就是“foo bar”,并为其加下“.c”的后缀,于是,我们的依赖目标就是“foo.c bar.c”。而命令中的“$<”和“$@”则是自动化变量,“$<”表示所有的依赖目标集(也就是“foo.c bar.c”),“$@”表示目标集(也就是“foo.o bar.o”)。

flietrs函数的应用:过滤

files = foo.elc bar.o lose.o

$(filter %.o,$(files)): %.o: %.c

$(CC) -c $(CFLAGS) $< -o $@

$(filter %.elc,$(files)): %.elc: %.el

emacs -f batch-byte-compile $<

$(filter %.o,$(files))表示调用Makefile的filter函数,过滤“$filter”集,只要其中模式为“%.o”的内容。其的它内容,我就不用多说了吧。这个例子展示了Makefile中更大的弹性。

10.自动生成依赖性:GNU组织建议把编译器为每一个.c源文件的自动生成的依赖关系放到一个文件.d中。

编译时加-M:自动找寻头文件

cc -M main.c

其输出是:

main.o : main.c defs.h

这里,我们给出了一个模式规则来产生[.d]文件:

%.d: %.c

@set -e; rm -f $@; \

$(CC) -M $(CPPFLAGS) $< >; $@.$$$$; \                    //-M是编译生成.d文件

sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ >; $@; \          

rm -f $@.$$$$

其中$@表示目标文件,$<表示所有依赖文件。

这个规则的意思是,所有的[.d]文件依赖于[.c]文件,“rm -f $@”的意思是删除所有的目标,也就是[.d]文件,第二行的意思是,为每个依赖文件“$<”,也就是[.c]文件生成依赖文件,“$@”表示模式 “%.d”文件,如果有一个C文件是name.c,那么“%”就是“name”,“$$$$”意为一个随机编号,第二行生成的文件有可能是 “name.d.12345”,第三行使用sed命令做了一个替换,关于sed命令的用法请参看相关的使用文档。第四行就是删除临时文件。

高级变量方法:

foo := a.o b.o c.o

bar := $(foo:.o=.c)

这个示例中,我们先定义了一个“$(foo)”变量,而第二行的意思是把“$(foo)”中所有

以“.o”字串“结尾”全部替换成“.c”,所以我们的“$(bar)”的值就是“a.c b.c c.c”。

11.定义命令包:c语言定义函数一样

define run-yacc

yacc $(firstword $^)

mv y.tab.c $@

endef

这里,“run-yacc”是这个命令包的名字,其不要和Makefile中的变量重名。在“define”和“endef”中的两行就是命令序列。这个 命令包中的第一个命令是运行Yacc程序,因为Yacc程序总是生成“y.tab.c”的文件,所以第二行的命令就是把这个文件改改名字。还是把这个命令 包放到一个示例中来看看吧。

foo.c : foo.y

$(run-yacc)

我们可以看见,要使用这个命令包,我们就好像使用变量一样。在这个命令包的使用中,命令包“run-yacc”中的“$^”就是“foo.y”,“$@” 就是“foo.c”(有关这种以“$”开头的特殊变量,我们会在后面介绍),make在执行命令包时,命令包中的每个命令会被依次独立执行。

我们可以使用“+=”操作符给变量追加值,如:

objects = main.o foo.o bar.o utils.o

objects += another.o

于是,我们的$(objects)值变成:“main.o foo.o bar.o utils.o another.o”(another.o 被追加

进去了)

?=        :的用法

FOO ?= bar

其含义是,如果 FOO 没有被定义过,那么变量 FOO 的值就是“bar”,如果 FOO 先前

被定义过,那么这条语将什么也不做。

目标变量:prog    

prog : CFLAGS = -g

prog : prog.o foo.o bar.o

$(CC) $(CFLAGS) prog.o foo.o bar.o

在这个示例中,不管全局的$(CFLAGS)的值是什么,在 prog 目标,以及其所引发的所

有规则中(prog.o foo.o bar.o 的规则),$(CFLAGS)的值都是“-g”

12.函数调用:函数调用,很像变量的使用,也是以“$”来标识的,其语法如下:

$(<function> <arguments> )

或是

${<function> <arguments>}

<function>就是函数名,make 支持的函数不多。<arguments>是函数的参数,参数

间以逗号“,”分隔,而函数名和参数之间以“空格”分隔。

Eg:$(subst a,b,$(x)):将$(x)中的a换成b   subst是字符串处理函数

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

把字串“x.c.c bar.c”符合模式[%.c]的单词替换成[%.o],返回结果是“x.c.o bar.o”

$(strip <string> )   :去空格函数,去掉开头结尾的空格的函数

$(findstring a,a b c)

$(findstring a,b c)

第一个函数返回“a”字符串,第二个返回“”字符串(空字符串)

13.文件名操作函数:

$(dir <names...> )

名称:取目录函数——dir。

功能:从文件名序列<names>中取出目录部分。目录部分是指最后一个反斜杠(“/”)

$(suffix <names...> )

名称:取后缀函数——suffix。

功能:从文件名序列<names>中取出各个文件名的后缀。

示例:$(suffix src/foo.c src-1.0/bar.c hacks)返回值是“.c .c”。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值