這只是入門,僅僅是入門而已。對於內容有任何意見,也歡迎指教。本文件由 陳雍穆( armor ; armor AT netlab Dot cse Dot yzu Dot edu Dot tw )所作。 作者許可本文件於網路上自由流傳,但保留其它之著作權力。 你可以自由的散佈及使用本文件,只要這份聲明和作者的名字跟本文件不被分割開來, 並且這份聲明不被做任何的修改。

Abstract

 

各位修計網的學弟妹,現在大家一定面臨到如何在 Unix 下快速開發程式的問題。在 Unix 系統上 寫C語言程式,根據老祖宗教科書的說法,都會要求模組化、分檔、註解,沒有人要看一個數十萬行的 main 函式。但是使用模組化、分檔撰寫程式,又要如何 compile 這些零零碎碎的檔案。如圖一所示, 檔案少的時候還可以這樣熱血一下,將執行檔 server 和 client 與各個 .o 檔編出來。但是如果手上的 project 是一個數百個分散的檔案時,這樣的作法並不是明智之舉。

 


圖一


圖二

 

在Unix系統上,有一個叫做make的工具,可以協助我們來開發和編譯程式,如圖二所示,只要打一個 make 指令就可以把圖一中數行的指令一次做完。不過要寫出一個 Makefile 就不是容易的事了,單是 GNU 本身的 manual ,看到就快打 退堂鼓了。雖然在資工繫上有一份留傳久遠的 文件,大部分的人照著畫葫蘆也可以做一個漂亮的 Makefile ,但是總覺得要考慮一堆 "TAB" 就是麻煩的一件事。又如果我們的程式需要使用到各種不同的函式庫時, 當程式被移到另一部機械上,要檢查這部機械有沒有這些函式庫還是一個大問題。於是乎, GNU 當然有更好用的 工具來解決這些問題,那就是 autoconf automake 。 有了這些工具,要進入 Unix Programming 的殿堂,可就是件輕鬆的事了。

 

Pre-requisite

 
在進入如何使用 automake 之前,大家最好先瞭解一下 Makefile 是什麼東西。 Makefile 就是告訴 make 如何 compile 和 link 一個程式的檔案。 一個基本的 Makefile 格式如下:
target ... : prerequisites ...
command ... ...

 

  • target ( 目標 ):是一個由程式產生的檔案,他可以是一個執行檔,或是一個目的檔。target也可以是一作用的名稱,例如 clean 或 install 。

     

  • prerequisite ( 必備檔案 ):一些能建立 target 的程式檔案,一個 target 通常由數個檔案建立。

     

  • command ( 命令列 ):描述 make 要執行的動作。由一個或一個以上的 tab ( 4個字元空白 )開頭。

     

  • 註解:在 Makefile 中,以"#"為開頭的的文字皆為註解,在 make 工作時會忽略他們。

     

  • 多行描述:在寫 Makefile 中,如果命令長度超過一行時,可以在該行的最後加上反斜線( )表示下一行為本行之延續,兩行應視為一行來處理。

     

  • macro ( 巨集 ):在 GNU mamual 中寫到,一個 variable 是在 Makefile 中定義一個字串或一段文字的名稱, 通常代替一段作用在targets, prerequisites, commands 上,複雜且詳細的命令。在某些版本的 make 中,variables 稱做 macros 。 macro巨集的格式如下
    <string> = <value>
 

下面是幾個 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

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

範例二:

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 : 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 $(objects)

有關Makefile的詳細說明,可以參考網路上其他的文件。

 

在進入下一個章節前,先檢查你的系統已經安裝以下的軟體:

 

你可以在shell下鍵入指令 whereis XXXX ,來尋找你要的XXXX。EX: whereis gcc 。如下圖。

 

你可以使用各套件所包好的 binary 檔或是 source code 安裝。以下四套 Linux 套件都可以在 ftp://ftp.yzu.edu.tw/pub3/Linux/iso-image 下載光碟燒錄檔。

