makefile学习笔记

makefile学习笔记

一,makefile定义一系列的规则对源码进行自动化编译链接,它是一个文件,需要make工具对其进行解释,一般都有这个工具。

二,makefile规则
target ...:prerequisites
command
command
...
target可以是object文件,也可以是执行文件,还可以是标签(后面解释)。
prerequisites就是生成target需要的文件。
command就是生成target执行的命令(任意的shell命令),注意command前面一定是TAB键。
总的说来就是:生成target需要prerequisites源文件,执行command命令生成。如果prerequisites比target要新,则command命令就会执行。
eg:
target:main.o kdb.o command.o\
display.o insert.o
cc -o target main.o kdb.o command.o\
display.o insert.o
main.o:mainc defs.h
cc -c main.c
kdb.o:kdb.o defs.h
cc -c kdb.c
command.o:command.c defs.h
cc -c command.c
display.o:display.c defs.h
cc -c display.c
insert.o:insert.c defs.h
cc -c insert.c
clean:
rm target main.o kdb.o command.o\
display.o insert.o
"\"表示换行的意思。将这部分部内容保存在makefile或Makefile中,然后执行make命令就会生成a执行文件了,这里的clean是一个标签,可以这样使用:make clean,这样就会执行rm操作。

三,makefile变量
定义:
object = main.o kdb.o command.o\
display.o insert.o
使用:
$(object)
所以上面的例子就可以变成:
object = main.o kdb.o command.o\
display.o insert.o
target:$(object)
cc -o target $(object)
main.o:mainc defs.h
cc -c main.c
kdb.o:kdb.o defs.h
cc -c kdb.c
command.o:command.c defs.h
cc -c command.c
display.o:display.c defs.h
cc -c display.c
insert.o:insert.c defs.h
cc -c insert.c
clean:
rm target $(object)

四,makefile的自动推导
只要make看到一个[.o]文件,则会自动把.c文件添加依赖,并且自动执行cc -c filename.c会被推导出来。
也就是说
main.o:mainc defs.h
cc -c main.c
等价于
main.o:defs.h
所以上面的例子又可以进进简化:
object = main.o kdb.o command.o\
display.o insert.o
target:$(object)
cc -o target $(object)
main.o:defs.h
kdb.o:defs.h
command.o:defs.h
display.o:defs.h
insert.o:defs.h
.PHONY:clean
clean:
rm target $(object)
这里的.PHONY后面解释。

五,清空目标
一般做法是:
.PHONY:clean
clean:
-rm target $(object)
PHONY表示伪目标后面有详细说明,而rm前面加上-表示如查发生错误忽略,继续做后面的事。

六,注释
使用“#”表示

七,makefile文件名
makefile文件名最好使用makefiel或Makefile,也可以自己定义文件名,但执行的时候需要加f参数
make -f make.linux

八,引用其它makefile
语法:-include
注意前面不能以TAB键开始,-符号前面已经说过了,这里就不解释了。
filename可以使用通配符
include

a.make *.mk $(bar)

九,环境变量MAKEFILES
这个环境变量的值是其它makefile文件,make会将这个值自动include,不同的是环境变量中的目标不会起作用,如果出错不理会。

十,文件查找
1.默认情况下会在当前目录找目标文件和依赖文件,系统有一个内置变量VPATH,如果默认找不到会到这个指定的目录找。
VPATH可以指定多个路径,用冒号会隔
eg:
VPATH = src:../header
2.还有另一种设置文件路径的方法:使用make的关键字“vpath”,它是关键字不是变量。
用法:
(1) vpath


vpath %.h ../header 表示所有以.h结尾的文件在../header目录下搜索。
(2) vpath
vpath %.h 清除为以.h结尾的文件设置的路径
(3)vpath
清除所以设置好的文件搜索路径

十一,伪目标
上面的clean是伪目标,它不是一个文件,只是一个标签,所以make无法生成这个文件,只在指明这个目标后才能用make clean,当然伪目标名字不能和文件名重名,为了避免这种情况发生而使用.PHONY,说明不管有没有clean文件,要运行clean这个目标,只能”make clean“,而且伪目标总是被执行。

1.伪目标作为默认目标样例:
all:pro1 pro2 pro3
.PHONY:all
pro1:pro1.o utils.o
cc -o pro1 pro1.o utils.o
pro2:pro2.o
cc -o pro2 pro2.o
pro3:pro3.o utils.o
cc -o pro3 pro3.o utils.o

2.伪目标作为依赖的样例:
.PHONY:cleanall cleanobj cleandiff
cleanall:cleanobj cleandiff
rm program
cleanobj:
rm *.o
cleandiff:
rm *.diff

