Autotools基礎使用

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. 操作流程

Autotools_Sequence

  1. 調用autoscan腳本,生成[configure.scan]文件,並將該文件重命名爲[configure.ac]。
  2. 修改[configure.ac],配置項目需要的各種自動化探測項。
  3. 編寫自定義宏,爲每個宏提供一個單獨的*.m4文件。
  4. 調用aclocal收集[configure.ac]中用到的各種非autoconf的宏,包括自定義宏。
  5. 調用autoheader,掃描[configure.ac]、[acconfig.h],生成默認的[config.h.in]宏定義文件。具體文件名稱可以在AC_CONFIG_HEADERS中配置。
  6. 編寫[Makefile.am]文件,配置編譯目標及其源碼組成。
  7. 如果[configure.ac]配置了AC_PROG_LIBTOOL或LT_INIT,需要執行libtoolize –automake –copy –force。
  8. 調用automake –add-miss,將每個Makefile.am轉化成[Makefile.in]。
  9. 調用autoconf,利用M4解析[configure.ac],生成configure腳本。

基本上只需要修改紅色表示的三個步驟就可以配置好工程,基礎例子可以參見:

Basic Project

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

詳細的例子可以參見:

install config file

打包

缺省情況下打包內容如下:

  • 所有源文件。
  • 所有[Makefile.am]/[Makefile.in]。
  • configure需要讀取的文件。
  • [Makefile.am]和[configure.ac]包含的文件。
  • 缺省文件,如README,ChangeLog,NEWS,AUTHORS。

如果需要打包其它文件(包括一些庫,特殊的頭文件,配置文件,幫助文件),需要特殊指定:

  1. 使用EXTRA_DIST來指定。
  2. 在編譯目標前添加dist或nodist前綴。

詳細的例子可以參見:

make dist

爲configure定義特殊接口

  1. 使用AC_ARG_WITH,添加–with-package參數
  2. 使用AC_ARG_ENABLE,添加-–enable-feature參數

詳細的例子可以參見:

Add New Optional Features

根據配置編譯不同模塊

  1. 使用AC_DEFINE或AC_DEFINE_UNQUOTED定義C語言使用的宏
  2. 使用AM_CONDITIONAL或AC_SUBST定義Makefile使用的宏

詳細的例子可以參見:

conditional compilation

配置特殊宏

  1. 新建一個單獨的目錄,用於存放自定義宏,一般定義爲m4
  2. 爲每個宏定義一個文件,以.m4結尾
  3. 使用AC_DEFUN定義具體的宏
  4. 運行aclocal -Im4生成aclocal.m4
  5. 在根目錄下的Makefile.am中添加ACLOCAL_AMFLAGS = -I m4

詳細的例子可以參見:

Add m4 macro

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章