[cpp 编译]Autotools笔记 翻译自autotools官方文档

来源:互联网 发布:孙总定制机箱淘宝店 编辑:程序博客网 时间:2024/05/16 19:02

1、要达到的目的
结构:
configure.ac Makefile.am src/Makefile.am
使用autoreconf命令
生成
configure Makefile.in src/Makefile.in config.in
然后使用make
任务完成!
2、Autotools核心包介绍
GNU Autoconf ======
autoconf 根据configure.ac创建configure
autoheader 根据configure.ac创建configure.h.in
autoreconf 安照恰当的顺序运行所有的工具
autoscan scan sources for common portability problems, and related macros missing from configure.ac
autoupdate 更新configure.ac中废弃的宏
ifnames 把所有的#if/#ifdef…标示符合并成指令
autom4te autoconf的核心。它驱动M4并且实现了上面这些工具大部分特性。不仅在创建configure文件时有用。
GNU Automake ======
automake 从Makefile.am和configure.ac创建Makefile.in
aclocal 在configure.ac中查找第三方宏,并且合并aclocal.m4中得定义
从configure.ac 到configure和config.h.in
autoconf 是一个宏处理器
autoconf 转换configure.ac为configure文件,configure.ac是一个使用宏指令的shell脚本,configure是一个成熟的shell脚本。
autoconf 通过众多的宏去执行公共的配置检查
configure.ac没有shell结构,而只使用宏是不常见的。
当处理configure.ac时,追踪宏的出现是可能的。这也是autoheader创建config.h.in的方法。
只是查找使用#define表示的宏。
真正的宏处理器实际上是GNU M4。autoconf 提供一些M4的顶层结构,加上一个宏池。

AC_INIT
强制autoconf初始化

AC_PREREQ(VERSION)
请求一个最小化的autoconf版本,如AC_PREREQ([2.65])

AC_CONFIG_SRCDIR(FILE)
一个安全检查。FILE应该是一个已分配的源文件,这样就可以确保configure不会从外层空间开始运行。

AC_CONFIG_AUX_DIR(DIRECTORY)
指定辅助脚本如install-sh和depcomp放置的目录。如AC_CONFIG_AUX_DIR([build-aux])
auxiliary scripts such as install-sh and depcomp should be in DIRECTORY. E.g. AC_CONFIG_AUX_DIR([build-aux])

AC_PROG_CC, AC_PROG_CXX, AC_PROG_F77,…
编译器检查。(如果需要可以处理交叉编译程序的搜索)
Compiler checks. (Handle search cross-compilers if needed.)

AC_PROG_SED, AC_PROG_YACC, AC_PROG_LEX, …
查找好的实现并且设置变量$SED, $YACC, $LEX, etc.
Find good implementations and set $SED, $YACC, $LEX, etc.

AC_CHECK_PROGS(VAR, PROGS, [VAL-IF-NOT-FOUND])
定义VAR变量的值为PROGS如果没有找到PROGS则使用第第三个参数VAL-IF-NOT-FOUND得值
Define VAR to the first PROGS found, or to VAL-IF-NOT-FOUND otherwise.
如:
AC_CHECK_PROGS([TAR], [tar gtar], [:])
if test “$TAR” = : ; then
AC_MSG_ERROR([This package needs tar.])
fi

AC_MSG_ERROR(ERROR-DESCRIPTION, [EXIT-STATUS])
打印ERROR-DESCRIPTION并且写入config.log中,然后终止configure
Print ERROR-DESCRIPTION(also to config.log) and abort ‘configure’

AC_MSG_WARN(ERROR-DESCRIPTION)
和AC_MSG_ERROR差不多,只是不停止。

AC_DEFINE(VARIABLE, VALUE, DESCRIPTION)
输出变量到config.h头文件中
Output the following to config.h
如:
/* DESCRIPTION */
#define VARIABLE VALUE

AC_SUBST(VARIABLE, [VALUE])
在生成的Makefile中定义$(VARIABLE)变量,值为VALUE。
Define $(VARIABLE) as VALUE in Makefile
下面三个等价:
AC_SUBST([FOO], [foo])
======================
FOO=foo
AC_SUBST([FOO])
======================
AC_SUBST([FOO])
FOO=foo

