Linux系统编程.NO3——makefile基本用法

关于makefile我也是从别人的贴子中总结出来的,而且只总结了一部分,如果想要了解得更多,可以去访问原文:http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=408225&extra=&authorid=10610714&page=1

2.Makefile基础

2.1.Makefile概述

会不会写Makefile就从侧面说明了一个人是否具备完成大型工程的能力,因为在Linux系统上做程序开发的时候是没有windows上的那些IDE的,编译规则都需要自己定义。
一个工程的源文件可能不计其数,其按类型、功能、模块分别放在若干个目录中,Makefile定义了一系列的规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至与进行更加复杂的功能操作,Makefile就像一个脚本一样,其中也可以执行操作系统的命令。
Makefile的好处就是实现自动化编译,提供了windows下IDE的作用,一旦写好Makefile,整个工程完全自动编译,极大的提高了软件开发的效率。
make是一个命令工具与,是一个解释Makefile中指令的工具。

2.2.程序的编译和链接

一般来说,不管是C还是C++,首先要把源文件编译成中间代码文件(windows下就是.obj文件,Linux下是.o文件,统称为object file),这个动作就是编译;然后再把大量的object file合成执行文件,这个动作就是链接。
编译时,编译器需要的是语法的正确,函数与变量的声明的正确,对于函数与变量的声明,一般都是指明头文件的位置,只要所有的语法正确,编译器就会编译出中间目标文件,所以每个源文件都会有一个中间目标文件。
链接时,主要是链接函数和全局变量,所以使用中间目标文件来链接应用程序,链接器并不管函数所在的源文件,只看函数的中间目标文件。多数时候,由于源文件太多,中间目标文件也就太多,而在链接时需要明确指出中间目标文件名,这样很麻烦,所以一般会给中间目标文件打个包,windows下这种包就是库文件(.lib文件),在Unix下,就是archive file(.a文件)。

2.3.Makefile规则

2.3.1.Makefile使用原则

Makefile文件用于告诉make命令具体怎样实现编译和链接程序,在使用Makefile定义规则的时候,一般有几个原则:

  1. 如果这个工程没有编译过,那么我们所有的c文件都要编译并被链接;
  2. 如果这个工程的某几个c文件被修改,那么我们只编译被修改的c文件,并链接目标程序;
  3. 如果这个工程的头文件被改变了,那么我们需要编译引用了这几个头文件的c文件,并链接目标程序。

2.3.2.Makefile基本规则

target…:prerequisites…
command


target指目标文件,可以是object file,也可以是可执行文件,
也可以还可以是一个标签。
prerequisites是要生成那个target所需要的文件或目标。
command也就是make需要执行的命令,可以是任意shell命令
这个格式指明了一种依赖关系,也就是target这个一个或多个目标文件依赖于prerequisites中的文件,target的生成规则定义在command中,即prerequisites中如果有文件要更新,那么command所定义的命令就会被执行,这就是Makefile最核心的规则。

2.3.3.Makefile使用实例

一个工程有8个源文件,3个头文件,最终要生成一个可执行文件edit。
edit : main.o kbd.o command.o display.o insert.o search.o files.o utils.o
cc -o edit main.o kbd.o command.o display.o insert.o search.o files.o utils.o
main.o : main.c defs.h
cc -c main.c
kbd.o : kbd.c defs.h command.h
cc -c kbd.c
command.o : command.c defs.h command.h
cc -c command.c
display.o : display.c defs.h buffer.h
cc -c display.c
insert.o : insert.c defs.h buffer.h
cc -c insert.c
search.o : search.c defs.h buffer.h
cc -c search.c
files.o : files.c defs.h buffer.h command.h
cc -c files.c
utils.o : utils.c defs.h
cc -c utils.c
clean :
rm edit main.o kbd.o command.o display.o insert.o search.o files.o utils.o
可以看到,所有的命令(cc,rm)前都有空格,这个空格必须是一个,cc是Unix中的编译器命令,Linux中是gcc,命令都是一样的。生成可执行文件gcc -o 目标文件 源文件/object file
生成编译文件gcc -c 源文件。注意生成object文件不需要加目标文件名,但是生成可执行文件时要加上目标文件名。
make是不会管理具体命令内容是什么,它只会去执行这些命令,make会比较target文件个prerequisites文件的修改日期,如果prerequisites的修改日期比target文件的日期要新,或者target不存在,那么make就会执行后续定义的命令。
clean:就像定义给make工具的子命令一样,执行命令make clean,就会自动执行clean:下面定义的语句。像这样冒号后面没有内容的,就是一个label(标签),make不会主动执行标签下的命令,只有用户主动执行make clean才会执行。

2.3.4.Makefile工作过程

