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_HEADERAC_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_DIRAC_CONFIG_MACRO_DIR([m4])指定使用m4目录存放第三方宏;然后在最外层的Makefile.am中加入ACLOCAL_AMFLAGS = -I m4。
AM_INIT_AUTOMAKEautomake的出现晚于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_ERRORAC_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_LIBTOOLAC_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_srcdirsrcdir的绝对路径名称
top_builddir当前构建树顶层目录的相对名称。在顶级目录中,与builddir相同。
buildidr当前构建树的当前目录,即./
abs_builddirbuilddir的绝对路径名称

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预设。例如:

用户变量说明
CCc编译器
CXXc++编译器
CPPFLAGSc/c++的预编译宏
CFLAGSc编译标识
CXXFLAGSc++编译标识
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_CPPFLAGSc/c++的预编译宏
maude_CFLAGSc编译标识
maude_CXXFLAGSc++编译标识
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

1.7. 参考资料

autoconf
automake
libtool
autoconf宏定义
Autotools 工具
绝世秘籍之GNU构建系统与Autotool概念分析
automake,autoconf使用详解
Autoconf中文手册

非常抱歉,我混淆了configure.acMakefile.am文件。下面是正确的步骤: 1. 在主项目的configure.ac文件中,使用AC_CONFIG_SUBDIRS宏指定需要包含的子项目目录,例如: ``` AC_CONFIG_SUBDIRS([subdir1 subdir2 subdir3]) ``` 2. 在每个子项目的configure.ac文件中,必须使用AC_CONFIG_AUX_DIR宏来指定子项目中的config.sub和config.guess文件的位置,例如: ``` AC_CONFIG_AUX_DIR([.]) ``` 3. 在每个子项目的Makefile.am文件中,使用ACLOCAL_AMFLAGS变量来指定包含的宏定义文件的位置,例如: ``` ACLOCAL_AMFLAGS = -I m4 ``` 其中,m4是包含宏定义文件的目录。 4. 在每个子项目的Makefile.am文件中,使用AUTOMAKE_OPTIONS变量指定需要使用外部子目录功能,例如: ``` AUTOMAKE_OPTIONS = subdir-objects ``` 5. 在每个子项目的Makefile.am文件中,定义生成的库文件和头文件,并使用INCLUDES变量指定需要包含的头文件路径,例如: ``` lib_LTLIBRARIES = libsubdir1.la libsubdir1_la_SOURCES = subdir1.c subdir1.h INCLUDES = -I$(top_srcdir)/subdir1 ``` 其中,lib_LTLIBRARIES变量指定生成的库文件名,libsubdir1_la_SOURCES变量指定生成库文件所需的源文件和头文件,INCLUDES变量指定需要包含的头文件路径。 6. 最后,在主项目的Makefile.am文件中,使用SUBDIRS变量指定包含的子目录,例如: ``` SUBDIRS = subdir1 subdir2 subdir3 ``` 这样,在主项目的configure脚本执行时,会自动进入每个子项目的目录执行其对应的configure脚本,然后生成各自的Makefile文件。同时,每个子项目的库和头文件也会被自动编译和链接到主项目中。 使用外部子目录功能可以自动化生成子项目的Makefile文件,避免了手动执行子项目的configure脚本的步骤。同时,也可以更灵活地控制子项目的编译和链接过程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值