makefile寫法
在 Unix 上寫程式的人大概都碰過 Makefile,尤其是用 C 來開發程式的人。用 make來開發和編譯程式的確很方便,可是要寫出一個 Makefile就不簡單了。偏偏介紹 Makefile 的文件不多,GNU Make 那份印出來要幾百頁的文件,光看完 Overview 就快陣亡了,難怪許多 人聞 Unix 色變。
本文將介紹如何利用 GNU Autoconf 及 Automake 這兩套軟體來協助我們『自動』產生 Makefile 檔,並且讓開發出來的軟體可以像 Apache, MySQL 和常見的 GNU 軟體一樣,只要會 ``./configure'', ``make'', ``make install'' 就可以把程式安裝到系統中。如果您有 心開發 Open Source 的軟體,或只是想在 Unix 系統下寫寫程式。希望這份介紹文件能幫助您輕松地進入 Unix Programming 的殿堂。
1. 簡介
Makefile 基本上就是『目標』(target), 『關連』(dependencies) 和『動作』三者所組成的一連串規則。而 make 就會根據 Makefile 的規則來決定如何編譯 (compile) 和連結 (link) 程式。實際上,make 可做的不只是編譯和連結程式,例如 FreeBSD 的 port collect ion 中, Makefile 還可以做到自動下載原始程式套件,解壓縮 (extract) ,修補 (patch),設定,然後編譯,安裝至系統中。
Makefile 基本構造雖然簡單,但是妥善運用這些規則就也可以變出許多不同的花招。卻也因此,許多剛開始學習寫 Makefile 時會感到沒有規范可循,每個人寫出來的 Makefile 長得都不太一樣,不知道從何下手,而且常常會受限於自己的開發環境,只要環境變數不同或路 徑改一下,可能Makefile 就得跟着修改。雖然有 GNU Makefile Conventions (GNU Makefile 慣例) 訂出一些使用 GNU 程式設計時撰寫 Makefile 的一些標准和規范,但是內容很長而且很復雜, 並且經常做些調整,為了減輕程式設計師維護 Makefile 的負擔,因此有了Automake。
程式設計師只需寫一些預先定義好的巨集 (macro),交給 Automake 處理後會產生一個可供Autoconf 使用的 Makefile.in 檔。再配合利用Autoconf 產生的自動設定檔 configure即可產生一份符合 GNU Makefile慣例的 Makeifle 了。
2. 上路之前
在開始試着用 Automake 之前,請先確認你的系統已經安裝以下的軟體: 1. GNU Automake 2. GNU Autoconf 3. GNU m4 4. perl 5. GNU Libtool (如果你需要產生 shared library)
我會建議你最好也使用 GNU C/C++ 編譯器 、GNU Make 以及其它 GNU 的工具程式來做為開發的環境,這些工具都是屬於 Open Source Software不僅免費而且功能強大。如果你是使用Red Hat Linux 可以找到所有上述軟體的 rpm 檔,FreeBSD 也有現成的 package 可以直 接安裝,或着你也可以自行下載這些軟體的原始檔回來 DIY。以下的范例是在 Red Hat Linux 5.2 + CLE2 的環境下所完成的。
3. 一個簡單的例子
Automake 所產生的 Makefile 除了可以做到程式的編譯和連結,也已經把如何產生程式文件(如 manual page, info 檔及 dvi 檔) 的動作,還有把原始程式包裝起來以供散 的動作都考慮進去了,所以原始程式所存放的目錄架構最好符合 GNU 的標准慣例,接下來我拿hello.c 來做為例子。
在工作目錄下建立一個新的子目錄 ``devel'',再在 devel 下建立一個``hello'' 的子目錄,這個目錄將作為我們存放 hello 這個程式及其相關檔案的地方:
% mkdir devel
% cd devel
% mkdir hello
% cd hello
用編輯器寫個 hello.c 檔,
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("Hello GNU!\n");
return 0;
}
接下來就要用 Autoconf 及 Automake 來幫我們產生 Makefile 檔了,
1. 用 autoscan 產生一個 configure.in 的雛型,執行 autoscan 後會產生一個configure.scan 的檔案,我們可以用它做為configure.in檔的藍本。
2. 編輯 configure.scan 檔,如下所示,並且把它的檔名改成configure.in
autoconfig用戶參考手冊 http://www.gnu.org/software/autoconf/manual/autoconf.html
automake用戶參考手冊 http://www.gnu.org/software/automake/manual/automake.html
修改后的configure.in文件內容如下
# cat configure.ac
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.69])
AC_INIT([hello], [1.0.1], [lsgxeva@163.com])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([hello.c])
AC_CONFIG_HEADERS([config.h])
# Checks for programs.
AC_PROG_CC
# Checks for libraries.
# Checks for header files.
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_CONFIG_FILES(Makefile)
AC_OUTPUT
上面以AC開頭的宏來自autoconf,以AM開頭的宏來自automake。要從autoconf或 automake中尋求幫助,這一點很有用。以GNOME開頭的宏來自於Gnomemacros目錄。這些宏都是用m4宏語言寫的。如果將 autoconf和automake安裝在/usr目錄下,autoconf和automake中的標准宏一般放在/usr/share/aclocal 目錄下。
3. 執行 aclocal 和 autoheader ,分別會產生 aclocal.m4 及 configure.h.in 兩個檔案
% aclocal
% autoheader
% ls
aclocal.m4 autom4te.cache autoscan-2.69.log config.h.in configure.ac hello.c
4. 編輯 Makefile.am 檔,內容如下
# cat Makefile.am
AUTOMAKE_OPTIONS = foreign
bin_PROGRAMS = hello
hello_SOURCES = hello.c
hello_CPPFLAGS = -I /usr/include/
5. 執行 automake --add-missing ,Automake 會根據 Makefile.am 檔產生一些檔案,包含最重要的 Makefile.in
% automake --add-missing
configure.ac:11: installing './compile'
configure.ac:6: installing './install-sh'
configure.ac:6: installing './missing'
Makefile.am: installing './depcomp'
6. 執行 autoconf 得到 configure可執行腳本文件
% autoconf
7. 執行測試:
執行./configure
執行 make 此時應該已經生成可執行文件,ls看一下
執行 make install
8. 測試程序:#可執行文件
make clean 清除編譯過程生成的文件
make uninstall 卸載
=========================================================================
1. autoscan
autoscan是 用來掃描源代碼目錄生成configure.scan文件的 .autoscan
可以用目錄名做為參數,但如果你不使用參數的 話,那么autoscan將認為使用的是當前目錄.
autoscan將掃描你所指定目錄中的 源文件,並創建configure.scan文件.
2. configure.scan
configure.scan包含了系統配置的 基本選項,里面都是 一些宏定義.我們需要將它改名為
configure.in
3. aclocal
aclocal是 一個perl 腳本程序.aclocal根據configure.in文件的 內容
,自動生成aclocal.m4文件.aclocal的 定義是 :"aclocal - create
aclocal.m4 by scanning configure.ac".
4. autoconf
autoconf是 用來產生configure文件的 .configure是 一個腳本,它能設置
源程序來適應各種不同的操作系統平台,並且根據不同的 系統來產生合適的 Makefile,從而可以使
你的源代碼能在不同的操作系統平台上被編譯出來.
configure.in文件的 內容是 一些宏,這些宏經過autoconf 處理后會變成檢查系統
特性.環境變量.軟件必須的 參數的 shell腳本.configure.in文件中的 宏的 順序並沒
有規定,但是 你必須在 所有宏的 最前面和最后面分別加上AC_INIT宏和AC_OUTPUT宏.
在 configure.ini中:
#號表示注釋,這個宏后面的 內容將被忽略.
AC_INIT(FILE)
這個宏用來檢查源代碼所在 的 路徑.
AM_INIT_AUTOMAKE(PACKAGE, VERSION)
這個宏是 必須的 ,它描述了我們將要生成的 軟件包的 名字及其版本號:PACKAGE是軟件包
的名字,VERSION是 版本號.當你使用make dist命令時,它會給你生成一個類似
helloworld-1.0.tar.gz的 軟件發行包,其中就有對應的 軟件包的 名字和版本號.
AC_PROG_CC
這個宏將檢查系統所用的 C編譯器.
AC_OUTPUT(FILE)
這個宏是 我們要輸出的 Makefile的 名字.
我們在 使用automake時,實際上還需要用到其他的 一些宏,但我們可以用aclocal 來幫
我們自動產生.執行aclocal后我們會得到aclocal.m4文件.
產生了configure.in和aclocal.m4 兩個宏文件后,我們就可以使用autocon
f來產生configure文件了.
5. Makefile.am
Makefile.am是 用來生成Makefile.in的 ,需要你手工書寫.Makefile.
am中定義了一些內容:
AUTOMAKE_OPTIONS
這個是 automake的 選項.在 執行automake時,它會檢查目錄下是 否存在 標准
GNU軟件包中應具備的各種文件,例如AUTHORS.ChangeLog.NEWS等文件.
我們將其設置成foreign時,automake會改用一般軟件包的 標准來檢查.
bin_PROGRAMS
這個是 指定我們所要產生的 可執行文件的 文件名.如果你要產生多個可執行文件,
那么在各個名字間用空格隔開.
helloworld_SOURCES
這個是 指定產生"helloworld"時所需要的 源代碼.如果它用到了多個源文件,
那么請使用空格符號將它們隔開.比如需要helloworld.h,helloworld.c那么請寫成:
helloworld_SOURCES= helloworld.h helloworld.c.
如果你在 bin_PROGRAMS定義了多個可執行文件,則對應每個可執行文件都要定義相對的
filename_SOURCES.
6. automake
我們使用automake --add-missing來產生Makefile.in.
選項--add-missing的 定義是 "add missing standard files
to package",它會讓automake加入一個標准的 軟件包所必須的 一些文件.
我們用automake產生出來的 Makefile.in文件是 符合GNU Makefile慣例
的 ,接下來我們只要執行configure這個shell 腳本就可以產生合適的 Makefile 文
件了.
7. Makefile
在 符合GNU Makefiel慣例的 Makefile中,包含了一些基本的 預先定義的 操作:
make
根據Makefile編譯源代碼,連接,生成目標文件,可執行文件.
make clean
清除上次的 make命令所產生的 object文件(后綴為".o"的 文件)及可執行文件.
make install
將編譯成功的 可執行文件安裝到系統目錄中,一般為/usr/local/bin目錄.
make dist
產生發布軟件包文件(即distribution package).這個命令將會將可執行文件及相關
文件打包成一個tar.gz壓縮的 文件用來作為發布軟件的 軟件包.
它會在 當前目錄下生成一個名字類似"PACKAGE-VERSION.tar.gz"的 文件.PA
CKAGE和VERSION,是 我們在 configure.in中定義的 AM_INIT_AUTOM
AKE(PACKAGE, VERSION).
make distcheck
生成發布軟件包並對其進行測試檢查,以確定發布包的正確性.
=========================================================================