AC_CHECK_LIB(LIBRARY, FUNCT, [ACT-IF-FOUND], [ACT-IF-NOT])
检查LIBRARY是否存在并且包含库函数FUNCT。
如果存在执行ACT-IF-FOUND中内容,否则执行ACT-IF-NOT中内容
Check whether LIBRARY exists and contains FUNCT.
Execute ACT-IF-FOUND if it does, ACT-IF-NOT otherwise.
举例:
AC_CHECK_LIB([efence], [malloc], [EFENCELIB=-lefence])
AC_SUBST([EFENCELIB])
检查efence包中有没有malloc函数,然后再Makefile中定义变量EFENCELIB

如果ACT_IF_FOUND没有被设置,并且库被发现,AC_CHECK_LIB将设置
LIBS=”-lLIBRARY $LIBS” 并且#define HAVE_LIBLIBRARY
(Automake 将为每一个链接使用$LIBS)

AC_CHECK_HEADERS(HEADERS…)
检查HEADERS和#define HAVE_HEADER_H 是否存在。
Check for HEADERS and #define HAVE_HEADER_H for each header found.
AC_CHECK_HEADERS([sys/param.h unistd.h])
AC_CHECK_HEADERS([wchar.h])
Might #define HAVE_SYS_PARAM_H, HAVE_UNISTD_H, and HAVE_WCHAR_H.
#if HAVE_UNISTD_H
#include <unistd.h>
#endif

AC_CHECK_HEADER(HEADER, [ACT-IF-FOUND], [ACT-IF-NOT])
只检查一个头文件。
Check only one header.

AC_CONFIG_HEADERS(HAEDERS…)
为所有的HEADER.in创建HEADER。只使用这样一个头文件,除非你知道你想做什么。
(autoheader只为第一个HEADER文件创建HEADER.in)
HEADERS包含用AC_DEFINE创建的定义。
举例:
AC_CONFIG_HEADERS([config.h:config.hin])
将会从config.hin中创建config.h(DJGPP编译器支持一个点好)

AC_CONFIG_FILES(FILES…)
为所有的FILE.in中创建FILE
FILES包含被AC_SUBST创建的定义
举例:
AC_CONFIG_FILES([Makefile sub/Makefile script.sh:script.in])
automake为每个有FILE.am的FILE创建FILE.in。
处理non-Makefiles也是合法的。

script.in举例:
#!/bin/sh
SED=’@SED@’
TAR=’@TAR@’
d=$1; shift; mkdir “$d”
for f; do
“$SED” ‘s/#.*//’ “$f” \
> “$d/$f”
done
“$TAR” cf “$d.tar” “$d”

script.sh举例:
#!/bin/sh
SED=’/usr/xpg4/bin/sed’
TAR=’/usr/bin/tar’
d=$1; shift; mkdir “$d”
for f; do
“SED” ‘s/#.*//’ “$f” \
> “$d/$f”
done
$”TAR” cf “$d.tar” “$d”

.in文件是一个模板,对于AC_SUBST([XYZ])定义的变量使用占位符@XYZ@。
config.status是替换了占位符的结果。
Makefile.in也是使用占位符@XYZ@, 但是automake 会创建XYZ=@XYZ@这种形式的定义,
并且根据需要可以简单的使用$(XYZ) 。

.in files are templates where @XYZ@ are placeholders for AC_SUBST([XYZ]) definitions.
‘config.status’ substitutes them.
Makefile.ins also use @XYZ@ as placeholders but Automake makes all XYZ=@XYZ@ definitions and
you may simply use $(XYZ) as needed.

Automake 原理

1、automake 帮助创建可移植的GNU标准适用的Makefile文件。
你可能使用其它种类的编译系统。(如:没有VPATH被创建,但是所有的对象进入obj/目录)
不要使用automake如果你不喜欢GNU 编译系统:automake 将会按照你的方式来,如果你适应模板。

2、automake 从Makefile.am中创建复杂的Makefile.in。
可以认为Makefile.in是内部细节。

