automake学习五

简介

每次运行automake,它都用调用autoconf来解析configure.ac,获取一些宏,产生合适的Makefile.in.本文主要介绍configure.ac一些重要的宏

每次运行aclocal,它都会扫描所有的.m4文件寻找宏定义,然后再扫描configure.ac

参考链接

automake官方

autoconf官方

编译相关宏

定义程序源文件

bin_PROGRAMS = hello
hello_SOURCES = hello.c version.c getopt.c getopt.h systerm.h
  • 任何以.c结尾的文件都会被编译为相应的.o, 最后会被链接为hello;
  • 如果hello_SOURCES没有被定义,则默认为hello.c;
  • 列在_SOURCES中的头文件会被部署,否则不会;

条件编译

如果hello-linux.c或者hello-generic.c按条件参与hello的编译,则相应的Makefile.am如下

bin_PROGRAMS = hello
hello_SOURCES = hello-common.c
EXTRA_hello_SOURCES = hello-linux.c hello-generic.c
hello_LDADD = $(HELLO_SYSTEM)
hello_DEPENDENCIES = $(HELLO_SYSTEM)

则在configure.ac中对应如下

...
case $host in
	*linux*) HELLO_SYSTEM='hello-linux.$(OBJEXT)';;
	*) HELLO_SYSTEM='hello-generic.$(OBJEXT)';;
esac
AC_SUBST([HELLO_SYSTEM])
...
  • 在上面的例子中,HELLO-SYSTEM将会被hello-linux.o或者hello-generic.o所替代

当然也可以选择条件编译来代替EXTRA_前缀,Automake会检测变量值来构建合适的编译依赖

bin_PROGRAMS = hello
hello_SOURCES = hello-common.c
if LINUX
	hello_SOURCES +=hello-linux.c
else
	hello_SOURCES += hello-generic.c
endif

在编译GNU的cpio时,在不同环境下编译工具会选择mt或者rmt来参与编译,这时有两种方法来进行编译

  • 替代编译
  • 条件编译

替代编译:

bin_PROGRAMS = cpio pax $(MT)
libexec_PROGRAMS = $(RMT)
EXTRA_PROGRAMS = mt rmt

由于Automake会自动增加$(EXEEXT)后缀重写bin_PROGRAMS,libexec_PROGRAMS,EXTRA_PROGRAMS,这时切记要使用AC_SUBST([MT],['mt$(EXEEXT)'])

条件编译:

bin_PROGRAMS = cpio pax
if WANT_MT
	bin_PROGRAMS += MT
endif
if WANT_RMT
	bin_PROGRAMS +=rmt
endif

这种方式就不用担心$(EXEEXT)后缀。

编译静态库

使用libtool及LTLIBRARIES编译共享库,将会被安装在libdir或者pkglibdir目录

例如要编译一个libcpio.a,但是不安装它,可以如下:

noinst_LIBRARIES = libcpio.a
libcpio_a_SOURCES = ...
libcpio_a_LIBADD = $(LIBOBJS) $(ALLOCA)

编译静态库只需要编译所有的有效文件,然后使用ar工具进行链接,$(AR)$(ARFLAGS)Makefile.am中对应的预设变量;最后对静态库使用$(RANLIB)来更新符号表.对于这些变量的设置,一般有四种不同方法:

  • 在configure.ac中定义AC_PROG_RANLIB
  • 在configure.ac中定义AM_PROG_RANLIB
  • 在Makefile.am中直接设置变量RANLIB的值
  • 在configure.ac使用AC_SUBST来设置变量值

下面这个小例子中,程序cpio静态链接了libcpio.a

noinst_LIBRARIES = libcpio.a
libcpio_a_SOURCES = ...

bin_PROGRAMS = cpio
cpio_SOURCES = cpio.c ...
cpio_LDADD = libcpio.a

编译动态库

libtool工具编译出的文件被称为libtool文件,他们一般由.lo或者.la为后缀,automake使用libtool编译共享库要以LTLIBRARIES为主标志,每一个_LTLIBRARIES变量都是一系列要编译的libtool共享库

lib_LTLIBRARIES = libgettest.la
libgettest_la_SOURCES = gettext.c gettext.h ...
  • 首先在linux中使用libtool前要先运行libtoolize
  • 如果gettext.h是一个要供大家使用的库函数,则需要使用_HEADERS变量
  • 申明在libgettest_la_SOURCES中的库函数是内部使用的接口

下面这个例子编译了一个程序hello,链接了libgettext.la

lib_LTLIBRARIES = libgettest.la
libgettext_la_SOURCES = gettext.c

bin_PROGRAMS = hello
hello_SOURCES = hello.c ...
hello_LDADD = libgettext.la
  • hello是静态还是动态链接libgettext.la是未知的,由libtool的配置及主机配置决定.

条件编译libtool libraries

两种不同情况

  • Automake 条件编译

      对于在automake运行阶段,目的地址已经知道,automake会自动提供合适的`-rpath`选项给`libtool`,这种情况一般用于库文件已经显示的罗列在了`_LTLIBRARIES`上
    
  • autoconf的AC_SUBST置换

      对于在运行`./configure`时,才被决定的库文件(`EXTRA_LTLIBRARIES`),这种情况,automake并不清楚最后的安装地址,这时,对于`_LDFLAGS`必须增加合适的`-rpath`参数.
    
EXTRA_LTLIBRARIES = libfoo.la libbar.la
lib_LTLIBRARIES = $(WANTEDLIBS)
libfoo_la_SOURCES = foo.c ...
libfoo_la_LDFLAGS = -rpath '$(libdir)'
libbar_la_SOURCES = bar.c ...
libbar_la_LDFLAGS = -rpath '$(libdir)'
lib_LTLIBRARIES = 
if WANT_LTBFOO
	lib_LIBRARIES +=libfoo.la
endif
if WANT_LTBBAR
	lib_LTLIBRARIES +=libbar.la
endif
libfoo_la_SOURCES = foo.c ...
libbar_la_SOURCES = bar.c ...

如果你有自己的m4宏,即aclocal.m4,可以重命名为acinclude.m4,则会自动被包含进aclocal.m4中

mv aclocal.m4 acinclude
aclocal
autoconf

然后写Makefile.am,告诉automake要生成什么,怎么生成

主目录中的Makefile.am

SUBDIRS = src
dist_doc_DATA = README

src目录中的Makefile.am

bin_PROGRAMS = hello
hello_SOURCES = main.c
hello_LDADD = $(LIBOBJS)

再运行

autoheader
automake --add-missing

也可以在编写完configure.acMakefile.am后直接运行

autoreconf

源代码下载:

git clone git@github.com:pzh2386034/automakeLearnExample.git