名稱 製作公司 網頁
RedHat Linux Red Hat www.redhat.com
Slackware Linux Patrick Volkerding www.slackware.com
Debian GNU/Linux GNU www.debian.org
Linux-Mandrake Mandrake soft www.linux-mandrake.com
 

Example

 
本章節提供一個使用automake的過程給大家參考。automake有許多參數設定,我們裡面只簡單使用幾個,其他詳細的部分,還是要 各位去翻閱 GNU automake manual 和 GNU autoconf manual

 

當我們已經寫好一組程式後,希望使用 automake 來替我們把 Makefile 做好。如圖三所示,在這組範例程式裡, 總共有 client.c client.h gettime.c gettime.h gmt2local.c gmt2local.h inits.c inits.h server.c config.h 十個檔案。程式主要產生一個 client 和 server 的執行檔,做網路傳輸。圖中的 Makefile.OLD.TXT 是舊的 Makefile ,在這裡我們不會用到他。

 


圖三


圖四

第一步:使用 autoscan 產生一個 configure.scan ,把他更名成 configure.in 。如圖三、圖四所示。

第二步:修改 configure.in 的內容。由 autoscan 產生的預設檔並不一定一樣,隨系統套件廠商的修改而不同。下面圖五是本範例產生的 預設 configure.in 檔,圖六是修改過的 configure.in 檔。

 


圖五


圖六

在改過的 configure.in 檔,我們加入了 AM_INIT_AUTOMAKE(s907441, 1.0) 與 AC_PROG_CC ,並更改了 AC_OUTPUT(Makefile) 。

  • AC_INIT(FILE) :autoscan 自行產生的,不要修改。
  • AM_INIT_AUTOMAKE(PACKAGE,VERSION) :這是必備的巨集,PACKAGE 是我們所要產生軟體套件的名稱,VERSION是版本編號,加在 AC_INIT(FILE) 後面。
  • AC_PROG_CC :檢查系統的 C compiler 。
  • AC_OUTPUT(FILE) :Automake 使用這個設定來決定要產生什麼檔案。我們要產生 Makefile 所以填入 Makefile 。
  • 以 dnl 開頭的都是註解。
 

這次作業上傳是使用學號當檔名,所以我們把 AM_INIT_AUTOMAKE(PACKAGE,VERSION) 的 PACKAGE 設定為學號, VERSION 設定為版本。換句話說,如何在作業繳交期限前有更動 作業版本,就把 VERSION 加 1 ,再執行下面的其他步驟。其他參數的設定,參考GNU autoconf manual

第三步:執行 aclocal 和 autoconf ,分別會產生 aclocal.m4 及 configure 兩個檔案,如圖七。


圖七

第四步:使用編輯器,建立 Makefile.am 檔,內容如圖八所示。


圖八

 

  1. AUTOMAKE_OPTIONS= foreign

    AUTOMAKE_OPTIONS 所記錄的是嚴謹度。主要是訂定一個套件是否符合 GNU 標準的條件。預設值是 GNU ,這樣一來 整個 package 就要有一些 GNU規定的檔案存在,例如 INSTALL , NEWS , README , COPYING , AUTHORS , and ChangeLog 檔等。 foreign 是比較寬鬆的等級,只確定設定檔能完整的工作。

     

  2. bin_PROGRAMS= client server

    bin_PROGRAMS 是決定要產生的執行檔檔名。如果要產生多個執行檔,每個檔名用空白字元隔開。換句話說,可以對應到我們上一個章節所講的 target 來理解。

     

  3. client_SOURCES= client.c config.h

    這裡就比較明顯,foo_SOURCES 跟上一個章節所講的 prerequisite 對應,這樣大家瞭解了吧!!而在這裡也可以使用巨集來工作。

    xs = a.c b.c
    foo_SOURCES = c.c $(xs)
    automake 會將 $(xs) 換成 a.c b.c ,整個 foo_SOURCES = c.c a.c b.c 。

     

  4. server_SOURCES= server.c config.h gettime.c gettime.h gmt2local.c gmt2local.h inits.c inits.h

    同上

     

