原文地址:Advanced GTK Techniques。
這篇教程中你將學(xué)會:
- 生成指定那些文件參加編譯的
Makefile
文件骨宠;
- 檢查程序所需庫纵装。
這篇文章是《如何開始一個真正的 GTK 項(xiàng)目》的一部分,如果你不想回看之前的章節(jié)沪摄,可以直接下載教學(xué)示例程序
app-skeleton1
躯嫉。你也可以從頭開始纱烘。
現(xiàn)在我們把注意力放在 Automake
上,這是編譯系統(tǒng)中另一個重要成員祈餐。我們配置好 Automake
后擂啥,就可以開始編寫代碼。
Make
是一個程序帆阳,它從文件 Makefile
中讀取如何編譯源代碼的指令哺壶,然后將代碼轉(zhuǎn)換成可執(zhí)行文件。Makefile
的內(nèi)容取決于使用何種編譯器蜒谤,何種系統(tǒng)山宾,以及很多其它事項(xiàng)。如果你希望實(shí)現(xiàn)在之前章節(jié)描述的所有標(biāo)準(zhǔn) make target
內(nèi)容鳍徽,那么 Makefile
將會變得很長资锰。
這便是引入 Automake
的原因。Automake
可以讓這一切更加簡潔阶祭、抽象绷杜,并且不受平臺的限制。Automake
會尋找一個名為 Automake.am
的文件濒募,將其轉(zhuǎn)譯為一個類似于 Makefile
的文件:Makefile.in
鞭盟。隨后,在運(yùn)行 configure
時瑰剃,它會最終轉(zhuǎn)化為 Makefile
齿诉。
創(chuàng)建 Makefile.am
我們首先完整拷貝一份 app-skeleton1
目錄,將它命名為 app-skeleton2
晌姚,或者直接重命名目錄亦可粤剧。我們當(dāng)前只需要在 Makefile.am
中添加一行:
# app-skeleton2/Makefile.am
SUBDIRS = src
SUBDIRS
變量告訴 Automake
需要在子目錄 src
中查找另外一個 Makefile.am
。最終生成的 Makefile
也會相應(yīng)地在 src
中查找另外一個 Makefile
舀凛。
Make 的遞歸
Peter Miller 曾有一篇著名的文章給出了對編寫遞歸
Makefile
的看法:《遞歸編寫 Make 是有害的》俊扳。建議閱讀一下這篇文章,也可以聽取其中一些你認(rèn)為有用的觀點(diǎn)猛遍。他的實(shí)現(xiàn)方法并不比本文的方法簡單多少馋记。事實(shí)上,在實(shí)際應(yīng)用中懊烤,大多數(shù)工程使用了遞歸式的Make
梯醒,所以至少你應(yīng)當(dāng)熟悉這種做法。
我們已經(jīng)告知了 Automake
進(jìn)入 src
目錄腌紧,那么我們也應(yīng)該在目錄中準(zhǔn)備一些讓它能用得上的東西茸习。創(chuàng)建一個 Makefile.am
是肯定的,此外還需要一些更重要的東西 —— 源代碼文件壁肋。在下一章節(jié)我們才會開始正式的編程工作号胚,現(xiàn)在可以先找個差不多的文件湊數(shù)籽慢。從 GTK 官方教程中拿來 “Hello World” 的例程不失為簡單快捷的辦法,我們不需要從網(wǎng)頁中手動復(fù)制猫胁,只需要 cd src
后拷貝一份即可:
wget http://git.gnome.org/browse/gtk+/plain/examples/hello-world.c
現(xiàn)在我們在 src
中創(chuàng)建 Makefile.am
箱亿,并在文件中輸入以下內(nèi)容:
#app-skeleton2/src/Makefile.am
bin_PROGRAMS = app-skeleton
app_skeleton_SOURCES = hello-world.c
Automake
的主要工作是設(shè)定變量,SUBDIRS
是其中一個案例弃秆。很多 Automake
變量的名稱由兩部分組成届惋,舉個例子,一個名為 something_PROGRAMS
的變量表示一個列表菠赚,包含了需要由 Automake
生成的可執(zhí)行文件的名稱脑豹。something
表示運(yùn)行 make install
時程序的安裝位置,所以 bin_PROGRAMS = app-skeleton
說明了 Automake
生成的 Makefile
將把 app-skeleton
安裝在 /usr/local/bin
中(你也可以把 bin
換成其它名稱衡查,Makefile
可通過 configure
靈活定制瘩欺,這一點(diǎn)可參閱之前的教程)。
順著這種命名的思路拌牲,app_skeleton_SOURCES = hello-world.c
表示名為 app-skeleton
的程序編譯依賴的源文件為 hello-world.c
击碗,也就是我們剛剛下載的文件(如果程序名包含了變量不允許的字符,Automake
將把它變?yōu)橄聞澗€)们拙。
我們還需要讓 configure
幫我們把剛才編寫好的文件轉(zhuǎn)換成一個新的 Makefile
。我們把 configure.ac
中的 AC_CONFIG_FILES
替換成:
#app-skeleton2/configure.ac
AC_CONFIG_FILES([
Makefile
src/Makefile
])
最后阁吝,我們還需要指派 configure
去找一個合適的 C 編譯器砚婆,在 AM_INIT_AUTOMAKE
后面加上一句 AC_PROG_CC
即可(CC
表示 C Compiler,Linux 中一般為為 gcc
)突勇。
現(xiàn)在装盯,運(yùn)行 autoreconf
和 ./configure
。configure
的輸出將比之前的略長(你可以看到它在尋找一個 C 編譯器)甲馋,并且會有更多文件產(chǎn)生埂奈。到目前為止,一切運(yùn)行良好定躏。不過當(dāng)你運(yùn)行 make
時账磺,會收到滿屏的錯誤:所有的 GTK 函數(shù)都未定義,編譯器也找不到 gtk/gtk.h
頭文件痊远。
引入 GTK 庫
我們需要指定哪些庫將被程序使用垮抗。這個工作在 configure.ac
中完成,然后 configure
會去查找這些庫并將它們的變量放入 Makefile
中碧聪。借此機(jī)會冒版,我們可以重新組織 configure.ac
,還能學(xué)習(xí)一些新的宏逞姿。
現(xiàn)在將 configure.ac
分成四個部分:
初始化:完成初始化編譯系統(tǒng)的準(zhǔn)備工作辞嗡;
工具箱:告訴
Autoconf
我們需要使用哪些工具捆等。configure
會幫我們查找這些工具,如果沒有找到便會報錯续室;庫:在此列出需要用到的庫栋烤。同樣地,如果
configure
沒有找到猎贴,它就會報錯班缎;輸出:輸出上述檢測的結(jié)果以供
make
使用。
注釋
你可以在
configure.ac
或者Makefile.am
中使用注釋她渴,在一行的開頭輸入 “#” 即可达址。configure.ac
中也可以為在一行開頭輸入 “dnl”(Delete until New Line)。二者的區(qū)別在于 “dnl” 會被Autoconf
完全忽略趁耗,而 “#” 會被一同拷貝進(jìn)configure
文件中沉唠。當(dāng)configure
中出現(xiàn)錯誤時,注釋有助于我們在configure.ac
中快速定位引起錯誤的部分苛败。
在“初始化”部分满葛,輸入:
# app-skeleton2/configure.ac
AC_INIT([App Skeleton], [2], [philip.chimento@gmail.com])
AC_CONFIG_SRCDIR([src/hello-world.c])
AM_INIT_AUTOMAKE([-Wall foreign])
AM_SILENT_RULES([yes])
我們將版本號改為 2,此外還有兩個新的宏:
-
AC_CONFIG_SRCDIR
這是一個安全行檢查罢屈,用于確認(rèn)其所指定位置確有一個
hello-world.c
嘀韧。我們需要把它的參數(shù)設(shè)定為項(xiàng)目中一個獨(dú)一無二的代碼文件,這里我們寫上目前唯一的代碼文件缠捌。 -
AM_SILENT_RULES
生成
Makefile
的過程通常產(chǎn)生非常長的信息锄贷,我們一般不需要看這么多,而且大量無用的信息刷屏可能會讓你忽視夾在其中的警告和錯誤信息曼月。AM_SILENT_RULES([yes])
將屏蔽這些消息谊却,只輸出一些總結(jié)信息。一個真正的程序員可能會使用AM_SILENT_RULES([no])
哑芹,然后運(yùn)行./configure --enable-silent-rules
來保證政治正確性炎辨。如果你開啟了靜默模式,但還是希望能檢查所有輸出信息聪姿,可以使用
make V=1
命令(V
表示 Verbose)碴萧。
在“工具箱”部分,輸入
# app-skeleton2/configure.ac
AC_PROG_CC
PKG_PROG_PKG_CONFIG
這里有一個新的宏 PKG_PROG_PKG_CONFIG
末购,它會在項(xiàng)目中加入用于檢查和引用庫的工具 —— pkg-config
勿决。這個宏并非 AC_
或者 AM_
開頭,而是 PKG_
招盲,說明這是一個由 pkg-config
提供的功能低缩。
在“庫”部分,我們用 pkg-config
引入我們需要的庫:
# app-skeleton2/configure.ac
PKG_CHECK_MODULES([APP_SKELETON], [
glib-2.0
gtk+-3.0
])
PKG_CHECK_MODULES
的第一個參數(shù) APP_SKELETON
為程序名,第二個參數(shù)列出了一系列 pkg-config 模塊
咆繁。一個模塊代表了 pkg-config
可以識別的一個庫讳推。這個宏使用 pkg-config
查找計(jì)算機(jī)中的庫愕鼓,然后生成兩個變量:APP_SKELETON_CFLAGS
—— 包含了庫的引用信息(類似于 gcc
中的 -I
參數(shù))露懒;APP_SKELETON_LIBS
—— 包含了庫的鏈接信息(類似于 gcc
中的 -L
和 -l
參數(shù))窃肠。這些變量可用于 Makefile
的編輯兽间。
這個宏表示我們將使用 glib-2.0
和 gtk+-3.0
兩個庫。如果你不知道需要用到庫的模塊名日裙,可以到 /usr/share/pkgconfig
和 /usr/lib/pkgconfig
中查找以 .pc
結(jié)尾的文件(譯者注:也可以在終端中輸入 pkg-config --list-all 查看
)弦疮。一些庫并不能用 pkg-config
引入阻肩,而是需要其它的方法匀伏,我們在這里不做介紹洒忧。
最后的“輸出”部分與之前相同:
# app-skeleton2/configure.ac
AC_CONFIG_FILES([
Makefile
src/Makefile
])
AC_OUTPUT
全部搞定后,我們在 src/Makefile.am
中使用由 pkg-config
生成的 APP_SKELETON_CFLAGS
和 APP_SKELETON_LIBS
變量:
# app-skeleton2/src/Makefile.am
AM_CFLAGS = $(APP_SKELETON_CFLAGS)
bin_PROGRAMS = app-skeleton
app_skeleton_SOURCES = hello-world.c
app_skeleton_LDADD = $(APP_SKELETON_LIBS)
AM_CFLAGS
中的定義將會應(yīng)用到這個 Makefile.am
文件里的所有編譯指令中够颠。相反地熙侍,app_skeleton_LDADD
變量只會在鏈接 app-skeleton
程序時被使用。
譯者注:原文作者使用了簡便的引用庫方法:將所有用到的庫綁定到
APP_SKELETON
變量中履磨。其實(shí)蛉抓,更為穩(wěn)妥的做法應(yīng)該為將每個庫分離對待,這樣有利于模塊的靈活調(diào)用剃诅。具體做法為修改configure.ac
中的PKG_CHECK_MODULES
宏:
#app-skeleton2/configure.ac
PKG_CHECK_MODULES([GLIB], [
glib-2.0
])
PKG_CHECK_MODULES([GTK], [
gtk+-3.0
])
然后修改
src/Makefile.am
中相關(guān)的變量:
# app-skeleton2/src/Makefile.am
bin_PROGRAMS = app-skeleton
app_skeleton_SOURCES = hello-world.c
app_skeleton_CFLAGS = \
$(GLIB_CFLAGS) \
$(GTK_CFLAGS)
app_skeleton_LDADD = \
$(GLIB_LIBS) \
$(GTK_LIBS)
在大型項(xiàng)目中往往會生成多個可執(zhí)行文件或庫文件巷送,這樣也利于分別為每個目標(biāo)設(shè)定
cflags
和libs
標(biāo)簽,更加清晰易讀矛辕。
現(xiàn)在我們再次編譯惩系,這次應(yīng)該就能正常工作了。注意這次編譯我們只需要輸入 make
即可如筛,Makefile
(現(xiàn)在是 22 KB 了)會在檢測到 configure.ac
被修改后自動執(zhí)行 ./configure
,同時也生成了新的自己抒抬。
你現(xiàn)在可以運(yùn)行 app-skeleton
來看看程序的效果:一個包含了一個按鈕控件的窗口杨刨,按鈕上寫著“Hello World”,按下之后會在終端打印“Hello World”并退出擦剑。
現(xiàn)在我們已經(jīng)有了像模像樣的編譯系統(tǒng)妖胀,接下來還有一些基礎(chǔ)工作等待著我們?nèi)ネ瓿桑喊惭b和翻譯。
文章許可協(xié)議:Attribution-NonCommercial-ShareAlike 3.0 Unported