荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: georgehill (人生不定式), 信区: Linux
标  题: Make程式和重编核心 (转寄)
发信站: BBS 荔园晨风站 (Thu Sep 14 12:41:38 2000), 站内信件

【 以下文字转载自 georgehill 的信箱 】
【 原文由 georgehill.bbs@smth.org 所发表 】
发信人: alanxzj (天浪), 信区: Linux
标  题: Make程式和重编核心 (转寄)
发信站: BBS 水木清华站 (Thu Sep 14 03:16:31 2000)

Make通常用来维护程式,使可执行档的内容保持和原始程式的一致性,因其依循唯
有变动才需重新编译连结的方式,由各档之间的「依存关系」自动去编译连结,如
此可省下了宝贵的时间和系统资源。在Linux中最普遍的例子应是核心(kernel)的
重 编,当读者把gcc等程式和核心原始程式安装完後(Slackware中为D套件,SLS中
为C和 S套件),便可依实际情况去更新或置换核心的内容。核心是由许多不同的部
份所组成 ,如行程的管理、档案系统的支援、周边配备的驱动程式、网路通讯的
协定等,当组 成的部分有所更新或是不需要时,就需要重编核心,以便产生符合
真实环境的核心程 式,使得PC能得到最佳的利用。如没有SCSI卡的PC便不需要
SCSI的驱动程式,而且可 依光碟和音效卡的种类更换不同的驱动程式。如此繁琐
的过程,在make的帮助下,可 以作得又快又好,只需透过一连串的选择,其馀就
完全交给make去负责,真是省事又 方便。和核心编译有关的细节我们稍後再共同
研讨。make的最初目的是帮助程式设计 师作为编译连结时的管理,因此我们先来
看看make的用法。

使用时机和环境
  当程式写作或是更新後,编连的步骤便是使用make的最好时机。在Linux中,
启 动make只消打make便可,make会先去找同目录下的Makefile或是makefile,若
找不到 便出现make的参数使用方法。makefile是一个文书档,可用vi或是jed编辑
,它可说 是make的script,make就完全依此档的内容来动作。在这个档中,记录
了档案的产生 方法、相关性质和一些变数等。在这个档中,凡是以#为开头者,整
行都视为注解, 和shell的script file是相同的。makefile中约略可分成变数区
和指令区两部分, 纵贯档案的有依存、字尾等规则,共同构成makefile的语法。


Makefile中的变数
  在makefile中可将一字串设定给一变数,需要时可如shell的script file展