十一,多目标
适用于多个目标的依赖文件一样,执行命令也类似
bigoutput littleoutput:text.g
generate text.g -$(sutstr output,,$@) > $@
$表示执行一个函数,substr是函数,output, ,$@是函数参数,$@是目标集,类似于数组,依次取出值。
这个等价于
bigoutput:text.g
generate text.g -bit > bigoutput
littleoutput:text.g
generate text.g -little > littleoutput

十二,静态模式
::

....
targets定义一系列目标文件,是一个集合,可以使用通配符。
target-patten是目标模式,从targets中取部分或全部的一个目标集合。
pererq-patten是目标的依赖模式,对target-patten模式进行二次定义,比如target-patten定义成%.o,pererq-patten定义成%.c,意思就是取%.o将.o换成.c后变成pererq-patten的集合。

例子一:
object=foo.o bar.o
all:$(object)
$(object):%.o:%.c
$(cc) -c $(CFLAGS) $< -o $@
object,cc,cflags都是定义的变量
$<表示依赖集合,$@表示目标集合,这两人个集合相当于数组,都是依次取值,所以等价于:
foo.o:foo.c
$(cc) -c $(CFLAGS) foo.c -o foo.o
bar.o:bar.c
$(cc) -c $(CFLAGS) bar.c -o bar.o

例子二:
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-complie $<

十三,自动成生依赖关系
如查一个文件包含了多个头文件,那它的依赖关系就很多,那写makefile文件时就要非常清楚包含了哪些头文件,这样非常麻烦,但是c/c++编译器一般都支持-M选项,它会自动生成文件的依赖关系。比如main.c文件包含头文件a.h,那么cc -M main.c生成的依赖关系为main.o:main.c a.h
那么如何运用编译器这一特性呢,我们的思路是这样的:为每个文件生成一个.d文件结尾包含了所有依赖关系的文件,然后include这个文件就可以了。
%.d:%.c
rm -rf $@;\
$(cc) -M $(CPPFLAGS) $< > $@.$$$$;\
sed -e 's,\($*\)\.o[ :]*, \1.o $@:,g' < $@.$$$$ > $@;\
rm -rf $@.$$$$
首先删除%.d文件,然后通过编译-M参数生成filename.d.1234的临时文件,然后用sed命令对finename.d.1234文件内容进行替换:
main.o : main.c defs.h替换成
main.o main.d :main.c defs.h保存为filename.d
最后删除临时文件
如果完成了这些,最后就是将这些文件include到makefile中了,使用这种方法:
source=foo.c bar.c
inlcude $(source:.c=.d)
这里.c=.d的意思是,将source中所.c字符都替换成.d字符。
这样就可以将相应的.d文件导入了。

十四,makefile书写命令
makefile的命令就是shell命令,需要注意的是命令前一定要是TAB键,除非命令跟在分号后;

十五,显示命令
每条命令执行时都会输出到屏幕上,如果命令前加上@,则不会在屏幕上显示。
比如:@echo test
则只会打印test,而不会输出命令echo

十六,命令执行
如果前一条命令结果需要应用到后一条命令,则这两条命令需要写在一起用分号分隔
exec:
cd /home/user;pwd
这样pwd才会打印/home/user,如果不用分号而写成两行,会打印makefile文件所在目录

十七,命令出错处理
当一个规则中的命令出错时,整个makefile可能就不能执行了。有些错误是可以忽略的,在命令前加-,前面已经说过。
还有一个方法是,make 命令加参数-i,它会忽略文件中的全部错误。
-k参数意思是如果命令出错了,终止该目标的执行,继续执行其它规则。

十八,嵌套执行make
一个大的工程可以有多个makefile文件 ,分布在不同的目录下,这样对分段编译有相当大的好处。
比如:subdir目录下有一个makefile文件,我们总控makefile文件可以这样写:
subsystem:
cd subdir;$(MAKE)

十九,变量传递
当嵌套时可以将上一层的变量应用到下一层去,变量声明时可以这样:
export
不想应用到下一层
unexport
例子:
export variable = value
等价于
variable = value
export variable
等价于
export variable:=value
等价


variable:=value
export variable

如果传递所有变量只需要export就行了,后面不用跟任何变量名默认全部变量都可以传递。

SHELL和MAKEFLAGS总是传递的。MAKEFLAGS的值是make命令的参数,但是有几个参数不会传递-C -f -h -o -W。如要你不想传递 MAKEFLAGS,那执行下层makefile时对这个变量再赋值就行了,比如:
subsystem:
cd /home/user;$(MAKE) MAKEFLAGS=

二十,定义命令包
一些相同的从序列可以定义成一个命令包。
define run-yacc
run $(firstword $^)
yacc y.tab.c $@
endef
使用:$(run-yacc)

二十一,其它
变量$^,表示依赖目标集合,与$<不同的时,运行时$^取的是集合全部内容,而$<是依次取,每次取一个值。

相关文档
最新文档