autotools使用

本文最后更新于 2022年5月10日 晚上

基本流程

基本流程为:

  1. 使用autoscan生成configure.scan文件,然后重命名为configure.ac
    configure.ac里面包含一些自动检查的内容
  2. 执行aclocal,configure.ac中的宏实际上是m4宏的一个封装,这条命令将会吧ac宏解析成m4宏
  3. 执行autoconf, 它会生成configure脚本
  4. 执行autoheader,它会根据configure.ac中的内容生成一些预定义信息
  5. Makefile.am中包含了程序编译链接信息,也就是makefile的主体内容,执行automake会生成Makefile的前置文件
  6. 执行./configure会生成Makefile文件

configure是检查系统设置,库函数是否满足等运行环境判断,Makefile.am则是真正的进行编译

configure.ac

autoconf基于此

首先介绍m4,m4是一个宏处理器,它会扫描文本,如果遇到宏则将其展开。

我们可以简单的认为他将shell脚本套上了一层函数的壳,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 检测是否安装foo程序的shell
if [ $(which foo) ]
then
echo "checking foo ... yes!"
else
echo "You should install foo!"
exit -1
fi

// check-foo.m4中脚本为
define(`check-foo', `
if [ $(which foo) ]
then
echo "checking foo ... yes!"
else
echo "You should install foo!"
exit -1
fi
')

然后在configure.ac中使用include(check-foo.m4),再运行m4 configure.ac就可以在生成文件中得到这个宏的展开结果

而autoconf其实是给m4套上了一层外壳,例如:

1
2
3
4
5
6
7
8
9
将check-foo.m4中文件内容修改为
AC_DEFUN([CHECK_FOO],
[if {% post_link $(which foo) %}
then
echo "checking foo ... yes!"
else
echo "You should install foo!"
exit -1
fi])

然后将configure.ac中的内容修改为:

1
2
AC_INIT
CHECK_FOO

运行下面命令
1
2
3
aclocal -I m4 // check-foo.m4在m4目录中
autoconf
./configure

如果系统中没有foo则会提示

1
2
which: no foo in (/bin:/usr/bin:/usr/local/bin)
You should install foo!

也就是说autoconf时自动将CHECK_FOO宏展开,而aclocal则是在本地文件中扫描是否有configure.ac中定义的宏

常用的autoconf宏

宏名 格式 说明
AC_PREREQ (version) 确定autoconf版本,它是在AC_INIT前唯一使用的宏
AC_INIT (package,version,[bug-report],[tarname],[url]) 默认生成的文件打包名为: tarname-version.tar.gz
AC_SUBST AC_SUBST(GLIB2_CFLAGS) 输出能被Makefile.am使用的变量
AC_ARG_ENABLE AC_ARG_ENABLE([gstaudio],AS_HELP_STRING([—enable-gstaudio=@:@yes/auto/no@:@], [Enable the GStreamer 1.0 audio backend @:@default=auto@:@]),[],[enable_gstaudio=”auto”]) 为configure添加—XX选项
AC_CHECK_HEADERS AC_CHECK_HEADERS(head_path1 head_path2…) 检测是否存在头文件
AC_CONFIG_SRCDIR (unique-file-in-source-dir) 检测源码是否存在,保证项目目录是正确的目录
AC_CONFIG_AUXDIR 指定辅助脚本文件目录
AC_CONFIG_HEADERS ([config.h]) 用于实例化config.h头文件
AC_CONFIG_FILES (filename) 指定输出的文件,如AC_CONFIG_FILE(Makefile),他会根据Makefile.in生成Makefile文件
AC_PROG_CC 自动检测gcc
AC_PROG_LIBTOOLS 自动检测libtools
AC_CHECK_FUNCS AC_CHECK_FUNCS([func1 func2 func3]) 检测对应函数是否可用
AC_SEARCH_LIBS AC_SEARCH_LIBS (function, search-libs, [action-if-found], [action-if-not-found], [other-libraries]) 在search-libs中检测function是否存在
AC_OUTPUT 用于创建configure.status,他用来创建Makefile, 一般在最后一行 AS_IF AS_IF (test1, [run-if-true1], …, [run-if-false]) 执行检测,如果成功执行第一条,如果第一条不成功执行第二条,以此类推

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

AC_PREREQ(2.61)
AC_INIT(sqlite, 3.38.5, http://www.sqlite.org)
AC_CONFIG_SRCDIR([sqlite3.c]) # 检测当前目录下是否存在sqlite3.c
AC_CONFIG_AUX_DIR([.])

# Use automake.
AM_INIT_AUTOMAKE([foreign])

AC_SYS_LARGEFILE

# Check for required programs.
AC_PROG_CC
AC_PROG_LIBTOOL
AC_PROG_MKDIR_P

# Check for library functions that SQLite can optionally use.
AC_CHECK_FUNCS([fdatasync usleep fullfsync localtime_r gmtime_r])
AC_FUNC_STRERROR_R

AC_CONFIG_FILES([Makefile sqlite3.pc])
BUILD_CFLAGS=
AC_SUBST(BUILD_CFLAGS)

AC_OUTPUT

Makefile.am

  1. PLV
    目标列表变量,用于指定目标文件,定义为: prefix_PRIMARY = product1 product2 ...
    常见前缀有:

    | 名称 | 说明|
    |-|-|
    | bin | 可执行程序安装位置,默认为 /usr/local/bin |
    | lib | 库文件安装位置,默认为 /usr/local/lib |
    | noinst | 生成但不安装,常用于静态库 |
    | check | 测试构建的目标,无需安装 |

    主变量有:

    |名称 | 说明 |
    |-|-|
    | PROGRAMS | 执行程序 |
    | LIBRARIES | 静态库 |
    | LTLIBRARIES | libtool生成的库(.la)|

  2. PSV
    目标源文件变量,指定目标文件的源文件列表,格式如下product_SOURCES = file1 file2 ...
  3. POV
    目标选项变量,常用的选项有:

    | 名称 | 说明 |
    |-|-|
    | product_CPPFLAGS | 预处理器参数 |
    | product_LDFLAGS | 链接参数,如-static -shared -L等 |
    | library_LIBADD | 将非Libtool的.o目标文件传给ar命令,生成静态库 |
    | product_CFLAGS | 编译器参数,如-g -Wall -I等 |
    | program_LDADD | 将静态库或.la传给链接器,用于链接生成可执行程序 |
    | library_LIBADD | 将LibTool的.lo文件添加到LibTool库文件 |

1
2
3
4
5
6
AUTOMAKE_OPTIONS = foreign // 检查等级
bin_PROGRAMS = hello // 生成的可执行程序
hello_sources = hello.c // hello需要的源文件
hello_LDADD = libcn.a // 补充的静态库
noinst_LIBRARIES = libcn.a // 生成静态库
libcn_a_SOURCES = cn.c // libcn.a需要的源文件

目标源文件变量中的product只支持字母,数字和下划线,因此他会将所有其他字符识别为下划线,因此libcn.a变成了libcn_a

实例

本例子为sqlite的源文件

configure.ac

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270

#-----------------------------------------------------------------------
# Supports the following non-standard switches.
#
# --enable-threadsafe
# --enable-readline
# --enable-editline
# --enable-static-shell
# --enable-dynamic-extensions
#

AC_PREREQ(2.61)
AC_INIT(sqlite, 3.38.5, http://www.sqlite.org) # 名称,版本,网站,邮箱等信息
AC_CONFIG_SRCDIR([sqlite3.c]) # 检测当前目录下是否存在sqlite3.c
AC_CONFIG_AUX_DIR([.]) # 指定辅助文件存放目录

# Use automake.
AM_INIT_AUTOMAKE([foreign]) # 确定automake检查级别

AC_SYS_LARGEFILE # 可以使用大文件的宏

# Check for required programs.
AC_PROG_CC # 自动检测要使用的gcc
AC_PROG_LIBTOOL
AC_PROG_MKDIR_P

# Check for library functions that SQLite can optionally use.
AC_CHECK_FUNCS([fdatasync usleep fullfsync localtime_r gmtime_r])
AC_FUNC_STRERROR_R # 检测strerror_r函数

AC_CONFIG_FILES([Makefile sqlite3.pc]) # 指定输出文件
BUILD_CFLAGS=
AC_SUBST(BUILD_CFLAGS) # 输出能被Makefile.am使用的变量

#-------------------------------------------------------------------------
# Two options to enable readline compatible libraries:
#
# --enable-editline
# --enable-readline
#
# Both are enabled by default. If, after command line processing both are
# still enabled, the script searches for editline first and automatically
# disables readline if it is found. So, to use readline explicitly, the
# user must pass "--disable-editline". To disable command line editing
# support altogether, "--disable-editline --disable-readline".
#
# When searching for either library, check for headers before libraries
# as some distros supply packages that contain libraries but not header
# files, which come as a separate development package.
#
AC_ARG_ENABLE(editline, [AS_HELP_STRING([--enable-editline],[use BSD libedit])]) # 添加editline选项
AC_ARG_ENABLE(readline, [AS_HELP_STRING([--enable-readline],[use readline])])

AS_IF([ test x"$enable_editline" != xno ],[ # 如果有editline选项
AC_CHECK_HEADERS([editline/readline.h],[ # 检测是否存在readline头文件
sLIBS=$LIBS
LIBS=""
AC_SEARCH_LIBS([readline],[edit],[ # 检测edit库中是否存在readline
AC_DEFINE([HAVE_EDITLINE],1,Define to use BSD editline) # 失败操作
READLINE_LIBS="$LIBS -ltinfo"
enable_readline=no
],[],[-ltinfo])
AS_UNSET(ac_cv_search_readline)
LIBS=$sLIBS
])
])

AS_IF([ test x"$enable_readline" != xno ],[
AC_CHECK_HEADERS([readline/readline.h],[
sLIBS=$LIBS
LIBS=""
AC_SEARCH_LIBS(tgetent, termcap curses ncurses ncursesw, [], [])
AC_SEARCH_LIBS(readline,[readline edit], [
AC_DEFINE([HAVE_READLINE],1,Define to use readline or wrapper)
READLINE_LIBS=$LIBS
])
LIBS=$sLIBS
])
])

AC_SUBST(READLINE_LIBS)
#-----------------------------------------------------------------------

#-----------------------------------------------------------------------
# --enable-threadsafe
#
AC_ARG_ENABLE(threadsafe, [AS_HELP_STRING(
[--enable-threadsafe], [build a thread-safe library [default=yes]])],
[], [enable_threadsafe=yes])
if test x"$enable_threadsafe" == "xno"; then
BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_THREADSAFE=0"
else
BUILD_CFLAGS="$BUILD_CFLAGS -D_REENTRANT=1 -DSQLITE_THREADSAFE=1"
AC_SEARCH_LIBS(pthread_create, pthread)
AC_SEARCH_LIBS(pthread_mutexattr_init, pthread)
fi
#-----------------------------------------------------------------------

#-----------------------------------------------------------------------
# --enable-dynamic-extensions
#
AC_ARG_ENABLE(dynamic-extensions, [AS_HELP_STRING(
[--enable-dynamic-extensions], [support loadable extensions [default=yes]])],
[], [enable_dynamic_extensions=yes])
if test x"$enable_dynamic_extensions" != "xno"; then
AC_SEARCH_LIBS(dlopen, dl)
else
BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_OMIT_LOAD_EXTENSION=1"
fi
AC_MSG_CHECKING([for whether to support dynamic extensions])
AC_MSG_RESULT($enable_dynamic_extensions)
#-----------------------------------------------------------------------

#-----------------------------------------------------------------------
# --enable-math
#
AC_ARG_ENABLE(math, [AS_HELP_STRING(
[--enable-math], [SQL math functions [default=yes]])],
[], [enable_math=yes])
AC_MSG_CHECKING([SQL math functions])
if test x"$enable_math" = "xyes"; then
BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_MATH_FUNCTIONS"
AC_MSG_RESULT([enabled])
AC_SEARCH_LIBS(ceil, m)
else
AC_MSG_RESULT([disabled])
fi
#-----------------------------------------------------------------------

#-----------------------------------------------------------------------
# --enable-fts4
#
AC_ARG_ENABLE(fts4, [AS_HELP_STRING(
[--enable-fts4], [include fts4 support [default=yes]])],
[], [enable_fts4=yes])
AC_MSG_CHECKING([FTS4 extension])
if test x"$enable_fts4" = "xyes"; then
BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_FTS4"
AC_MSG_RESULT([enabled])
else
AC_MSG_RESULT([disabled])
fi
#-----------------------------------------------------------------------

#-----------------------------------------------------------------------
# --enable-fts3
#
AC_ARG_ENABLE(fts3, [AS_HELP_STRING(
[--enable-fts3], [include fts3 support [default=no]])],
[], [])
AC_MSG_CHECKING([FTS3 extension])
if test x"$enable_fts3" = "xyes" -a x"$enable_fts4" = "xno"; then
BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_FTS3"
AC_MSG_RESULT([enabled])
else
AC_MSG_RESULT([disabled])
fi
#-----------------------------------------------------------------------

#-----------------------------------------------------------------------
# --enable-fts5
#
AC_ARG_ENABLE(fts5, [AS_HELP_STRING(
[--enable-fts5], [include fts5 support [default=yes]])],
[], [enable_fts5=yes])
AC_MSG_CHECKING([FTS5 extension])
if test x"$enable_fts5" = "xyes"; then
AC_MSG_RESULT([enabled])
AC_SEARCH_LIBS(log, m)
BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_FTS5"
else
AC_MSG_RESULT([disabled])
fi
#-----------------------------------------------------------------------

#-----------------------------------------------------------------------
# --enable-rtree
#
AC_ARG_ENABLE(rtree, [AS_HELP_STRING(
[--enable-rtree], [include rtree support [default=yes]])],
[], [enable_rtree=yes])
AC_MSG_CHECKING([RTREE extension])
if test x"$enable_rtree" = "xyes"; then
BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_GEOPOLY"
AC_MSG_RESULT([enabled])
else
AC_MSG_RESULT([disabled])
fi
#-----------------------------------------------------------------------

#-----------------------------------------------------------------------
# --enable-session
#
AC_ARG_ENABLE(session, [AS_HELP_STRING(
[--enable-session], [enable the session extension [default=no]])],
[], [])
AC_MSG_CHECKING([Session extension])
if test x"$enable_session" = "xyes"; then
BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_SESSION -DSQLITE_ENABLE_PREUPDATE_HOOK"
AC_MSG_RESULT([enabled])
else
AC_MSG_RESULT([disabled])
fi
#-----------------------------------------------------------------------

#-----------------------------------------------------------------------
# --enable-debug
#
AC_ARG_ENABLE(debug, [AS_HELP_STRING(
[--enable-debug], [build with debugging features enabled [default=no]])],
[], [])
AC_MSG_CHECKING([Build type])
if test x"$enable_debug" = "xyes"; then
BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_DEBUG -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE"
CFLAGS="-g -O0"
AC_MSG_RESULT([debug])
else
AC_MSG_RESULT([release])
fi
#-----------------------------------------------------------------------

#-----------------------------------------------------------------------
# --enable-static-shell
#
AC_ARG_ENABLE(static-shell, [AS_HELP_STRING(
[--enable-static-shell],
[statically link libsqlite3 into shell tool [default=yes]])],
[], [enable_static_shell=yes])
if test x"$enable_static_shell" = "xyes"; then
EXTRA_SHELL_OBJ=sqlite3-sqlite3.$OBJEXT
else
EXTRA_SHELL_OBJ=libsqlite3.la
fi
AC_SUBST(EXTRA_SHELL_OBJ)
#-----------------------------------------------------------------------

AC_CHECK_FUNCS(posix_fallocate)
AC_CHECK_HEADERS(zlib.h,[
AC_SEARCH_LIBS(deflate,z,[BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_HAVE_ZLIB"])
])

AC_SEARCH_LIBS(system,,,[SHELL_CFLAGS="-DSQLITE_NOHAVE_SYSTEM"])
AC_SUBST(SHELL_CFLAGS)

#-----------------------------------------------------------------------
# UPDATE: Maybe it's better if users just set CFLAGS before invoking
# configure. This option doesn't really add much...
#
# --enable-tempstore
#
# AC_ARG_ENABLE(tempstore, [AS_HELP_STRING(
# [--enable-tempstore],
# [in-memory temporary tables (never, no, yes, always) [default=no]])],
# [], [enable_tempstore=no])
# AC_MSG_CHECKING([for whether or not to store temp tables in-memory])
# case "$enable_tempstore" in
# never ) TEMP_STORE=0 ;;
# no ) TEMP_STORE=1 ;;
# always ) TEMP_STORE=3 ;;
# yes ) TEMP_STORE=3 ;;
# * )
# TEMP_STORE=1
# enable_tempstore=yes
# ;;
# esac
# AC_MSG_RESULT($enable_tempstore)
# AC_SUBST(TEMP_STORE)
#-----------------------------------------------------------------------

AC_OUTPUT

Makefile.am

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

AM_CFLAGS = @BUILD_CFLAGS@ // @...@是特殊的语法,它引用configure.ac中定义的变量
lib_LTLIBRARIES = libsqlite3.la
libsqlite3_la_SOURCES = sqlite3.c
libsqlite3_la_LDFLAGS = -no-undefined -version-info 8:6:8

bin_PROGRAMS = sqlite3
sqlite3_SOURCES = shell.c sqlite3.h
EXTRA_sqlite3_SOURCES = sqlite3.c
sqlite3_LDADD = @EXTRA_SHELL_OBJ@ @READLINE_LIBS@
sqlite3_DEPENDENCIES = @EXTRA_SHELL_OBJ@
sqlite3_CFLAGS = $(AM_CFLAGS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_ENABLE_STMTVTAB -DSQLITE_ENABLE_DBSTAT_VTAB $(SHELL_CFLAGS)

include_HEADERS = sqlite3.h sqlite3ext.h

EXTRA_DIST = sqlite3.1 tea Makefile.msc sqlite3.rc sqlite3rc.h README.txt Replace.cs Makefile.fallback
pkgconfigdir = ${libdir}/pkgconfig
pkgconfig_DATA = sqlite3.pc

man_MANS = sqlite3.1

autotools使用
https://www.xinhecuican.tech/post/94468308.html
作者
星河璀璨
发布于
2022年5月9日
许可协议