0. 前言
當前開源項目的標準編譯過程已經變成了簡單的三部曲:configure/make/make install,使用起來很方便。維護者不在需要考慮不同編譯環境的問題,也基本上不需要寫太多複雜的Makefile。但是,autotools的工具數量太多,涉及的語言也不少,不可能從頭學到尾。
本文以一個完整的例子,一步步建立了一個基本可用的模板工程。後續項目可以直接使用該工程,並且可以逐步完善自己的需求。
1. 工具介紹
- autoscan: 用來掃描源代碼目錄生成[configure.scan]文件。
- aclocal: 根據configure.in文件的內容,自動生成[aclocal.m4]文件。
- autoheader: 掃描configure.ac中的內容,並確定需要如何生成[config.h.in]。
- autoconf: 在編譯軟件包前執行一系列測試,發現系統的特性,使源碼可以去適應不同系統的差別,增強可移植性。
- automake: 根據[Makefile.am]自動構建[Makefile.in]的工具。極大地簡化了描述軟件包結構及追蹤源碼間依賴關係的過程。
- Libtool: 是編譯器和鏈接器的命令行接口,利用它可以方便地產生具有可移植性的靜態庫和動態鏈接庫。
2. 操作流程
- 調用autoscan腳本,生成[configure.scan]文件,並將該文件重命名爲[configure.ac]。
- 修改[configure.ac],配置項目需要的各種自動化探測項。
- 編寫自定義宏,爲每個宏提供一個單獨的*.m4文件。
- 調用aclocal收集[configure.ac]中用到的各種非autoconf的宏,包括自定義宏。
- 調用autoheader,掃描[configure.ac]、[acconfig.h],生成默認的[config.h.in]宏定義文件。具體文件名稱可以在AC_CONFIG_HEADERS中配置。
- 編寫[Makefile.am]文件,配置編譯目標及其源碼組成。
- 如果[configure.ac]配置了AC_PROG_LIBTOOL或LT_INIT,需要執行libtoolize –automake –copy –force。
- 調用automake –add-miss,將每個Makefile.am轉化成[Makefile.in]。
- 調用autoconf,利用M4解析[configure.ac],生成configure腳本。
基本上只需要修改紅色表示的三個步驟就可以配置好工程,基礎例子可以參見:
3. 常用宏
AC_PREREQ
原型:AC_PREREQ(VERSION)
功能:需要的最低autoconf版本
AC_PREREQ([2.65])
AC_INIT
原型:AC_INIT(PACKAGE, VERSION, BUG-REPORT-ADDRESS)
功能:autoconf初始化。告訴autoconf包名稱,版本,報告bug的Email
AM_INIT_AUTOMAKE
原型:AM_INIT_AUTOMAKE([OPTIONS…])
功能:初始化automake
參數:
參數 | 描述 |
---|---|
-Wall | 打開全部警告 |
-Werror | 將警告當錯誤處理 |
-foreign | 放寬一些GNU標準需求 |
-1.11.1 | 需要automake的最低版本 |
-dist-bzip2 | 在使用make dist和make distcheck期間同時創建tar.bz2存檔 |
-tar-ustar | 使用ustar格式創建tar存檔 |
AM_INIT_AUTOMAKE([foreign -Wall -Werror])
AC_CHECK_HEADERS 或 AC_CHECK_HEADER
原型:
AC_CHECK_HEADERS(HEADERS…)
AC_CHECK_HEADER(HEADER, [ACT-IF-FOUND], [ACT-IF-NOT])
功能:檢查頭文件。代碼中可以使用HAVE_XXX_H的方式檢查該頭文件是否存在
# 配置文件中的定義
AC_CHECK_HEADERS([string.h])
# 代碼中的定義
#if HAVE_STRING_H
#include <string.h>
#else
/* replace header file */
#endif
AC_CONFIG_SRCDIR
原型:AC_CONFIG_SRCDIR ( unique-file-in-source-dir )
功能:確認某些關鍵文件在正確的目錄中
AC_CONFIG_HEADERS
原型:AC_CONFIG_HEADERS(HEADERS…)
功能:創建頭文件
# 創建config.h
AC_CONFIG_HEADERS([config.h])
# 創建config.h, 它的輸入文件是config.h.ini, 在autoheader時被創建
AC_CONFIG_HEADERS([config.h:config.h.ini])
AC_CHECK_PROGS
原型:AC_CHECK_PROGS (variable, progs-to-check-for, [ value-if-not-found ], [ path = ‘$PATH’])
功能:將variable定義爲第一個發現的程序,如果沒有發現就設置爲VAL-IF-NOT-FOUND
# 如果發現tar,gtar,就設置到變量$TAR中,如果沒有發現就設置爲‘:’
AC_CHECK_PROGS([TAR], [tar gtar], [:])
if test "$TAR" = :; then
AC_MSG_ERROR([This package needs tar])
fi
AC_DEFINE
原型:AC_DEFINE(VARIABLE, VALUE, DESCRIPTION)
功能:定義一個宏並輸出到config.h中
注意:該宏是用於生成C語言的宏。如果value是一個shell變量可以使用AC_DEFINE_UNQUOTED
AC_SUBST
原型:AC_SUBST(VARIABLE, [VALUE])
功能:定義一個宏到Makefile中,可以在Makefile.am中以@XXX@的形式使用
AC_CHECK_LIB
原型:AC_CHECK_LIB(LIBRARY, FUNCT, [ACT-IF-FOUND], [ACT-IF-NOT])
功能:檢查庫是否存在並且包括函數FUNCT
AC_CHECK_LIB([efence], [malloc], [EFENCELIB=-lefence])
AC_SUBST([EFENCELIB])
AM_CONDITIONAL
原型:AM_CONDITIONAL(NAME, CONDITION)
功能:執行CONDITION中的shell語句,如果成功則定義變量NAME
# 僅當系統中存在bar.h文件時定義WANT_BAR
AC_CHECK_HEADER([bar.h], [use_bar=yes])
AM_CONDITIONAL([WANT_BAR], [test "$use_bar" = yes])
編譯器和工具檢查
宏 | 功能 |
---|---|
AC_PROG_CC | 檢查C編譯器 |
AC_PROG_CPP | 檢查C++編譯器 |
AC_PROG_INSTALL | 檢查install工具 |
LT_INIT | 檢查libtool |
AC_PROG_SED | 檢查sed工具 |
AC_PROG_YACC | 檢查YACC工具 |
AC_PROG_LEX | 檢查LEX工具 |
錯誤處理
宏 | 功能 |
---|---|
AC_MSG_ERROR | 打印錯誤信息並退出 |
AC_MSG_WARN | 打印錯誤信息但不退出 |
4. 編寫Makefile.am文件
父目錄
使用SUBDIRS = XXX的格式增加子目錄。
子目錄
在autotools中,編譯和安裝的規則是在一起的:安裝目錄_編譯類型=編譯目標
安裝目錄
安裝目錄 | Makefile中的變量 | 使用方式 |
---|---|---|
prefix | 默認/usr/local | 通過–prefix指定 |
exec_prefix | ${prefix} | 同prefix |
bindir | ${exec_prefix}/bin | bin_編譯類型 |
libdir | ${exec_prefix}/lib | lib_編譯類型 |
includedir | ${prefix}/include | include_編譯類型 |
noinstdir | 無 | 不安裝 |
- 設置編譯目標時需要去掉dir後綴
- 如果自定義一個安裝目錄時需要加上dir的後綴
編譯類型
編譯類型 | 說明 | 使用方式 |
---|---|---|
PROGRAMS | 可執行程序 | bin_PROGRAMS |
LIBRARIES | 庫文件 | lib_LIBRARIES |
LTLIBRARIES | libtool庫文件 | lib_LTLIBRARIES |
HEADERS | 頭文件 | include_HEADERS |
SCRIPTS | 腳本文件 | script_SCRIPTS |
DATA | 數據文件 | conf_DATA |
- script_SCRIPTS和conf_DATA中的安裝目錄需要手動配置
編譯目標
參數 | 含義 |
---|---|
_SOURCES | 源代碼文件 |
_LIBADD | 需要鏈接的庫 |
_LDADD | 需要鏈接的庫 |
_LDFLAGS | 對應-L, -l, -shared, -fpic等選項 |
_LIBTOOLFLAGS | libtool編譯時的選項 |
- 編譯選項也可以使用宏AM_CFLAGS進行配置
- 如果你的編譯目標爲lib時,需要使用_LIBADD
- 如果你的編譯目標爲bin時,需要使用_LDADD
5. 進階
安裝配置文件
某些時候,我們需要將一些配置文件安裝到特殊的位置,可以使用下面的方式:
# 定義一個編譯目標,安裝目錄爲conf,編譯類型爲數據文件
confdir = ${exec_prefix}/conf
conf_DATA = utils.conf
詳細的例子可以參見:
打包
缺省情況下打包內容如下:
- 所有源文件。
- 所有[Makefile.am]/[Makefile.in]。
- configure需要讀取的文件。
- [Makefile.am]和[configure.ac]包含的文件。
- 缺省文件,如README,ChangeLog,NEWS,AUTHORS。
如果需要打包其它文件(包括一些庫,特殊的頭文件,配置文件,幫助文件),需要特殊指定:
- 使用EXTRA_DIST來指定。
- 在編譯目標前添加dist或nodist前綴。
詳細的例子可以參見:
爲configure定義特殊接口
- 使用AC_ARG_WITH,添加–with-package參數
- 使用AC_ARG_ENABLE,添加-–enable-feature參數
詳細的例子可以參見:
根據配置編譯不同模塊
- 使用AC_DEFINE或AC_DEFINE_UNQUOTED定義C語言使用的宏
- 使用AM_CONDITIONAL或AC_SUBST定義Makefile使用的宏
詳細的例子可以參見:
配置特殊宏
- 新建一個單獨的目錄,用於存放自定義宏,一般定義爲m4
- 爲每個宏定義一個文件,以.m4結尾
- 使用AC_DEFUN定義具體的宏
- 運行aclocal -Im4生成aclocal.m4
- 在根目錄下的Makefile.am中添加ACLOCAL_AMFLAGS = -I m4
詳細的例子可以參見: