autotools使用流程
autotools 是一系列工具,它包含了aclocal,autoconf,autoheader和automake这些工具,使用autotools主要就是利用各个工具来生成最后的makefile文件。其具体流程如下图:
如果你的系统安装了autoreconf,则上面的工具调用可以通过autoreconf这一个命令来完成,如果有哪个源文件更新,autoreconf会检测到并重新调用上面的工具来生成新的Makefile.
命令如下:
autoreconf --install --force
基础例子
文件结构
geesun@geesun-OptiPlex-3010:~/automake$ tree
.
├── configure.ac
├── Makefile.am
└── src
└── helloworld.c
helloworld.c代码源文件:
#include <config.h>
#include <stdio.h>
int main (void)
{
printf("Hello "PACKAGE_STRING);
return 0;
}
configure.ac文件
AC_INIT([helloworld], [1.0], [geesun@gmail.com])
AC_PREREQ([2.68])
AC_CONFIG_SRCDIR([src/helloworld.c])
AC_CONFIG_AUX_DIR([build-aux])
AM_INIT_AUTOMAKE([silent-rules -Wall -Werror subdir-objects foreign])
AM_SILENT_RULES([yes])
AC_PROG_CC
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
Makefile.am文件
bin_PROGRAMS = helloworld
helloworld_SOURCES = src/helloworld.c
常用功能分析
1. 增加configure的选项
如果要给configure生成像--enable-XXXX,--disable-XXXX,--with-XXXX,--without-XXXX这样的参数,就需在configure.ac里用到AC_ARG_ENABLE和AC_ARG_WITH这两个宏,AC_ARG_ENABLE和AC_ARG_WITH语法如下:
AC_ARG_ENABLE(option-name, help-string, action-if-present, action-if-not-present)
AC_ARG_WITH (package, help-string, [action-if-given], [action-if-not-given])
我们来看下的configure.ac例子文件:
......
AM_SILENT_RULES([yes])
dnl Example of default-enabled feature
AC_ARG_ENABLE([feature1],
AS_HELP_STRING([--disable-feature1], [Disable feature1]))
AS_IF([test "x$enable_feature1" != "xno"], [
AC_DEFINE([HAVE_FEATURE1], [1], [Enable feature1])
])
dnl Example of default-disabled feature
AC_ARG_ENABLE([feature2],
AS_HELP_STRING([--enable-feature2], [Enable feature2]))
AS_IF([test "x$enable_feature2" = "xyes"], [
AC_DEFINE([HAVE_FEATURE2], [1], [Enable feature2])
])
dnl feature3 has depended on feature2, if feature2 was not enabled, feature3 always disabled
AC_ARG_ENABLE([feature3],
AS_HELP_STRING([--enable-feature3], [Enable feature3]),
[
AS_IF([test "x$enable_feature2" != "xyes"], [enable_feature3="no"])
],
[
enable_feature3="no"
])
AS_IF([test "x$enable_feature3" = "xyes"], [
AC_DEFINE([HAVE_FEATURE3], [1], [Enable feature3])
])
AS_ECHO(["feature1 = $enable_feature1"])
AS_ECHO(["feature2 = $enable_feature2"])
AS_ECHO(["feature3 = $enable_feature3"])
AC_ARG_WITH([foo],
AS_HELP_STRING([--without-foo], [Ignore presence of foo and disable it]))
AS_IF([test "x$with_foo" != "xno"], [
AC_DEFINE([HAVE_FOO], [1], [With foo])
])
AS_ECHO(["with_foo = $with_foo"])
AC_PROG_CC
......
有关Autoconf的语法规则,可以参考The Autoconf Language.
AS_IF就是一个if else的语句,比较好理解,AC_DEFINE就是在config.h里面来定义一个宏来给之后具体的代码使用。
helloworld.c代码文件:
printf("Hello "PACKAGE_STRING"\n");
#ifdef HAVE_FEATURE1
printf("Hello Feature1 \n");
#endif
#ifdef HAVE_FEATURE2
printf("Hello Feature2 \n");
#endif
#ifdef HAVE_FEATURE3
printf("Hello Feature3 \n");
#endif
#ifdef HAVE_FOO
printf("Hello Foo \n");
#endif
2.条件编译
通常,我们针对不同平台,可能会编译不同源文件,还有就是在用户在使用configure增加或者减少某个功能时,需要编译出更多或者更少的可执行文件,这是怎么做到的呢?下面我们就用一个例子来说明这个在autoconf里面怎么做到。
首先在configure.ac中增加选项,让用户来决定是否开启指定功能:
AC_ARG_ENABLE([debug],
AS_HELP_STRING([--enable-debug], [Enable debug feature]))
AM_CONDITIONAL([DEBUG], [test "x$enable_debug" = "xyes"])
AM_CONDITIONAL是在configure.ac里面定义一个条件,这样在Makefile.am里面就可以使用这个条件了,如果没有定义,是不可以使用的。
再在Makefile.am里面根据这个条件来指定文件进行编译:
if DEBUG
bin_PROGRAMS = helloworld debug
debug_SOURCES=src/debug.c
else
bin_PROGRAMS = helloworld
endif
if DEBUG
helloworld_SOURCES = src/helloworld.c \
src/hello-debug.c
else
helloworld_SOURCES = src/helloworld.c
endif
3.查找库以及头文件
AC_CHECK_LIB和AC_SEARCH_LIB是用来查找库,如果找到库,则会在编译可执行文件时把这个库增加到链接库里面。语法如下:
AC_CHECK_LIB (library, function, [action-if-found], [action-if-not-found], [other-libraries])
AC_SEARCH_LIBS (function, search-libs, [action-if-found], [action-if-not-found], [other-libraries])
AC_CHECK_HEADER和AC_CHECK_HEADERS是用来查找头文件的,如果找到,会在config.h里面增加相对应的宏。语法如下:
AC_CHECK_HEADER (header-file, [action-if-found], [action-if-not-found], [includes])
AC_CHECK_HEADERS (header-file..., [action-if-found], [action-if-not-found], [includes])
configure.ac例子如下:
AC_CHECK_LIB(m, abs,[],[AC_MSG_ERROR([unable to find the cos() function])])
AC_CHECK_HEADERS([pthread.h], [],[AC_MSG_ERROR([unable to find the pthread.h])])
AC_SEARCH_LIBS([pthread_create], [pthread])
4.自定义Makefile规则
在做工程的时候,可能会有一些比较特殊的文件需要通过Makefile产生,这个时候就需要用到在Makefile.am里面增加一些自己定义的规则来完成我们的目的。这些功能就是在Makefile.am里面增加一些带-local后缀的target来实现。目前支持-local后缀的targets有: all, install-exec, uninstall, clean 等。
例子:
scripts:
mkdir -p scripts
echo "#!/bin/sh " > scripts/hello.sh
echo "echo ""hello world"" " >> scripts/hello.sh
all-local: scripts
clean-local:
rm -rf scripts/
更多可以参考这里
5.自定义安装目录
大型工程里面会有许多文件,有一些要安装在特定的目录,不一定是系统默认目录,这个时候,就需要在Makefile.am中增加目录规则。系统默认目录可以参考这里。 要自己定义目录,首先要定义xxxdir变量,然后才可以用xxx来指定文件。如下例子:
mydir=$(prefix)/mybin
my_PROGRAMS = hello2
hello2_SOURCES = src/main2.c
6.其他文件安装
脚本默认不打包,如果要默认打包进去,则要用:
dist_bin_SCRIPTS = my_script
不保留原始目录结构:
include_HEADERS = foo.h bar/bar.h
保留原始目录结构:
nobase_include_HEADERS = foo.h bar/bar.h
data文件可以安装在如下目录:datadir, sysconfdir, sharedstatedir, localstatedir, pkgdatadir.
noinst_PROGRAMS=hello3
hello3_SOURCES = src/main3.c
7.更多可以参考
autotools.io
Program and Library Variables
Building a Shared Library
GNU Automake
Autoconf Macro Index
AutoMake Macro Index
comments