歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux綜合 >> Linux資訊 >> Linux文化 >> Make程式和重編核心

Make程式和重編核心

日期:2017/2/27 12:17:38   编辑:Linux文化

  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

  或是可將「命令」寫在下一行,但是需有<TAB>定位字元作為前導,因此可寫成:

  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並不是完美無瑕,當某天抱怨完不便和缺點後,便是寫個程式「修理」一番的最好時機。(Ivor Chen)


摘自:http://www.pocketix.com


Copyright © Linux教程網 All Rights Reserved