学习Autoconf

Last Updated: 2023-06-02 09:54:14 Friday

-- TOC --

GNU做得工具真是强大,这一套自动配置Makefile,以及后续编译安装的工具链,也出自它。很多著名的开源项目,特别是有年头的,都使用autoconf。(cmake是后来出的,相对简单一点,但它们都要基于更基础的make工具)

Autoconf is part of the GNU Autotools build system. Autotools is a collection of three main packages: autoconf, automake, and libtools. Each of the package has smaller sub-packages including autoheader, aclocal, autoscan etc.

autoconf官网:https://www.gnu.org/software/autoconf/

configure.ac --> configure --> Makefile,configure.ac就是基于m4的简化版的shell脚本,configure是完整版的。

简单理解m4

autoconf语法,就是m4 macro + shell script.

Gnu m4 macro is an implementation of the traditional UNIX macro processor. By using m4, you can easily create portable shell script, include different pre-defined macros, and define your own extensions easily. In short, autoconf syntax is shell script wrapped by gnu m4 macro.

现在日子应该比以前好了吧,bash基本上统一了天下。

In the early days, writing portable shell scripts wasn’t that easy. For example not all the mkdir support -p option, not all the shells are bash compatible, etc. Using the m4 macro to perform the regular shell logics, like AS_IF instead if if [[ ]]; then..., AS_MKDIR_P instead of mkdir -p, AS_CASE instead of case ... esac makes your configure script works better on all unix/unix-like environment, and more conventional. Most of the time you’ll be using macros instead of bare bone shell script, but keep in mind that behind the scene your final output is still shell script.

m4基本上就是定义macro和替换macro,很像C语言的宏替换。所谓的编译,就是从configure.ac到configure,后者就是一个shell脚本,所有的m4 macro,都被替换掉了。

# define a macro MY_MACRO that expands to text ABC
m4_define([MY_MACRO], [ABC])
MY_MACRO => ABC

# define a macro that is visible to other m4 scripts
AC_DEFUN([MY_MACRO], [ABC])
MY_MACRO => ABC

所有的符号都是可扩展的,因此那些不要扩展的符号,要用[]括起来。这就是在configure.ac中直接写shell脚本不能用[]的原因。

ABC="hello world"     # m4 would TRY to expand ABC, hello, and world
[ABC="hello world"]   # m4 would just produce ABC="hello world" to the output

不能被替换的部分(shell脚本),会在编译(autoreconf)后保留下来,连注释也都完整保留。因此,这里所谓的编译,就是macro replacement!

安装autoconf工具链

下面熟悉的配置,编译和安装开源软件的流程,就是在使用autoconf:

./configure
make
sudo make install

一般开源项目发布的版本,已经包含生成的configure脚本,用于生成项目的Makefile文件,直接执行此configure,不需要autoconf工具链。但是如果中间出了什么问题,还是可能需要的:

$ sudo dnf install autoconf automake libtool gettext-devel

gettext-devel用来得到autopoint工具。

hello autoconf

$ mkdir hello
$ cd hello
$ touch configure.ac  # ac: autoconf
$ touch Makefile.am   # am: automake
$ touch hello.c

下面是这3个文件的内容:

$ cat configure.ac
# Must init the autoconf setup
AC_INIT([hello], [1.0], [12345@qq.com])

# Safety checks in case user overwritten --srcdir
AC_CONFIG_SRCDIR([hello.c])

# Store the auxiliary build tools (e.g., install-sh, config.sub, config.guess)
# in this dir (build-aux)
AC_CONFIG_AUX_DIR([build-aux])

# Init automake, and specify this program use relaxed structures.
# i.e. this program doesn't follow the gnu coding standards, and doesn't have
# ChangeLog, COPYING, AUTHORS, INSTALL, README etc. files.
# 这里的-Werror应该与最后传递给gcc的不一样,只是书写一样!
AM_INIT_AUTOMAKE([-Wall -Werror foreign])

# Check for C compiler
AC_PROG_CC
# We can add more checks in this section

# Tells automake to create a Makefile
# See https://www.gnu.org/software/automake/manual/html_node/Requirements.html
AC_CONFIG_FILES([Makefile])

# Generate the output
AC_OUTPUT


$ cat Makefile.am
bin_PROGRAMS = hello
hello_SOURCES = hello.c


$ cat hello.c
#include <stdio.h>