3、Makefile.am 从整体上来说跟Makefile的句法差不多。但是Makefil.am通常只包含变量的定义。
automake 从这些定义中创建编译规则。添加额外的Makefile到Makefile.am中也是可以的。automake将会保存他们到
输出中。

在automake中声明configure.ac
AM_INIT_AUTOMAKE([OPTIONS…])
检查automake需要的工具,这些工具可以生成Makefiles。
有用的选项:
-Wall 打开所有警告选项
-Werror 报告警告作为错误
foreign 放开一些GNU标志要求
1.11.1 需要一个最小版本的automake
dist-bzip2 并且通过‘make fist’和‘make distcheck’创建一个tar.bz2的存档文件。
tar-ustar 创建一个使用ustar格式的tar存档文件

Check for tools needed by ‘automake’-generated Makefiles.
Userful options:
-Wall Turn all warning on.
-Werror Report warning as errors.
foreign Relax some GNU standard requirements.
1.11.1 Require a minimum version of ‘automake’.
dist-bzip2 Also create tar.bz2 archives during ‘make diet ‘ and ‘make distcheck’
tar-ustar Create tar archives using the us tar format.

automake为每一个有FILE.am的FILE创建FILE.in文件。

where_PRIMARY 对于声明的目标的约定。
where_PRIMARY = targets …

targets 会被安装的目录:
bin_$(bindir)
lib_$(libdir)

custom_$(customdir) 自己自定义的目录。 You define customdir.
noinst_ 不按装。 Not installed
check_ 使用make check命令时会创建。Built by ‘make check’

可选项:
dist_ 分配目标(如果没有默认的) Distribute targets(if not the default)
nodist_ 不分配目标。Don’t

targets 会被编译作为:
_PROGRAMS
_LIBRARIES
_LTLIBARAIES(Libtool libraries)
_HEADERS
_SCRIPTS
_DATA

Makefile.am举例:
bin_PROGRAMS = foo run-me
foo_SOURCES = foo.c foo.h print.c print.h
run_me_SOURCES = run.c run.h print.c

这个程序将会被安装到$(bindir)
These programs will be installed in $(bindir)
这个程序的源代码被放进program_SOURCES目录
The sources of each program go into program_SOURCES.
非字母和数字的字符被_下划线代替。
Non-alpahnumeric characters are mapped to ‘_’.
automake 会自动的从这些文件中计算用来编译和链接的对象的列表。
Automake automatically computes the list of objects to build and link from these files.
头文件不会被编译。我们列出他们只是因为他们被分配了。(automake 不分配那些他不了解的文件)
Header files are not compiled. We list them only so they get distributed(Automake does not distribute
files it does not know about)
两个程序中使用同样的源码也是可以的。
It’s OK to use the same source for two programs.
编译器和链接器会被从扩展名中推测出来。
Compiler and linker are inferred from the extensions.

标准文件系统的层级
prefix /usr/local
exec-prefix prefix
bindir exec-prefix/bin
libdir exec-prefix/lib

includedir prefix/include
datarootdir prefix/share
datadir datarootdir
mandir datarootdir/man
infodir datarootdir/info

(Static) Libraries 静态库

添加AC_PROG_RANLIB 到configure.ac.

Makefile.am举例:
lib_LIBRARIES = libfoo.a libbar.a
libfoo_a_SOURCES = foo.c privfoo.h
libbar_a_SOURCES = bar.c privbar.h
include_HEADERS = foo.h bar.h

这个库将会被安装到$(libdir)
库的名字必须符合lib*.a这样的形式。
公共的头文件将会被安装到$(includedir).
Public headers will be installed in $(includedir).
私有的头文件像常规源文件一样,不会被安装。

目录布局
你可能有一个Makefile(因此也有一个Makefile.am)在每个目录。
他们所有必须被声明在configure.ac中。
如:
AC_CONFIG_FILES([Makefile lib/Makefile])
make 运行在顶层目录
‘make’ is run at the top-level
Makefile.am应该固定顺序在使用SUBDIRS变量的递归的目录中。
Makefile.ams should fix the order in which to recurse directories using the SUBDIRS variable.
例如:
Makefile.am
SUBDIRS = lib src

