[譯文] 如何開始一個真正的 GTK 項目(第三部分:配置 Automake)

原文地址:Advanced GTK Techniques。


這篇教程中你將學(xué)會:

  • 生成指定那些文件參加編譯的 Makefile 文件;
  • 檢查程序所需庫。

這篇文章是《如何開始一個真正的 GTK 項目》的一部分,如果你不想回看之前的章節(jié),可以直接下載教學(xué)示例程序 app-skeleton1。你也可以從頭開始。


現(xiàn)在我們把注意力放在 Automake 上,這是編譯系統(tǒng)中另一個重要成員。我們配置好 Automake 后,就可以開始編寫代碼。

Make 是一個程序,它從文件 Makefile 中讀取如何編譯源代碼的指令,然后將代碼轉(zhuǎn)換成可執(zhí)行文件。Makefile 的內(nèi)容取決于使用何種編譯器,何種系統(tǒng),以及很多其它事項。如果你希望實現(xiàn)在之前章節(jié)描述的所有標(biāo)準 make target 內(nèi)容,那么 Makefile 將會變得很長。

這便是引入 Automake 的原因。Automake 可以讓這一切更加簡潔、抽象,并且不受平臺的限制。Automake 會尋找一個名為 Automake.am 的文件,將其轉(zhuǎn)譯為一個類似于 Makefile 的文件:Makefile.in。隨后,在運行 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 是有害的》。建議閱讀一下這篇文章,也可以聽取其中一些你認為有用的觀點。他的實現(xiàn)方法并不比本文的方法簡單多少。事實上,在實際應(yīng)用中,大多數(shù)工程使用了遞歸式的 Make,所以至少你應(yīng)當(dāng)熟悉這種做法。

我們已經(jīng)告知了 Automake 進入 src 目錄,那么我們也應(yīng)該在目錄中準備一些讓它能用得上的東西。創(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 表示運行 make install 時程序的安裝位置,所以 bin_PROGRAMS = app-skeleton 說明了 Automake 生成的 Makefile 將把 app-skeleton 安裝在 /usr/local/bin 中(你也可以把 bin 換成其它名稱,Makefile 可通過 configure 靈活定制,這一點可參閱之前的教程)。

順著這種命名的思路,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)在,運行 autoreconf./configure。configure 的輸出將比之前的略長(你可以看到它在尋找一個 C 編譯器),并且會有更多文件產(chǎn)生。到目前為止,一切運行良好。不過當(dāng)你運行 make 時,會收到滿屏的錯誤:所有的 GTK 函數(shù)都未定義,編譯器也找不到 gtk/gtk.h 頭文件。

引入 GTK 庫

我們需要指定哪些庫將被程序使用。這個工作在 configure.ac 中完成,然后 configure 會去查找這些庫并將它們的變量放入 Makefile 中。借此機會,我們可以重新組織 configure.ac,還能學(xué)習(xí)一些新的宏。

現(xiàn)在將 configure.ac 分成四個部分:

  • 初始化:完成初始化編譯系統(tǒng)的準備工作;

  • 工具箱:告訴 Autoconf 我們需要使用哪些工具。configure 會幫我們查找這些工具,如果沒有找到便會報錯;

  • 庫:在此列出需要用到的庫。同樣地,如果 configure 沒有找到,它就會報錯;

  • 輸出:輸出上述檢測的結(jié)果以供 make 使用。

注釋

你可以在 configure.ac 或者 Makefile.am 中使用注釋,在一行的開頭輸入 “#” 即可。configure.ac 中也可以為在一行開頭輸入 “dnl”(Delete until New Line)。二者的區(qū)別在于 “dnl” 會被 Autoconf 完全忽略,而 “#” 會被一同拷貝進 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

    這是一個安全行檢查,用于確認其所指定位置確有一個 hello-world.c。我們需要把它的參數(shù)設(shè)定為項目中一個獨一無二的代碼文件,這里我們寫上目前唯一的代碼文件。

  • AM_SILENT_RULES

    生成 Makefile 的過程通常產(chǎn)生非常長的信息,我們一般不需要看這么多,而且大量無用的信息刷屏可能會讓你忽視夾在其中的警告和錯誤信息。AM_SILENT_RULES([yes]) 將屏蔽這些消息,只輸出一些總結(jié)信息。一個真正的程序員可能會使用 AM_SILENT_RULES([no]),然后運行 ./configure --enable-silent-rules 來保證政治正確性

    如果你開啟了靜默模式,但還是希望能檢查所有輸出信息,可以使用 make V=1 命令(V 表示 Verbose)。

在“工具箱”部分,輸入

# app-skeleton2/configure.ac
AC_PROG_CC
PKG_PROG_PKG_CONFIG

這里有一個新的宏 PKG_PROG_PKG_CONFIG,它會在項目中加入用于檢查和引用庫的工具 —— 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 查找計算機中的庫,然后生成兩個變量:APP_SKELETON_CFLAGS —— 包含了庫的引用信息(類似于 gcc 中的 -I 參數(shù));APP_SKELETON_LIBS —— 包含了庫的鏈接信息(類似于 gcc 中的 -L-l 參數(shù))。這些變量可用于 Makefile 的編輯。

這個宏表示我們將使用 glib-2.0gtk+-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_CFLAGSAPP_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 變量中。其實,更為穩(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)

在大型項目中往往會生成多個可執(zhí)行文件或庫文件,這樣也利于分別為每個目標(biāo)設(shè)定 cflagslibs 標(biāo)簽,更加清晰易讀。

現(xiàn)在我們再次編譯,這次應(yīng)該就能正常工作了。注意這次編譯我們只需要輸入 make 即可,Makefile (現(xiàn)在是 22 KB 了)會在檢測到 configure.ac 被修改后自動執(zhí)行 ./configure,同時也生成了新的自己。

你現(xiàn)在可以運行 app-skeleton 來看看程序的效果:一個包含了一個按鈕控件的窗口,按鈕上寫著“Hello World”,按下之后會在終端打印“Hello World”并退出。

現(xiàn)在我們已經(jīng)有了像模像樣的編譯系統(tǒng),接下來還有一些基礎(chǔ)工作等待著我們?nèi)ネ瓿桑喊惭b和翻譯。


文章許可協(xié)議:Attribution-NonCommercial-ShareAlike 3.0 Unported

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容