日前處理一件工作,用 C 語言引用另一家廠商提供的 SDK 開發一套小工具。身為一個專業人員,按照 GNU 軟體開發指南,我們的 C 程式碼,應該要透過 Autoconf/Automake 完成建置前的組態工作。於是我進一步地使用 Autoconf 工具完成完成軟體建置環境的檢測與生產的組態文件。
然而我在將第三方廠商的 SDK 檢測動作加入 Autoconf 流程時,碰到了麻煩。為了處理這件事,花了我一整個工作天解決。令我不禁抱怨 GNU Autoconf manual 的內容編排內容實在很糟糕。本文記錄了在 Autoconf 中,如何檢查建置軟體時所需的額外標頭檔與函數庫。
檢測核心與機器規格
Autoconf 以 AC_OUTPUT 定義輸出文件。若我們需要在那些輸出文件中使用變數,則可以用 AC_SUBST 建立輸出變數,那些輸出變數可以在 Autoconf 的輸出文件中,透過 @輸出變數名稱@ 的寫法引用變數內容。AC_SUBST 的第二個參數若省略,表示以內部變數之現值作為輸出變數之值。
下列定義 KERNEL, MACHINE 與 ARCHITECTURE。我先利用 uname
取得核心與 CPU 硬體規格,指派為 KERNEL, MACHINE 之值。再以 AS_IF 判斷 MACHINE 的結果,指派 ARCHITECTURE 之值。因為這三個變數要持續延用於 Makefile.am 中,故再以 AC_SUBST 建立對應的輸出變數。
以 AC_ARG_WITH 指定額外的軟體項目
經常下載 C 程式碼並使用 Autoconf 流程編譯程式碼的人,應該知道有許多案子的 configure 允許我們透過 --with-xxx 的參數,指定額外的項目。當我們編寫 Autoconf 文件時,需用 AC_ARG_WITH 實現這個工作。
假設第三方廠商提供的SDK名稱為 mylib ,我們想要在 configure 中增加一個 --with-mylib 的參數項目,以便他人指定 mylib 的安裝路徑。當我們增加 --with-mylib 選用參數時,Autoconf 會自動在內部定義一個 with_mylib 變數代表它。所以當你下達 configure --with-mylib=/opt/local/mylib
時,在 Autoconf 內部便定義 with_mylib 之值為 /opt/local/mylib 。
AC_CHECK_HEADERS 可以幫我們檢查標頭檔是否可在系統 INCLUDE 路徑中尋獲(預設為 /include:/usr/include)。AC_CHECK_LIB 則幫我們檢查函數庫檔案是否可在系統 LIBRARY 路徑中尋獲(預設為 /lib:/usr/lib)。但當我們的檔案並未被安裝在系統預設路徑時,那兩個巨集就幫不了我們。在此例中,我將 MyLib 安裝在 /usr/local/mylib 。此時我們就必須使用其他較複雜的方式,實現檢查動作。
-
Macro: AC_COMPILE_IFELSE (input, [action-if-true], [action-if-false])
See: Running the Compiler
-
Macro: AC_LINK_IFELSE (input, [action-if-true], [action-if-false])
See: Running the Linker
-
Macro: AC_MSG_RESULT
AC_MSG_RESULT 僅輸出訊息,通常用於成功事件。
-
Macro: AC_MSG_ERROR
AC_MSG_ERROR 在輸出訊息後,會中止 configure 流程,通常用於失敗事件
檢查標頭檔的動作,我使用 AC_COMPILE_IFELSE 即時產生一段引用指定標頭檔的 C 程式碼,交由 Autoconf 調用 C 編譯器編譯。此處的編譯動作會套用我先前定義的 CFLAGS 之值作為編譯時的參數。我在 CFLAGS 中指示了 MyLib 標頭檔的路徑位置,若路徑錯誤,則編譯動作也會失敗,進入失敗處理流程。AC_CHECK_HEADERS 的問題在於它不會套用 CFLAGS 的內容,因此我們才要自行處理。
檢查函數庫檔的動作,我使用 AC_LINK_IFELSE 即時產生一段調用指定函數的 C 程式碼,交由 Autoconf 調用編譯器與連結器。此處的建置動作會套用我先前定義的 CFLAGS, LDFLAGS 與 LIBS 之值作為建置時的參數。若路徑錯誤,則建置動作也會失敗,進而觸入失敗處理流程。
configuer.ac 完整內容
參考文件
相關文章
樂多舊網址: http://blog.roodo.com/rocksaying/archives/12452111.html