int main(){
    printf("hello autoconf\n");
    return 0;
}

然后,生成configure:

$ autoreconf -vif  # configure.ac --> configure

每次修改configure.ac文件,都要执行上面的命令,重新生成。

接着,开始熟悉的节奏:

$ ./configure
$ make
$ ./hello  # test hello

configure.ac

configure.ac文件的语法,就是一行行的Macro_Name([param1],[param2],...),autoconf的macro系统会将其展开成shell脚本,后者才真正做各种检查。也因此,我们也可以直接在configure.ac文件中编写shell脚本,只是不能使用[],会被autoconf错误地展开。

The syntax for configure.ac is MACRO_NAME([param-1],[param-2]..). The parameter passed to the macro must be quoted by square brackets, (unless it is another macro that you want to expand BEFORE calling the outer macro, which is very rare). The macros will expands to shell script that perform the actual checks. You can also write shell script in your configure.ac file. Just one difference, you should use if test ; then... instead of if [[ ]]; then... for condition branching, because the square brackets would get expanded by the autoconf macro system.

这是每个configure.ac的第一条指令。

In every autoconf configure script, you must first initialize autoconf with this macro. The square braket that wraps around each parameter cannot be omitted.

Next we specify a unique file identifying we are in the right directory. This is a safety check in case user override the –srcdir command line option.

为辅助工具指定一个独立的目录。

By default autoconf will create many auxiliary files that help to build and distribute the programs. However we don’t want to have these files to mess up the project home directory. In convention we call this macro with [build-aux] so that it put these extra files in build-aux/ instead of project home.

这里写上关键词foreign的好处,是不用遵守gnu标准,automake不会抱怨项目中没有README等文件。

Initializes automake. An important note here is in early phase of your project development, you probably want to provide the option foreign to init automake. If foreign wasn’t provided, automake will complain that your project didn’t confirm to gnu coding standards, which would require you to have README, ChangLog, AUTHORS, and many other files in your project’s home directory.

Checks for a valid C compiler. There are hundreds more checks you can put in this section.

Required by automake to create the output file. Here we simply put the Makefile in.

Creates the configure script

打印信息,如果是error,configure脚本会停止运行。

# Printing regular message
AC_MSG_NOTICE([Greetings from Autoconf])

# Prints an error message and stops the configure script
AC_MSG_ERROR([We have an error here!]

automake

Unlike autoconf, automake is not using m4 to extend the syntax. It uses a naming convention that converts to the actual logic.

Makefile.am

默认安装路径为/usr/local/bin,可以在执行configure时,用--prefix修改。

The output is a PROGRAM (other options are LIBRARY, HEADER, MAN, etc.) named hello, and will be installed in bin directory (default to /usr/local/bin, but can be configured when invoking ./configure.

bin表示安装路径,PROGRAMS表示类型(其它类型如LIBRARIES),hello就是输出的程序名。

The sources of hello program is hello.c

hello是前面定义的名称,SOURCES定义源,用于PROGRAMS或LIBRARIES类型。

make targets

生成的Makefile中,有好些常见的targets:

make
make all           # same with make
make install
make install-strip # Same as make install, then strip debugging symbols.
make uninstall     # The opposite of make install
make clean         # Erase from the build tree
make maintainer-clean  # Erase files that generated by autoconf
make distclean     # Additionally erase anything ./configure created.
make check         # Run the test suite, if any.
make installcheck  # Check the installed programs or libraries, if supported.
make dist          # Recreate package-version.tar.gz from all the source files.

替换configure默认参数

Some influential environment variables:
  CC          C compiler command
  CFLAGS      C compiler flags
  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
              nonstandard directory <lib dir>
  LIBS        libraries to pass to the linker, e.g. -l<library>
  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
              you have headers in a nonstandard directory <include dir>

Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.

我们可以在执行configure的时候,指定C编译器,编译选项等等,例如:

$ ./configure CC=/usr/bin/clang \  # default is gcc
              CFLAGS='-Wall -Wextra -O3' # defautl is -g -O2   

CC和CFLAGS放在configure后面,表示它们是传入的参数,$1和$2,不是环境变量。可见configure内部肯定要对参数进行复杂的计算。

make也可以做这样的替换。

本文链接:https://cs.pynote.net/sf/c/cdm/202305311/

-- EOF --

-- MORE --