src/Makefile.am
SUBDIRS = dira dirb

当前目录会隐含的被创建在SUBDIRS中得子目录列表最后面。
The current directory is implicitly built after subdirectories.
你能够使用.在任何你想覆盖的地方。
You can put ‘.’ where you want to override this.

$(srcdir) 和 VPATH的创建

1、记住VPATH构建:一个源文件不一定要再当前目录。
Remember VPATH builds: a source file is not necessary in the current directory.

2、有两个成对的树:build 树和source树。
Makefile和objects目标文件在build树中。
Makefile.in,Makefile.am,和源文件在source树中。
如果./configure 运行在当前目录,则这两个树就是一个。

3、在每个Makefile中,config.status将会定义$(srcdir)。$(srcdir)是对应源代码目录的路径。

4、当引用automake的变量中定义的源文件和目标时,不需要担心source和build目录,因为make命令
将会去检查所有这些目录。

5、你可能需要$(srcdir)目录,当需要为工具指定flags或者写入定制的命令的时候。比如说:告诉编译器去从dir/目录中
包含头文件,就需要写成-I$(srcdir)/dir, 而不是 -Idir. (-Idir 将会从build树中查找头文件。)
举例:
lib/Makefile.am
noinst_LIBRARIES = libcompat.a
libcompat_a_SOURCES = xalloc.c xalloc.h
这是一个简易的库,只在创建包得时候使用。

src/Makefile.am
LDADD = ../lib/libcompat.a
AM_CPPFLAGS = -I$(srcdir)/../lib
bin_PROGRAMS = foo run-me
foo_SOURCES = foo.c foo.h print.c print.h
run_me_SOURCES = run.c run.h print.c
run_me_LDADD = ../lib/libcompat.a
run_me_CPPFLAGS = -I$(srcdir)/../lib

当链接所有的程序时,LDADD 将会被添加。
LDADD is added when linking all programs.
AM_CPPFLAGS 包含额外的预处理指令。
AM_CPPFLAGS contains additional preprocessor flags.
你能够使用per-target 变量:他们被应用在单独的应用中。
You can use per-target variables: they apply to a single program.

Per-Target的标志:
假设foo是一个程序或者库:
foo_CFLAGS 额外的C编译器标志
foo_CPPFLAGS 额外的预处理器标志
foo_LDADD 额外的链接objects目标对象, 相当于-lxxx 和 -Lxxx (如果foo是程序时)
foo_LIBADD 额外的链接objects目标对象,相当于-lxxx 和 -Lxxx (如果foo是一个库时)
foo_LDFLAGS 额外的链接器标志

foo_XXXFLAGS的默认值是$(AM_XXXFLAGS)
在你的程序中使用简单的文件名去引用库。(对外部的库只保持使用-l和-L)

Per-Target Flags
Assuming foo is a program or library:
foo_CFLAGS Additional C compiler flags
foo_CPPFLAGS Additional preprocessor flags (-Is and -Ds)
foo_LDADD Additional link objects, -ls and -Ls (if foo is a program)
foo_LIBADD Additional link objects, -ls and -Ls(if foo is a library)
foo_LDFLAGS Additional linker flags

The default value for foo_XXXFLAGS is $(AM_XXXFLAGS).
Use plain file names to refer to libraries inside your package (keep -ls and -Ls for external libraries only).

举例:
configure.ac
AC_CHECK_LIB([efence], [malloc], [EFENCELIB = -lefence])
AC_SUBST([EFENCELIB])

src/Makefile.am
bin_PROGRAMS = foo run-me
foo_SOURCES = foo.c foo.h print.c print.h
run_me_SOURCES = run.c run.h print.c
run_me_CPPFLAGS = -I$(srcdir)/../lib
run_me_LDADD = ../lib/libcompat.a $(EFENCELIB)