开 ,因此也可称为巨集(marco),变数设定的方式为:

  变数名称=设定值

  除了某些特殊符号外(如#、:、;、=、空白、定位字元、新列字元),其馀都可
作 为设定值的内容。一般来说,最好使用英数字,以避免发生不可预料的错误,
以下是 一些合法的设定

  SOURCE = test1.c test2.c test3.c
  OBJ = main.o


  当要取用(展开)变数时,只需用()将变数括起来,前头加上$符号即可,如
$(OBJ) 这个变数,当make执行至此时,将视为main.o。



依存关系
  make的主要工作方式,是依「依存关系」(dependency)来工作的,而所谓的
依存关系,就是指两或多个档案间彼此的关系,譬如我们写了一个test.c程式,当
我们 编译如下时:

  $ gcc -O -o test test.c

  便会产生test.o这个目的档,因此test.o便是依於test.c,当test.c改变时,
 test.o也需重新编译,才能保持程式的最新版本;若test.o是由test1.c和
test2.c 所组成的,那test.o同时依存於test1.c及test2.c,依存关系便是相关档
案的先後关系,和档案的「生成」方式,如C语言的原始档.c需cc或gcc作编译後才
能生成目标档 .o,而且make功能强大,在依存规则中并不限定只能作和编译有关
的动作。

  接下来就是将依存规则写入makefile中了,依存规则的格式如下:

  目标档;依存档;命令

  「目标档」就是「依存档」照「命令」的方式造出的档案,如上例便可写成:


  test:test.c;gcc -O -o test test.c

  或是可将「命令」写在下一行,但是需有定位字元作为前导,因此可写成:

  test:test.c
     gcc -O -o test test.c


  通常以此方式撰写,认为是较好的方式;若「目标档」或「依存档」中有两个
以 上的档案,各档案名称间以空白隔开便可,如下:

  test:test1.c test2.c
     gcc -O -o test test1.c test.c


  如此定下规则,那天若是test1.c或test2.c有修改时(日期会比test.o还新)
, make便会重新编译,若是test.o为最晚者,那就没有执行命令的必要了。

  接下来我们先看范例一:


范例一:

01 #
02 # Makefile for cshow
03 # By Ivor Chen
04 # 08/31/1994
05 #
06
07 CC = gcc
08 OPTIMIZE = -fomit-frame-pointer -O2 -s
09 CFLAGS = $(DEFINES) $(OPTIMIZE)
10 LFLAGS = -N
11
12 PROGS = cshow
13 PROGS_O = cshow.o
14 LIBS = -lvgagl -lvga
15
16 all: progs
17
18 progs: $(PROGS)
19
20 objs: $(PROGS_O)
21
22 .c.o:
23 $(CC) $(CFLAGS) -c -o $*.o $<
24
25 .c.s:
26 $(CC) $(CFLAGS) S o $*.s $<
27
28 .o:
29 $(CC) $(CFLAGS) $(LFLAGS) o $* $*.o $(LIBS)
30 chmod a+rs,go-w $*
31
32 clean : cleanbin
33 rm f *.o *~
34
35 cleanbin :
36 rm f $(PROGS)
37
38 dep :
39 rm f .depend
40 make .depend
41
42 .depend:
43 echo # Program dependencies>.depend
44 gcc -MM $(patsubst %.o,%.c,$(PROGS_O)) >>.depend
45
46 include .depend

  范例一是笔者的cshow程式的makefile,其中01至05行以#开头作为注解用;
07至 14行是设定变数,其中07-10所设定的是有关编译器及其命令,11至14行则设
定被编 译的档案名称及额外需被连结的程式库名称;第16行便是一个依存规则,
若是我们在 命令列下只打make,那make便会去寻找makefile中的第一个规则来工
作,在此这便是 第一个规则,但这个规则比较特殊:一、本规则并无「命令」,
二、本规则中的all 并不是档名,而且其後的progs是下一条规则(第18行)的「目
标档」,这样一来,当 我们一去make all时,由於all是由progs所构成,因此会
跳到第18行去,而第18行 的$(PROGS)是cshow,为做本make最终产生的档案,为一
可执行档,第20行的cshow.o 便是最终的目的档,那cshow和cshow.o又是如何产生
的?这和第22、25、28行有关, 这几行是利用下一节的「字尾规则」,稍後再论


  范例一中第32和35行是makefile中另外常见的规则,其目的不是「产生」目的
档 ,而是去「删除」某些档案,35行的动作包含在32之中,35行的目的是删除可
执行档 (rm -f $(PROGS));而32行会先执行35行的动作,再去删除*.o和*~的档
;若是我 们更新了一大群source的部份时,最好要make clean,否则仍会发生.
o和其source 间版本不同的错误。

字尾规则
  通常我们会以特定的字尾来表示不同档案的种类,如.c 便是代表c语言的原始
档 , 而.o 通常代表此档经特定的编译程式所产生的目的档,由於在同一系统中
同一语 言原始档的编译程式皆相同,我们便可为这些原始档定出一定的编译方式
,这便是字 尾规则(Suffix rule)的用意所在,字尾规则通常是在於定义
Makefile的内建依存 规则;字尾规则的语法如下:

.字尾一.字尾二:
    命令

  其中的意义是字尾一的档案经「命令」的作用後产生字尾二的档案,如范例一
中 的第22和23行:

22 .c.o:
23 $(CC) $(CFLAGS) -c -o $*.o $<
  这便是一个字尾规则,22阐述.c和.o的关系,23行便是描述.o如何由.c产生,
其 中$*和$<请参考表二的说明,例如有个test.c,在23行展开时便成为:

  gcc -fomit-frame-pointer -O2 -s -c -o test.o test.c

  而且因为$<的关系,若是test.o的时间比test.c还晚,则不进行编译的动作,
这 项特性能节省编译的时间,避免不必要的动作,因为有这项特性,我们更须注
意一件 事:当读者ftp下一个更新的版本至旧有的程式项中时,若是须要重新编译
,在make 之前最好先make clean,免得同一档名的.o虽比.c新,但真正的内容版
本却比.c旧。

  「空字尾」规则是字尾规则的特殊形态,所产生的档案便是依存档去掉字尾的
情 况,一般情况中用於产生最後的可执行档,如范例一中的第28、29及30行,第
29行的 实际作用,便是将.o档连结成最後的档案,第30行再将其权限改变成可执
行的形式。

  第42行也是「空字尾」规则,主要目的在於产生.depend档,在.depend档中记
载 各依存档彼此的关系,make在执行时会参考到此档。

多档案程式
  make有一个很方便的特性是对於多档案的程式,能作完善的管理。所谓的多档
案 程式,就是程式本身由多个.c所组成,只要在makefile中定好档案间的关系,
接下来 就无需挂虑到底那一档需要编译了。对於多档案程式,一般的方式是保留
个别对应到 .c的.o档,连结时再把各个.o连在一起,这个方式的好处在於当修改
了其中之一的.c 後,make便只需重新编译修改过的即可,真是省时又方便,接下
来我们就利用图一的 这个程式来说明。

图一:

main
|
--------------+-------------
| | |
| | |
main.o input.o output.o
| | |
| | |
main.c input.c output.c

  图一是main这个程式的结构,主要由main.o、input.o和output.o组成,
main.o、 input.o和output.o各自依存於如图的叁个.c档,这般的档案结构是很常
见的方式,对 於如此的多档案程式,我们只需修改范例一中的第13行:

  PROGS_O = main.o input.o output.o

  如此一来,make便能自动的决定何时需要、何时不需重新作编译的动作。

核心重组
  Linux本身便附有核心程式的原始码,这使得使用者可以很方便的"制造"出一
个 核心程式出来,尤其是自行更改或是向外取得某部份原始程式後、或是想要更
改对一 些设备的支援时,便是重编核心的时机,"重编核心"好像是一件多麽不同
的事,其实 真正的动作也只是再去编译、连结出一个程式,而且所编连出的核心
,不管是由lilo 或是loadlin.exe所启动,在编译的过程中原来的核心程式并未先
删除,唯有各部份 的程式都编好後才去组成核心程式,所以重编核心这件事是
Linux爱好者所不可放弃 的一件事,因为每台PC的设备并不相同,核心依实际的情
况去芜存菁後,才能发挥最 大的功用。

  当安装了必要的套件後,Linux的核心原始程式放在/usr/src/linux之中,这
儿 linux是一个连结档,连结到不同的版本子目录,要重编核心,需以root签入或
是以 su命令转成root身份,当成为root後,只需键入cd ~/linux便可进入上述的
原始程 式子目录内;自十几年前的CP/M作业系统开始,至今天的DOS、OS/2、
NextStep至於 未来的Windows或是NT,我们一般的使用者很难一窥作业系统的真正
面目,更遑论去 自行修改了,但在此我们见到的是一套有着多人、多工、网路支
援等完整的作业系统 ,同时又紧紧的配合PC的硬体,以PC的观点来发展,这样的
作业系统,怎不令人窝心 呢?而且程式码完全公开,是研究作业系统不可多得的
典范,就是此原因,Linux还 在不断发展中,更重要的一点是使用者再也不是一个
旁观者,若是发现那儿有bug, 更可提笔上阵,自行创作一番。

  在原始程式子目录下,有许多不同的子目录,如BOOT、FS、INIT等,每个子目
录 有着不同功能的source,如FS便是管理File System的部份,对作业系统有兴
趣的读 者我们以後再来专论;由於这儿的的Makefile太过冗长,因此笔者不引述
,若是看不 太懂Makefile的一些Shell Script指令,可以参考陈仁和所着「
Linux管理与操作手 册--Shell的使用」。

  接下来我们便要实际的穿越编译核心,第一步便是以root的身份进入source子
目 录,接下来通常是make clean,作用是删除旧的.o各核心程式及相关档案,若
是之 前并没更改source,此步骤当然可省略;接下来是更改设定,这也是要重编
核心的原 因之一,键入make config後,便会询问一连串的问题,这些问题便是
config.in的 内容.

  整体设定过程可以看得出有些杂乱无章,这是因为Linux所支援的是因应硬体
发 展的结果,所以看得出是叠床架屋的样子,config的结果是设定一些变数以供
make时 使用,在Makefile中可以见到若某些变数存在时便包含入对应的子目录,
在编译时就 会一同处理。

  设定完成後,接下来是建立.depend档,此档记录真正要组成核心的档案间之
依 存关系,而make dep或make depend都可达到相同的目的。

  再过去Linux是由lilo所输入解压缩和启动的,所以直接键入make zlilo便可
, 此时便开始约十到二十分钟的编译,若是想继续工作,可切换到别的console去
,或 者是键入:

  make zlilo & 1>/dev/null 2>/dev/null

将工作送至背景,将讯息抑制。

  除了lilo,我们也可由A磁碟机来启动,这时便需以make zdisk来将核心送到
开 机片上;在光碟月刊八月号上介绍了另一个由DOS来启动的程式loadlin.exe,
而且也 出现了umsdos的安装方式,这对使用者来说是莫大的方便,因为在过去想
安装Linux 的人来说,要重割硬碟是件很不便的事,而且事先旧有的资料要如何处
理也是很伤脑 筋,这使得想认识Linux的人裹足不前,现在不利因素皆已去除,方
便大门已开,读 者可利用八月号的光碟直接安装(不过请先取得Q和U套件),就把
Linux直接装入DOS的 linux子目录,再用开机片开机,对於原来的程式或资料不会
造成损坏,就能使Linux 动起来,若是再利用多重开机和loadlin.exe,在一开机
就能选择作业系统,是再也 方便不过的事了,如果是利用这种方式开机者,重编
核心要利用make zImage来作, 并在组译完成後,将zImage拷到loadlin.exe能读
到的地方,如/dev/hda0/loadlin( Linux和DOS不在同一分割中)或
/DOS/loadlin(使用umsdos),记得要cp过去,不然 重组徒然浪费时间而已。

  Linux是一个极新的领域,其免费、强大的特性,加上源源不断的支援,与其
它 作业系统比较起来丝毫不逊色。多人、多工早就是她的基本功能,图型介面漂
亮又好 用,但Linux并不是完美无瑕,当某天抱怨完不便和缺点後,便是写个程式
「修理」一番的最好时机。

--

※ 来源:·BBS 水木清华站 smth.org·[FROM: 202.116.64.6]
--
※ 转载:·BBS 荔园晨风站 bbs.szu.edu.cn·[FROM: 192.168.1.115]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店