- 1.
configure.ac
和Makefile.am
的格式解析概述
1. configure.ac
和Makefile.am
的格式解析概述
1.1. Autotools相關工具鏈
1.1.1. Autotools
Autotools是一系列工具
- autoscan
可以通過調用autoscan命令,得到一個初始化的configure.scan文件。然后重命名為configure.ac后,在此基礎上編輯configure.ac。
autoscan會掃描源碼,並生成一些通用的宏調用,輸入的聲明,以及輸出的聲明。盡管autoscan十分方便,但是沒人能夠在構建之前,就把源碼完全寫好。
因此,autoscan通常用於初始化configure.ac,即生成configure.ac的雛形文件configure.scan - aclocal
configure.ac實際是依靠宏展開來得到configure。因此,能否成功生成,取決於宏定義是否能夠找到。
autoconf會從自身安裝路徑下尋找事先定義好的宏。然而對於像automake,libtool,gettex等第三方擴展宏,autoconf便無從知曉。
因此,aclocal將在configure.ac同一個目錄下生成aclocal.m4,在掃描configure.ac過程中,將第三方擴展和開發者自己編寫的宏定義復制進去。
如此一來,autoconf遇到不認識的宏時,就會從aclocal.m4中查找 - autoconf
autoconf是 用來產生configure文件的 .configure是 一個腳本,它能設置
源程序來適應各種不同的操作系統平台,並且根據不同的 系統來產生合適的 Makefile,從而可以使
你的源代碼能在不同的操作系統平台上被編譯出來. - autoheader
autoheader命令掃描configure.ac文件,並確定如何生成config.h.in。每當configure.ac變化時,都可以通過執行autoheader更新config.h.in。
在configure.ac通過AC_CONFIG_HEADERS([config.h])告訴autoheader應當生成config.h.in的路徑,
config.h包含了大量的宏定義,其中包括軟件包的名字等信息,程序可以直接使用這些宏。
更重要的是,程序可以根據其中的對目標平台的可移植相關的宏,通過條件編譯,動態的調整編譯行為。 - automake
手工編寫Makefile是一件相當繁瑣的事情,並且隨着項目的復雜程序變大,編寫難度越來越大。automake工具應運而生。
可以編輯Makefile.am文件,並依靠automake來生成Makefile.in
1.1.2. 其他相關工具
- m4
m4是一個經典的宏工具。autoconf正是構建在m4之上,可以理解為autoconf預先定義了大量的,用戶檢查系統可移植性的宏,這些宏在展開就是大量的shell腳本。
所以編寫configure.ac就需要對這些宏掌握熟練,並且合理調用。 - libtool
libtool試圖解決不同平台下,庫文件的差異。libtool實際是一個shell腳本,實際工作中,調用了目標平台的cc編譯器和鏈接器,以及給予合適的命令行參數。
libtool可以單獨使用,也可以跟autotools集成使用。 - autoreconf
早期autoreconf並不存在,軟件開發者就自己編寫腳本,按照順序調用autoconf,autoheader,automake等工具.
autoreconf程序能夠自動按照合理的順序調用autoconf,automake,aclocal程序
1.2. 工具鏈的流程
- autotools完整流程
- autoreconf
- behind autoreconf
- configure生成Makefile
your source files --> [autoscan*] --> [configure.scan] --> configure.ac
[acinclude.m4] --.
|
[local macros] --+--> aclocal* --> aclocal.m4
|
configure.ac ----'
configure.ac --.
| .------> autoconf* -----> configure
[aclocal.m4] --+---+
| `-----> [autoheader*] --> [config.h.in]
[acsite.m4] ---'
configure.ac --.
+--> automake* --> Makefile.in
Makefile.am ---'
.-------------> [config.cache]
configure* --------------+------------> config.log
|
[config.h.in] -. v .-> [config.h] -.
+--> config.status* -+ +--> make*
Makefile.in ---' `-> Makefile ---'
所以需要項目維護者手動修改的文件除了可選的NEWS README AUTHORS ChangeLog文件之外,就是configure.ac文件和每個源碼文件夾下的Makefile.am文件了。
1.3. autoconf
1.3.1. configure.ac文件
configure.ac用於生成configure腳本,以下以clist工程舉例。
例如有以下文件結構
.
├── clist // clist庫
│ ├── clist.c
│ ├── clist.h
│ ├── CMakeLists.txt // 該文件是用於cmake的,忽略
│ ├── config.h.in // 該文件是用於cmake的,忽略
│ └── Makefile.am
├── CMakeLists.txt // 該文件是用於cmake的,忽略
├── configure.ac
├── .gitignore // 該文件是用於git的,忽略
├── LICENSE
├── m4
│ └── .gitignore // 該文件是用於git的,忽略
├── Makefile.am
├── README.md
└── samples // 測試程序,需要鏈接clist庫
├── CMakeLists.txt // 該文件是用於cmake的,忽略
├── Makefile.am
├── memcheck.stp // 該文件是用於systemstap的,忽略
└── test.c
其中需要在autotools構建中用到的文件除了源碼文件之外,還有./configure.ac
、./Makefile.am
、./clist/Makefile.am
、./samples/Makefile.am
、./m4/
。
m4為空文件夾,是為了后續存放自動生成的m4宏文件避免autoconf告警,由於git無法提交空文件夾,故在其下add了一個.gitignore文件。
使用autoscan掃描目錄后,修改自動生成的configure.scan為configure.ac,並修改如下
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.69])
AC_INIT([clist], [1.0.1.1114], [tangm421@outlook.com])
AC_CONFIG_SRCDIR([clist/clist.c])
AC_CONFIG_HEADER(config.h)
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([m4])
#m4_pattern_forbid([^PKG_])
AM_INIT_AUTOMAKE
AM_PROG_AR([AC_MSG_ERROR([cannot find any available compression tool for \$AR])])
AC_DISABLE_SHARED
LT_INIT()
# Checks for programs.
AC_PROG_CC
#AC_DISABLE_SHARED // 這類宏放在LT_INIT之后是無效的
#AC_PROG_INSTALL // 若使用這兩個老式宏,AC_PROG_CC最好放在此宏之前,否則會有N多警告
#AC_PROG_LIBTOOL
dnl AC_PROG_RANLIB // 若使用了libtool則需要將AC_PROG_RANLIB去掉,且#注釋無效
AC_CANONICAL_HOST
#AC_PROG_MAKE_SET
# Checks for libraries.
# Checks for header files.
#AC_CHECK_HEADERS([malloc.h stdio.h stdlib.h string.h])
# Checks for typedefs, structures, and compiler characteristics.
#AC_CHECK_HEADER_STDBOOL
AC_CHECK_HEADERS([db_cxx.h],
[echo "db_cxx.h found"],
[AC_MSG_WARN([db_cxx.h not found])],
[#ifdef HAVE_FOO_H
# include <inttypes.h>
#endif
])
AC_MSG_NOTICE([Using native OSTYPE value from \$host_os: $host_os, ARCH/LARCH value from \$host_cpu: $host_cpu])
#AC_DEFINE(PROJECT_IMPORTEXPORT, [], [Only usefull for windows])
#AH_TEMPLATE(PROJECT_IMPORTEXPORT, [Only usefull for windows])
AC_DEFINE_UNQUOTED(PROJECT_IMPORTEXPORT, ${PROJECT_IMPORTEXPORT:""}, [Only usefull for windows])
AC_ARG_ENABLE(clist-debug,
[AS_HELP_STRING([--enable-clist-debug], [Enable clist debug print])],
AC_SUBST(LIBCLIST_CPPFLAGS, "-DCLIST_DEBUG"),
AC_SUBST(LIBCLIST_CPPFLAGS, ""))
# Checks for library functions.
#AC_FUNC_MALLOC
AC_CONFIG_FILES([Makefile clist/Makefile samples/Makefile])
AC_OUTPUT
#AC_OUTPUT([Makefile clist/Makefile samples/Makefile])
1.3.2. configure.ac文件的標准布局
configure.ac調用Autoconf宏的順序並不重要,但有一些例外。每個configure.ac必須在檢查之前包含對AC_INIT的調用,並在末尾包含對AC_OUTPUT的調用(參閱Output)。此外,某些宏依賴於首先被調用的其他宏,因為它們會檢查某些變量的先前設置值來決定要做什么。這些宏在各個描述中都有說明(參閱Existing Tests),並且如果調用它們的順序不正確,它們還會在創建配置時向您發出警告。
為了鼓勵一致性,以下是建議的調用Autoconf宏的順序
Autoconf requirements
AC_INIT(package, version, bug-report-address)
information on the package
checks for programs
checks for libraries
checks for header files
checks for types
checks for structures
checks for compiler characteristics
checks for library functions
checks for system services
AC_CONFIG_FILES([file...])
AC_OUTPUT
1.3.3. configure.ac常見宏說明
宏 | 說明 |
---|---|
AC_PREREQ | 聲明autoconf要求的版本號。 |
AC_INIT | 定義軟件包全名稱,版本號,聯系方式。 |
AC_CONFIG_SCRDIR | 用來偵測所指定的源碼文件是否存在,來確定源碼有效性。 |
AC_CONFIG_HEADER | AC_CONFIG_HEADERS([config.h])告訴autoheader應當生成config.h.in的路徑,由autoconf自動生成config.h文件。在實際的編譯階段,生成的編譯命令會加上-DHAVE_CONFIG_H定義宏,於是在代碼中,就可以安全的引用config.h。 config.h包含了大量的宏定義,其中包括軟件包的名字等信息,程序可以直接使用這些宏;更重要的是,程序可以根據其中的對目標平台的可移植性相關的宏,通過條件編譯,動態的調整編譯行為。 每當configure.ac有所變化,都可以通過再次執行autoheader更新config.h.in。在configure.ac通過 |
AC_CONFIG_AUX_DIR | 當我們以--install參數運行時,libtoolize --copy被調用,這將使得ltmain.sh被copy進來;接下來分別執行autoconf和autoheader;automake的參數為--add-missing --copy --no-force,這將使得幾個輔助腳本和文件被安裝到目錄下。 這些輔助文件默認安裝在configure.ac同一個目錄下,如果你希望用另一個目錄來存放他們,可以配置AC_CONFIG_AUX_DIR,例如AC_CONFIG_AUX_DIR([build-aux])將使用build-aux目錄來存放輔助文件。 如果不使用--install參數,輔助文件要么不copy,要么以軟鏈的形式創建。推薦使用--install,因為這樣,其他軟件維護可以避免由於構建工具版本不一致造成問題。 |
AC_CONFIG_MACRO_DIR | AC_CONFIG_MACRO_DIR([m4])指定使用m4目錄存放第三方宏;然后在最外層的Makefile.am中加入ACLOCAL_AMFLAGS = -I m4。 |
AM_INIT_AUTOMAKE | automake的出現晚於autoconf,所以automake是作為autoconf的擴展來實現的。通過在configure.ac中聲明AM_INIT_AUTOMAKE告訴autoconf需要配置和調用automake。 在AC_INIT 宏之后添加AM_INIT_AUTOMAKE([foreign -Wall -Werror]),括號里面的選項可以根據需要來修改,具體請看automake手冊關於這個宏的說明。 NEWS README AUTHORS ChangeLog:這些文件是GNU軟件的標配,不過在項目中不一定需要加入。如果項目中沒有這些文件,每次autoreconf會提示缺少文件,不過這並不影響。如果不想看到這些錯誤提示,可以用AM_INIT_AUTOMAKE([foreign])來配置automake,或者在頂層Makefile.am中使用AUTOMAKE_OPTIONS = foreign;foreign參數就是告訴automake不要這么較真。 |
AM_PROG_AR | 指定壓縮工具,構建靜態庫時需要。 |
AC_MSG_ERROR | AC_MSG_XXX這些宏都是echo shell命令的包裝器。configure時它們將輸出定向到適當的文件描述符。配置腳本很少需要直接運行echo為用戶打印消息。使用這些宏可以很容易地更改打印每種消息的方式和時間。 |
AC_DISABLE_SHARED | 更改LT_INIT的默認行為以禁用共享庫。用戶仍然可以通過指定“ --enable-shared”來覆蓋此默認設置。 LT_INIT的"disable-shared"選項是該功能的簡寫。 AM_DISABLE_SHARED是AC_DISABLE_SHARED的已棄用別名;此選項必須在LT_INIT之前才能生效。 |
LT_INIT | 如果要使用libtool編譯,需要在configure.ac中添加LT_INIT宏,同時去掉AC_PROG_RANLIB。 啟用libtool后,該宏會添加對--enable-shared,--disable-shared,--enable-static,--disable-static,--with-pic和--without-pic配置標志的支持,查閱LT_INIT說明。 |
AC_PROG_CC | 指定C編譯器,默認GCC。 |
AC_PROG_LIBTOOL | AC_PROG_LIBTOOL和AM_PROG_LIBTOOL是不推薦使用的舊版本,建議使用LT_INIT替代之。 |
AC_PROG_RANLIB | 構建靜態庫時需要,具體請看automake手冊,建議使用LT_INIT替代之。 |
AC_CANONICAL_HOST | 該宏調用后,可以在通過host_cpu,host_vendor和host_os這三個變量獲得系統相關信息。 |
AC_CHECK_HEADERS | 檢查一批頭文件。 |
AC_DEFINE | 使用本宏進行符號定義,但要為其定義模板。如果缺少模板,autoheader將報錯。 |
AH_TEMPLATE | 配合AC_DEFINE使用。 |
AC_DEFINE_UNQUOTED | 類似於AC_DEFINE,但還要對variable和value進行三種shell替換(每種替換只進行一次): 變量擴展('$'),命令替換('`'),以及反斜線轉義符('\')。值中的單引號和雙引號 沒有特殊的意義。在variable或者value是一個shell變量的時候用本宏代替AC_DEFINE。 |
AM_CONDITIONAL | 用於定義條件,生成一個automake宏,可以在Makefile.am中使用這個條件宏進行判斷控制。 |
AC_ARG_ENABLE | 本宏用來增加編譯時選項,該選項使用戶可以選擇要構建和安裝的可選功能,若選項為軟件包,類似於nginx中的引入第三方功能包時,參考AC_ARG_WITH。最終可以在./configure --help的Optional Packages選項中看到該項。 |
AS_HELP_STRING | 格式化幫助字符串。 |
AC_SUBST | 創建或者重新賦值一個automake變量。 |
AC_CONFIG_FILES | 生成相應的Makefile文件,不同目錄下通過空格分隔。 |
AC_OUTPUT | 建議使用AC_CONFIG_FILES替代之。 |
1.3.5. 常用變量
Autoconf會預設一些輸出變量,例如:
變量 | 說明 |
---|---|
CFLAGS |
調用AC_PROG_CC時設置默認值-g -O2 |
top_srcdir |
程序包的頂級源代碼目錄的名稱。在頂級目錄中,與srcdir 相同。 |
srcdir |
包含該makefile的源代碼的目錄的名稱。 |
abs_srcdir |
srcdir 的絕對路徑名稱 |
top_builddir |
當前構建樹頂層目錄的相對名稱。在頂級目錄中,與builddir 相同。 |
buildidr |
當前構建樹的當前目錄,即./ |
abs_builddir |
builddir 的絕對路徑名稱 |
1.3.4. 關於自定義宏
后續待補。。。
1.4. automake
1.4.1. Makefile.am文件
Makefile.am是一種比Makefile更高層次的規則。只需指定要生成什么目標,它由什么源文件生成,要安裝到什么目錄等構成。
- 原則1:每個目錄一個Makefile.am文件;同時在configure.ac的AC_CONFIG_FILES宏中指定輸出所有的Makefile文件
- 原則2:父目錄需要包含子目錄,在父目錄下的Makefile.am中添加: SUBDIRS = 子目錄
- 原則3:Makefile.am中指明當前目錄如何編譯
Makefile.am用以生成最終的Makefile編譯腳本,以下還是以clist工程為例
./Makefile.am
AUTOMAKE_OPTIONS = foreign
ACLOCAL_AMFLAGS = -I m4
SUBDIRS = clist
SUBDIRS += samples
cmakedatadir = $(datadir)/cmake
nobase_dist_cmakedata_DATA = ./CMakeLists.txt
nobase_dist_cmakedata_DATA += clist/CMakeLists.txt
nobase_dist_cmakedata_DATA += ./samples/CMakeLists.txt
這里我把foreign選項放在了最頂層的Makefile.am中,由於configure.ac文件中加入了AC_CONFIG_MACRO_DIR宏,故此處必須加上ACLOCAL_AMFLAGS = -I m4
。
SUBDIRS是一個特殊變量,列出了在處理當前目錄之前應遞歸到的所有目錄。所有在此聲明的子目錄也參與到構建工程,故也需要Makefile.am文件。
關於此文件中的最后幾行則是在執行make install
時將幾個cmake文件按照原始文件結構層次安裝到$(datadir)/cmake
目錄下,並且允許在分發(執行make dist
)時將這幾個cmake文件按照層次結構也包含在內。
./clist/Makefile.am
lib_LTLIBRARIES = libclist.la
libclist_la_CPPFLAGS = @LIBCLIST_CPPFLAGS@
libclist_la_SOURCES = config.h clist.c
include_HEADERS = clist.h
子目錄clist下用來編譯clist庫,因為啟用了libtool(libtool將共享庫和靜態庫抽象為一個統一的概念,稱為libtool庫。 libtool庫是使用.la后綴的文件,並且可以指定靜態庫,共享庫或兩者。在運行./configure之前,無法確定它們的確切性質:並非所有平台都支持所有類型的庫,並且用戶可以顯式選擇應構建的庫。由於共享庫和靜態庫的目標文件必須以不同的方式進行編譯,因此在編譯過程中也會使用libtool。 libtool構建的對象文件稱為libtool對象:這些文件使用.lo后綴。 Libtool庫是從這些libtool對象構建的)所以此處庫名為libclist.la,使用libclist_la_為前綴添加預編譯指令、源碼文件及包含文件。LIBCLIST_CPPFLAGS則是先前的configure.ac文件中聲明的一個automake變量在此處引用。
./samples/Makefile.am
#AM_CFLAGS = -I$(top_srcdir)/clist
bin_PROGRAMS = sample
sample_CFLAGS = -I$(top_srcdir)/clist
sample_SOURCES = test.c
sample_LDADD = ../clist/libclist.la
sample_CPPFLAGS = -D_BINDIR='"$(bindir)"'
nodist_sample_SOURCES = mydefines.h
BUILT_SOURCES = mydefines.h
CLEANFILES = mydefines.h
mydefines.h: Makefile
echo '#define INSTALL_BINDIR "$(bindir)"' > $@
子目錄samples用來編譯測試程序,程序名為sample,使用sample_為前綴添加C編譯標志、源碼以及鏈接庫。
關於此文件中的最后幾行,是為了說明后面如何引用預定義的變量的問題,BUILT_SOURCES
則是為了在構建sample之前生成mydefines.h,關於BUILT_SOURCES
變量的說明參閱automake 9.4 Built Sources
在靜態庫和動態庫同時存在時,libtool默認鏈接的動態庫
有關使用指定庫鏈接以及靜態庫和動態庫混合鏈接的情形后續待補...
1.4.2. 語法說明
1.4.2.1. 統一命名規范
Automake變量通常遵循統一的命名規范,可以輕松決定程序(和其他派生對象)的構建方式以及安裝方式。該規范還支持configure
時確定應構建的內容。
在make
時,某些變量用於確定要構建的對象。變量名由幾部分組成,這些部分串聯在一起,其中指示構建的部分通常稱為元
。
1.4.2.2. 元
就拿_PROGRAMS
為例,以_PROGRAMS結尾的變量,列出了生成的Makefile應該生成的程序。用Automake語言來說,此_PROGRAMS后綴稱為元
。
bin_PROGRAMS的bin
部分告訴automake應該將生成的程序安裝在bindir中。回想一下,GNU Build System使用一組變量來表示目標目錄,並允許用戶自定義這些位置。任何這樣的目錄變量都可以放在元
前面(省略dir后綴),以告訴automake在何處安裝列出的文件。
Automake可以識別與不同類型的文件相對應的其他元變量,例如_PROGRAMS,_LIBRARIES,_LTLIBRARIES等。
元變量 | 說明 |
---|---|
_PROGRAMS |
標識需要被編譯和連接的程序的列表 |
_LIBRARIES |
標識需要被編譯和連接的庫的列表 |
_LTLIBRARIES |
標識需要被編譯和連接的庫(使用libtool生成的庫)的列表 |
當前元
有_PROGRAMS
, _LIBRARIES
, _LTLIBRARIES
, _LISP
, _PYTHON
, _JAVA
, _SCRIPTS
, _DATA
, _HEADERS
, _MANS
, _TEXINFOS
。
將沒有前綴的元
定義為變量(例如 PROGRAMS
)是錯誤的!
1.4.2.3. 目錄
某些變量用於確定應該把創建了的對象安裝在哪里。這些變量中在元
前面的部分指示了應將哪個標准目錄作為安裝目錄。標准目錄名在GNU標准中給出(參考GUN編碼標准中的目錄變量)。automake通過前綴pkg
擴展了這些標准目錄變量,這些擴展的與標准的相同,但附加了$(PACKAGE)
。例如:
變量名 | 說明 |
---|---|
pkgdatadir |
相當於$(datadir)/$(PACKAGE) |
pkgincludedir |
相當於$(includedir)/$(PACKAGE) |
pkglibdir |
相當於$(libdir)/$(PACKAGE) |
GNU編碼標准中的目錄變量,如:prefix
、exec_prefix
、bindir
、libdir
、includedir
、datarootdir
、datadir
等。
在構造變量名稱時,通用的dir
后綴被保留了。因此,使用bin_PROGRAMS
而不是bindir_PROGRAMS
。在使用automake擴展目錄時,同樣適用於此規則。例如,以下代碼片段會將./CMakeLists.txt安裝到$(datadir)/cmake
文件夾中。
cmakedatadir = $(datadir)/cmake
nobase_dist_cmakedata_DATA = ./CMakeLists.txt
1.4.2.4. 前綴
某些元
還可由一個或者多個前綴和變量串聯起來形成。某些前綴如下:
-
EXTRA_
對於每個
元
,都可以插入一個EXTRA_
前綴。該前綴用於儲存根據configure的運行結果,可能創建、也可能不創建的對象列表。引入該變量是因為Automake必須靜態地知道需要創建的對象的完整列表以創建在所有情況下都能夠工作的Makefile.in
。
例如:EXTRA_LTLIBRARIES = lib1.la lib2.la
,這兩個庫不會被明確的構建,如果其在任何地方都不會作為Makefile依賴項出現,就不會被構建。一般該前綴用在條件編譯的情形下比較常見。 -
check_
該前綴表示僅僅在運行
make check
命令的時候才創建這些對象。 -
inst_
/noinst_
用於控制
make install
時的安裝行為。
inst_
表示應構建相關對象,且進行安裝。
noinst_
表示應構建相關對象,但不安裝。這通常用於構建程序包其余部分所需的對象,例如靜態庫或幫助程序腳本。 -
dist_
/nodist_
用於控制
make dist
時的發布行為。
任何元
或_SOURCES
變量都可以使用dist_作為前綴,以將列出的文件添加到發行版中。類似地,nodist_可用於從發行版中省略文件。示例 說明 dist_maude_SOURCE = test.c
表示test.c作為構建目標 maude
時候的源,並進行分發。nodist_maude_SOURCE = mydefines.h
表示mydefines.h只作為構建目標 maude
時候的源,但不進行分發 -
nobase_
默認情況下,在子目錄中指定的可安裝文件在安裝前將刪除其目錄名稱。例如,在此示例中,頭文件將安裝為$(cmakedatadir)/CMakeLists.txt。
dist_cmakedata_DATA += clist/CMakeLists.txt
但是,可以使用
nobase_
前綴來規避此路徑剝離。在此示例中,頭文件將安裝為$(cmakedatadir)/clist/CMakeLists.txt。nobase_dist_cmakedata_DATA += clist/CMakeLists.txt
當與其他前綴混合出現時,應首先指定該前綴
1.4.2.5. 衍生變量
有時Makefile變量名是從用戶提供的某些文本中派生而來的。例如,_PROGRAMS
中列出的程序名稱將被重寫為_SOURCES
變量的名稱。Automake把這些文本規范化,以使它可以不必服從Makefile的變量名規則。進行變量引用時,名稱中的所有字符(字母,數字,@
和下划線除外)都將變為下划線。
例如,如果程序名為sniff-glue
,則派生變量名稱將為sniff_glue_SOURCES
,而不是sniff-glue_SOURCES
。同樣的,名稱為libmumble++.a
的庫的源文件應在libmumble___a_SOURCES
變量中列出。
1.4.2.6. 用戶保留變量
GNU編碼標准保留了一些Makefile變量,以供“用戶”(構建軟件包的人)使用,這些變量有些可能會被Autoconf預設。例如:
用戶變量 | 說明 |
---|---|
CC |
c編譯器 |
CXX |
c++編譯器 |
CPPFLAGS |
c/c++的預編譯宏 |
CFLAGS |
c編譯標識 |
CXXFLAGS |
c++編譯標識 |
LDFLAGS |
鏈接標識 |
Automake為每個用戶標志變量引入了一個特定於automake的影子變量(沒有為CC之類的變量引入影子變量,因為它們沒有意義)。影子變量的名稱是在用戶變量名前加上AM_
。例如,CFLAGS
的影子變量為AM_CFLAGS
。軟件包維護者(即Makefile.am和configure.ac文件的作者)可以根據需要調整這些影子變量。
1.4.2.7. 目標變量
與每個程序相關聯的是變量集合,可用於修改該程序的構建方式。每個庫都有類似的此類變量列表。程序或庫的規范名稱用作命名這些變量的基礎。以程序或庫名為maude
舉例,常見的變量如下:
變量 | 說明 |
---|---|
maude_SOURCES |
源文件 |
maude_LDADD |
添加其他對象到程序中 |
maude_LIBADD |
添加其他對象到庫中 |
maude_CPPFLAGS |
c/c++的預編譯宏 |
maude_CFLAGS |
c編譯標識 |
maude_CXXFLAGS |
c++編譯標識 |
maude_LDFLAGS |
鏈接標識 |
1.4.2.8. 其他
SUBDIRS
EXTRA_DIST
BUILT_SOURCES
1.4.3. Makefile.am常用變量說明
構建目標類型 | 示例 | 說明 | |
可執行程序 | bin_PROGRAMS = sample | 構建的可執行程序sample,並安裝在bin目錄 | |
sample_SOURCES = test.c | 參與構建sample的源文件 | ||
nodist_sample_SOURCES = mydefines.h | 參與構建sample的源文件但不分發 | ||
sample_LDADD = ../clist/clist.la | 需要鏈接到sample的庫文件 | ||
庫 | 靜態庫 | lib_LIBRARIES = libclist.a | 構建的靜態庫clist.a,並安裝在lib目錄 |
libclist_a_SOURCES = clist.c | 參與構建clist靜態庫的源文件 | ||
libclist_a_LIBADD = $(LIBOBJS) $(ALLOCA) \ |
需要鏈接到clist靜態庫的其他對象 | ||
clistincludedir = $(includedir)/clist nobase_clistinclude_HEADERS = clist.h |
安裝到$(clistincludedir)目錄下的頭文件,且按照原目錄結構組織 | ||
libtool庫 | lib_LTLIBRARIES = libclist.la | 構建的libtool庫(靜態庫或動態庫),並安裝在lib目錄 | |
libclist_la_SOURCES = clist.c | 參與構建libtool庫的源文件 | ||
nodist_libclist_la_SOURCES = config.h | 參與構建libtool庫的源文件,但不分發 | ||
clistincludedir = $(includedir)/clist nobase_clistinclude_HEADERS = clist.h |
安裝到$(clistincludedir)目錄下的頭文件,且按照原目錄結構組織< | ||
頭文件 | include_HEADERS = clist.h | 構建目標的頭文件,並安裝到include目錄,參考automake 9.2 Header files | |
源文件 | sample_SOURCES = test.c | 構建目標的源文件,並分發,參考automake 8.5 Default _SOURCES |
當一些頭文件不需要在外部被引用時,也應該列在_SOURCES
中,而不是_HEADERS
。例如,庫的頭文件一般列出在_HEADERS
,程序的頭文件一般列出在_SOURCES
中。另外有一些參與目標構建但既不屬於目標對象,又不需要被外部引用的頭文件,則可以使用noinst_HEADERS
,比較典型的如configure生成的config.h文件。
_LDADD
和_LIBADD
不適合傳遞程序特定的鏈接器標志(-l,-L,-dlopen和-dlpreopen除外)。
1.5. 一些常見問題
1.5.1. 標識變量的順序問題
以CPPFLAGS為例,automake中有三個有關該標識變量,CPPFLAGS
、AM_CPPFLAGS
、maude_CPPFLAGS
,用於傳遞給C/C++預處理器,CPPFLAGS是用戶變量,AM_CPPFLAGS是Automake變量,而mumble_CPPFLAGS是特定於目標對象的變量,也即每個目標變量。
編譯時,automake始終使用這些變量中的兩個,如果maude_CPPFLAGS
定義了,則使用該變量,否則,使用AM_CPPFLAGS,第二個變量始終是CPPFLAGS。該規則也同樣適用於其他類似標記。 例如:
bin_PROGRAMS = foo bar
foo_SOURCES = xyz.c
bar_SOURCES = main.c
foo_CPPFLAGS = -DFOO
AM_CPPFLAGS = -DBAZ
xyz.o將使用$(foo_CPPFLAGS)$(CPPFLAGS)
進行編譯(因為xyz.o是foo目標的一部分),而main.o將使用$(AM_CPPFLAGS)$(CPPFLAGS)
進行編譯(因為bar目標變量未定義)。
推薦使用額外自定義的變量,然后使用目標對象的標記變量追加。例如:
AM_CFLAGS = $(WARNINGCFLAGS)
bin_PROGRAMS = prog1 prog2
prog1_SOURCES = ...
prog2_SOURCES = ...
prog2_CFLAGS = $(LIBFOOCFLAGS) $(AM_CFLAGS)
prog2_LDFLAGS = $(LIBFOOLDFLAGS)
1.5.2. 如何引用預定義的變量
例如想將bindir
定義到程序中使用,直接使用以下方式是行不通的:
AC_DEFINE_UNQUOTED([INSTALL_BINDIR], [$bindir],
[Define to the read-only architecture-independent
data directory.])
最終得到的結果是:
#define DINSTALL_BINDIR "${prefix}/bin"
因為該行為是GNU編碼標准強制規定的,要達到目的,不能使用AC_DEFINE
,而是使用Makefile通過編譯標識傳遞,或者定義到專門的頭文件中。
- 方式一:使用Makefile通過編譯標識傳遞
AM_CPPFLAGS = -DINSTALL_BINDIR='"$(bindir)"'
- 方式二:創建一個專用頭文件
DISTCLEANFILES = mydefines.h
mydefines.h: Makefile
echo '#define INSTALL_BINDIR "$(bindir)"' >$@
1.6. clist示例工程
1.7. 參考資料
autoconf
automake
libtool
autoconf宏定義
Autotools 工具
絕世秘籍之GNU構建系統與Autotool概念分析
automake,autoconf使用詳解
Autoconf中文手冊