make dist和 make distcheck 创建一个tarball 将会包含:
所有的声明在…_SOURCES中得源文件
所有的声明在…_HEADERS中得头文件
所有的使用dist_…_SCRIPTS声明的脚本
所有的用dist_…_DATA声明的数据
。。。
公共文件如ChangLog, NEWS, 等等。
查看 automake –help 获得这些文件的列表。

额外的文件和目录会被列到EXTRA_DIST中。
举例:
Makefile.am
SUBDIRS = lib src
EXTRA_DIST = HACKING
将会额外分配HACKING。

条件句使用
Conditionals: Usage
条件句允许符合条件的创建和不符合条件的分配
Conditionals allow for conditional builds and unconditional distribution.

举例:
有条件的Programs:
bin_PROGRAMS = foo
if WANT_BAR
bin_PROGRAMS += bar
endif
foo_SOURCES = foo.c
bar_SOURCES = bar.c

有条件的Sources:
bin_PROGRAMS = foo
foo_SOURCES = foo.c
if WANT_BAR
foo_SOURCES += bar.c
endif

bar 将会被创建如果WANT_BAR是真。
bar is built if WANT_BAR is true.
如果WANT_BAR为真,则bar.o将会被链接进foo。
bar.o is linked in foo if WANT_BAR is true.
在不考虑WANT_BAR的情况下,foo.c 和 bar.c都会被分配而。
In all case foo.c and bar.c are distributed regardless of WANT_BAR.
这些是可移植的。config.status将会注释掉Makefile.in中那些必须使无效的规则。
This is portable. ‘config.status’ will comment rules of Makefile.in that must be disabled.
在configure.ac中WANT_BAR必须被声明和赋值。
WANT_BAR must be declared and valued in configure.ac.

条件句声明
AM_CONDITONAL(NAME, CONDITION)
声明条件NAME。CONDITON应该是一个shell指令,如果它执行成功则NAME将被置为enabled。
Declare conditional NAME. CONDITION should be a shell instruction that succeeds if NAME should be enabled.

configure.ac
AC_CHECK_HEADER([bar.h], [use_bar=yes])
AM_CONDITIONAL([WANT_BAR], [test "$use_bar" = yes])
只有当bar.h出现在系统中的时候,WANT_BAR才会为enable
Will enable WANT_BAR only if bar.h is present on the system.

扩展的automake规则
Extending Automake Rules

1、Makefile.am中得内容机会被逐字的拷贝到Makefile.in中。
The contents of Makefile.am are copied almost verbatim to Makefile.in.

2、automake 添加新的规则和变量到Makefile.in中,完成你定义的特定变量的语义。
‘automake’ adds new rules and variables in Makefile.in, to achieve the semantics of the special variables
you have defined.

3、一些次要的重写被完成去可移植的处理像条件或者 += 这样的结构。
Some minor rewriting is done to handle constructs like conditionals or += portably.

4.在Makefile.am中定义自己的规则也是可以的。
It’s OK to define your own rules in Makefile.am.

有用的维护target (make style-check)
Helpful maintenance targets(‘make style-check’)

创建特殊的文件(从一些随机的源中生成常见问题的文件)
Build idiosyncratic files (generate a FAQ from some random source)

。。。

5、可以定义对于automake无意义的变量。
It’s OK to define variables that are meaningless to Automake.

被使用在自定义的规则中。
For use in custom rules.

6、 当心冲突:你的定义将会覆盖automake中得定义。
Beware of conflicts: your definitions (of variables or rules) will override those of Automake.

-Wall 将会诊断这些。
-Wall will diagnose these.

推荐
Recommendations

1、使用 -Wall -Werror。
Use -Wall -Werror.

2、保持简单的安装
Keep Your Setup Simple(KYSS!)

如果你的程序自动化程度太高,你将会花费大量的时间去调试你的cunning tricks。
You will spend a large part of time debugging your cunning tricks if you try to automatize too much.

3、不要欺骗automake
Do not lie to Automake.
Automake can be annoying, but when you lie it gets worse!

丢失?autoreconf 一直是你的朋友
Lost? ‘autoreconf’ is Still Your Friend

如果make失败,通过手动运行autoreconf重新创建配置文件。
If ‘make’ fails to rebuild configuration files, run ‘autoreconf’ manually.