默认方式下,只要用户输入make命令,make工具就会在当前目录查找Makefile或者makefile文件,如果找到了Makefile文件,那么就会以文件中第一个目标文件作为最终目标文件。
如果这个最终文件不存在或者该文件的依赖文件更新时间比这个最终文件要新,那么make就会执行后面所定义的命令来生成或更新这个最终文件。
如果最终文件所依赖的.o文件也存在,那么make会在当前的文件中找目标为.o文件的依赖性,找到则再根据某一个规则先生成.o文件,前提是.o文件的依赖的.c和.h文件都是存在的,这样make就会先生成.o文件,最后再生成最终的可执行文件。
make的工作过程就是一个检查依赖性的过程,make会一层又一层地去寻找文件的依赖关系,直到最终编译出最终目标文件。make命令对于工程的纠错仅仅局限于该文件是否存在,如果某文件实在不存在,那么make就会退出工作,至于编译是否成功这些问题不是make能考虑的事情。
根据Makefile的工作过程也可以看出,像clean:这样不在最终文件的依赖性列表中的东西,make是不会去主动执行的。而且任意修改一个.c或.h文件,都会引起make的工作。

2.3.5.Makefile使用变量

在之前的实例中,可以看到如果依赖文件太多,有时候需要多次书写,如edit : main.o kbd.o command.o display.o insert.o search.o files.o utils.o
cc -o edit main.o kbd.o command.o display.o insert.o search.o files.o utils.o
很不方便,如果Makefile更加复杂,然后又需要添加一个依赖文件,很可能就会出错,所以为了Makefile的易维护,在Makefile中可以使用变量,即和C语言中的宏定义是一个意思。
只要在文件一开声明一个变量(变量名自定义)如:
obj.o= main.o kbd.o command.o display.o insert.o search.o files.o utils.o那么在之后的文件中需要用到这些依赖文件就只需要使用 ( o b j . o ) 即 可 调 用 。 如 : e d i t : (obj.o)即可调用。如: edit: (obj.o)edit(obj.o)
cc -o $(obj.o)
clean:
rm edit $(obj.o)
不仅书写更加方便,修改的时候也不需要修改所有地方,只需要修改定义即可。

2.3.6.Makefile自动推导

make是一个很强大的工具,它可以自动推导文件以及文件依赖关系后面的命令。比如make遇到了一个.o文件,它就会自动地把.c文件加在依赖关系中。如make找到一个insert.o,那么inset.o的依赖文件insert.c和形成命令gcc -c insert.c也会被推导出来,这样Makefile的书写就更加简单,联合变量,之前的Makefile可以得到极大的简化:
objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.o
edit : $(objects)
cc -o edit $(objects)
main.o : defs.h
kbd.o : defs.h command.h
command.o : defs.h command.h
display.o : defs.h buffer.h
insert.o : defs.h buffer.h
search.o : defs.h buffer.h
files.o : defs.h buffer.h command.h
utils.o : defs.h
.PHONY : clean
clean :
rm edit $(objects)

2.3.7.Makefile归纳功能

在使用了变量和自动推导功能后,Makefile虽然已经得到了极大的简化,但是任然有很多重复的地方,比如所有.o文件都依赖于defs.h文件,kbd.o command.o files.o都依赖于command.h文件,而display.o insert.o search.o files.o又都依赖于buffer.h文件。
为了解决这些重复书写的定义,make提供了归纳功能。即将有相同依赖文件的对象全都放在一行定义:
objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.o
edit : $(objects)
cc -o edit $(objects)
$(objects) : defs.h
kbd.o command.o files.o : command.h
display.o insert.o search.o files.o : buffer.h
.PHONY : clean
clean :
rm edit $(objects)
归纳功能可以最大限度的减少Makefile的代码量,但是却不能明显的看出依赖关系,而且难以阅读。

2.3.8.Makefile清空规则

每个Makefile都应该有一个清空功能,用于清空.o和可执行文件,这样才利于重编译,也利于保持文件的清洁。一般格式是:
clean:
rm edit $(obj.o)
也可是写成.PHONY:clean
clean:
rm edit $(obj.o)
.PHONY是一个伪目标声明(这个不是自定义,只能这么写),用于告诉make工具,clean是一个伪目标,由于目标clean后面没有任何依赖文件,所以make执行检查的时候是无法检查出“clean的依赖文件的更新日期比clean文件的更新日期新”这一结果的,所以按照make正常的逻辑来解释clean,是有可能不会执行的。因此要给与clean特殊声明。
用.PHONY声明之后,只要用户执行make clean,make就会跳过检查而直接执行clean所定义的命令。
最后一行也可以改成- rm edit $(obj.o)多加一个减号-表示如果执行过程中某些文件出现了问题,不用理会,继续做后面的事情。
最关键的是不能放在文件开头,否则会被make认成最终目标,一般的使用规则是clean从来都是放在文件的最后

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值