第五步:使用 automake --add-missing 將 Makefile.in 產生出來,如圖九所示。 automake 會根據 Makefile.am , 同時 scan configure.in 檔,來產生對應的Makefile.in 。

 


圖九

第六步:執行 ./configure ,我們可以看到 automake 強大的功能,他會去 check 一堆 header 檔、 function call 、 compiler 等等,如圖十所示。此時我們期望已久的 Makefile 就產生了。 configure 檢查 header 的動作是根據configure.in裡面所設定的 AC_CHECK_HEADERS( ) 和AC_CHECK_FUNCS( ) 裡面所設定的內容來 check 。


圖十

第七步:執行 make ,讓 make 根據 Makefile 來 compile 和 link 程式,如圖十一所示。而完成狀況 如圖十二所示,已經可以看到執行檔 client 和 server 。


圖十一


圖十二


Detail

本段補充前幾章零碎缺漏的部分。

A. 用 automake 所產生的 Makefile 檔案提供了那些功能。

 

  • make all

與直接使用 make 指令相同。

  • make clean

清除所有的執行檔與目的檔 ( .o )如圖十三。


圖十三
  • make distclean

make clean 加上把 ./configure 產生的 Makefile 等檔案刪除,如圖十四。 


圖十四
  • make install

把編譯好的執行檔安裝到系統目錄中。預設會放到 /usr/local/bin 裡面。我們可以用 ./configure --help 看到在 Configuration 的設定項目中,prefix 是設成 /usr/local , bindir 就是 EPREFIX/bin ,EPREFIX 又跟 prefix 相同。如果我們在執行 ./configure 產生 Makefile 檔時沒有指定目錄,預設就是這些。 所以,我們也可以根據 ./configure 時使用的參數,來改變程式最後要安裝的目錄。 ./configure --prefix=PREFIX , PREFIX 就是你想安裝的目錄。 ./configure --prefix=/www ,就是 把程式執行檔裝到 /www 去。

 

  • make dist

將程式和相關的檔案包裝成一個 tar.gz 的壓縮檔。這個 tar.gz 檔根據在 configure.in 裡, AM_INIT_AUTOMAKE(PACKAGE,VERSION) 填寫的 PACKAGE 和 VERSION 對應欄位建立。 檔名為 package-version.tar.gz ,如圖十五。 


圖十五

 

  • make distcheck

make dist 加上檢查產生的 tar.gz 檔是否能正常工作。包括解開 tar.gz , ./configure , make all 。 經檢查過的 tar.gz 就可以提供散播 (distribution) ,如圖十六。

 


圖十六

 

B. 準備散佈的套件換到另一個平台能不能執行。

 

configure 是一個 shell script,它可以在一般 Unix 的 sh 這個 shell 下執行,而其他的 install-sh , missing , mkinstalldirs 也都是 shell script 。所以很難有問題產生。

C. 更新的程式組如何重新包裝。

  1. make distclean
  2. 修改configure.in 裡的 AM_INIT_AUTOMAKE(PACKAGE,VERSION) 中的VERSION。
  3. aclocal
  4. autoconf
  5. 建立 Makefile.am 檔
  6. automake --add-missing
  7. make distcheck
 

D. 更新的程式組如何測試。

這是有點笨的問題,如果只是 function 小部分修改,直接重新 make 看看 gcc 回應的資料就知道。 如果大到翻修結構,增減檔案,那還是重頭 run 一次,翻新 Makefile吧。
 

Future

 
其他還有許多功能與設定,例如使用其他的 compiler ( C++ / Assembly / Fortran 77 / Java / Yacc and Lex )、多層目錄的設定、建立 shared library 、各種巨集的使用等等,這些東西並非一時間就可以完全 寫成稿 ( 跟翻譯 manual 差不多 )。其他部分,就有待各位自行 K 手冊了。
arrow
arrow
    文章標籤
    Makefile autotools
    全站熱搜

    Bluelove1968 發表在 痞客邦 留言(0) 人氣()