举例:
autoreconf –install
如果这些没有帮助,直接硬来。
If this does not help, try harder.

举例:
autoreconf –install –force

如果还是没有帮助,那就再强制使用一次。
If this still does not help, try even harder.

如下:
make -k maintainer-clean
autoreconf –install –force

做这些在你认为必要的时候。每一个这样的命令会造成你的package 花费大量的时间去重新配置和编译。
Do this only when necessary. Each of these commands will cause your package to take longer to
reconfigure and recompile.

定义宏:
Defining Macros
AC_DEFUN(MACRO-NAME, MACRO-BODY)
定义MACRO-NAME 为 MACRO-BODY
Define MACRO-NAME as MACRO-BODY.

避免可能的名字冲突。宏命名空间:
Avoid names that may conflict. Macro name spaces:
m4_ 原始M4宏。
m4_ Original M4 macros, plus M4sugar macros.
AS_ M4sh 宏
AS_ M4sh macros (macroized shell constructs)
AH_ autoheader 宏
AH_ Autoheader macros
AC_ autoconf 宏(被写在顶层)
AC_ Autoconf macros(written on top of the above layers)
AC_CHECK_ 一般检查
AC_CHECK_ Generic checks.
AC_FUNC_ 检查特定的函数。
AC_FUNC_ Specific function checks.
AC_HEADER_ 检查特定的头。
AC_HEADER_ Specific header checks.
AC_PROG_ 检查特定的程序。
AC_PROG_ Specific program checks.
。。。
AM_ automake的宏
AM_ Automake macros
AT_ autotest宏
AT_ Autotest macros

mkdir()的例子:
POSIX 系统定义的mkdir()有两个参数。
Mingw32中mkdir()只有一个参数。
Win32中是_mkdir()只有一个参数。

#if HAVE_MKDIR
#if MKDIR_ONE_ARG
#define mkdir(a, b) mkdir(a)
#endif
#else
#if HAVE__MKDIR
#define mkdir(a, b) _mkdir(a)
#else
#error “Don’t know how to create a directory.”
#endif
#endif

让我妈写一个autoconf 宏去定义这些C宏。
Let’s write an Autoconf macro to define these C macros.

写一个高优先级的宏:AX_FUNC_MKDIR
Writing a High-Level Macro: AX_FUNC_MKDIR

举例:
AC_DEFUN([AX_FUNC_MKDIR],
[AC_CHECK_FUNCS([mkdir _mkdir])
AC_CHECK_HEADERS([io.h])
AX_FUNC_MKDIR_ONE_ARG
])

Libtool库的版本:跳跃版本
Versioning Libtool Libraries: Bumping Versions

在发布版之前记住跳跃库版本。
Remenber to bump library versions before a release.

假设旧版本为CURRENT:REVERSION:AGE。
Suppose the old version was CURRENT:REVERSION:AGE.

如果没有改变接口 CURRENT:REVERION+1:AGE
not changed the interface(bug fixes)

接口中添加了函数 CURRENT+1:0:AGE+1
augmented the interface
(new functions)

破坏了原来的接口 CURRENT+1:0:0
broken old interface
(e.g. removed functions)

介绍Gettext
Introducting Gettext

国际化
Internationalization (I18n)
改变程序去支持多语言和文化习惯
Changing a program to support for multiple languages and cultural habits.

字符处理(unicode)
Character handling(unicode…)

本地发现
Locale awareness(date formats, currencies, numbers, time zones, etc.)

本地化
Localizability

本地化
Localization (L10n)
提供一个国际化的包去支持一个本地语言和文化习惯

Gettext 一个完整得工具集,可以完成翻译输出信息的功能
Gettext = complete toolset for translating messages output by programs.

举例:
#include <config.h>
#include <stdio.h>
#include “gettext.h”
#define _(string) gettext(string)
void say_hello(void) {
puts(_(“Hello World!”));
printf(_(“This is %s.\n”), PACKAGE_STRING);
}

被翻译的信息用_()标志。


地址:http://blog.vokaa.org/category/c/c-%E7%BC%96%E8%AF%91/