configure.ac和Makefile.am的格式解析概述


1. configure.acMakefile.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. 工具鏈的流程

  1. autotools完整流程
    autotools流程
  2. autoreconf
    autotools生成configure
  3. behind autoreconf
    autoreconf
  4. configure生成Makefile
    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 4.8.1 Preset Output Variables

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 3.3 The Uniform Naming Scheme

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. 目錄

automake 3.3 The Uniform Naming Scheme

某些變量用於確定應該把創建了的對象安裝在哪里。這些變量中在前面的部分指示了應將哪個標准目錄作為安裝目錄。標准目錄名在GNU標准中給出(參考GUN編碼標准中的目錄變量)。automake通過前綴pkg擴展了這些標准目錄變量,這些擴展的與標准的相同,但附加了$(PACKAGE)。例如:

變量名 說明
pkgdatadir 相當於$(datadir)/$(PACKAGE)
pkgincludedir 相當於$(includedir)/$(PACKAGE)
pkglibdir 相當於$(libdir)/$(PACKAGE)

GNU編碼標准中的目錄變量,如:prefixexec_prefixbindirlibdirincludedirdatarootdirdatadir等。

在構造變量名稱時,通用的dir后綴被保留了。因此,使用bin_PROGRAMS而不是bindir_PROGRAMS。在使用automake擴展目錄時,同樣適用於此規則。例如,以下代碼片段會將./CMakeLists.txt安裝到$(datadir)/cmake文件夾中。

cmakedatadir = $(datadir)/cmake
nobase_dist_cmakedata_DATA = ./CMakeLists.txt

1.4.2.4. 前綴

automake 3.3 The Uniform Naming Scheme

某些還可由一個或者多個前綴和變量串聯起來形成。某些前綴如下:

  • 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. 衍生變量

automake 3.5 How derived variables are named

有時Makefile變量名是從用戶提供的某些文本中派生而來的。例如,_PROGRAMS中列出的程序名稱將被重寫為_SOURCES變量的名稱。Automake把這些文本規范化,以使它可以不必服從Makefile的變量名規則。進行變量引用時,名稱中的所有字符(字母,數字,@和下划線除外)都將變為下划線。

例如,如果程序名為sniff-glue,則派生變量名稱將為sniff_glue_SOURCES,而不是sniff-glue_SOURCES。同樣的,名稱為libmumble++.a的庫的源文件應在libmumble___a_SOURCES變量中列出。

1.4.2.6. 用戶保留變量

automake 3.6 Variables reserved for the user

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. 目標變量

automake 27.6 Program and Library Variables

與每個程序相關聯的是變量集合,可用於修改該程序的構建方式。每個庫都有類似的此類變量列表。程序或庫的規范名稱用作命名這些變量的基礎。以程序或庫名為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) \
sub1/libsub1.la \
sub2/libsub2.a

需要鏈接到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. 標識變量的順序問題

automake 27.6 Flag Variables Ordering

以CPPFLAGS為例,automake中有三個有關該標識變量,CPPFLAGSAM_CPPFLAGSmaude_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. 如何引用預定義的變量

autoconf 20.5 How Do I #define Installation Directories?

例如想將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示例工程

clist
clist tag

1.7. 參考資料

autoconf
automake
libtool
autoconf宏定義
Autotools 工具
絕世秘籍之GNU構建系統與Autotool概念分析
automake,autoconf使用詳解
Autoconf中文手冊


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM