Yanyg - Software Engineer

GNU Autotools (autoconf, automake, libtool) 编译简单示例

目录

Fist publish in https://blog.csdn.net/cppgp/article/details/7258875

1 操作平台: Linux

2 软件包安装(Debian)

~$ yes | sudo apt-get install gcc make autoconf automake libtool

3 从一个例子谈起。

3.1 example

完整拷贝如下代码直接在终端执行或者保存为auto-example.sh,添加执行权限执行。或者参考2.1~2.5逐步执行。

echo "create directory ..."
echo_exit()
{
    echo "ERROR: $@"
    exit 1
}

# 1.
mkdir hello && cd hello || echo_exit "mkdir hello or cd hello failed"
cat > hello.c <<EOF || echo_exit "generates hello.c failed"
#include <stdio.h>
int main()
{
    printf("hello auto-tools!\n");
    return 0;
}
EOF

# 2.
cat > Makefile.am << EOF || echo_exit "generates Makefile.am failed"
bin_PROGRAMS = hello
hello_SOURCES = hello.c
EOF

# 3.
cat > configure.ac << EOF || echo_exit "generates configure.ac failed"
#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

AC_PREREQ([2.67])
AC_INIT([hello], [1.0], [[email protected]])
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
AC_CONFIG_SRCDIR([hello.c])
AC_CONFIG_HEADERS([config.h])

# Checks for programs.
AC_PROG_CC

# Checks for libraries.

# Checks for header files.

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.

AC_CONFIG_FILES([Makefile])
AC_OUTPUT
EOF

# 4.
autoreconf --install || echo_exit "autoreconf --install failed"

# 5.
./configure && make || echo_exit "configure or make failed"

# 6.
make dist && make distcheck || echo_exit "make dist && make distcheck failed"

echo "All Do Over Success"

3.2 创建hello目录和源代码hello.c:

~$ mkdir hello && cd hello
~$ cat > hello.c <<EOF
#include <stdio.h>
int main()
{
    printf("hello auto-tools!\n");
    return 0;
}
EOF

3.3 创建 Makefile.am

~$ cat > Makefile.am << EOF
bin_PROGRAMS = hello
hello_SOURCES = hello.c
EOF

3.4 用 autoscan 生成configure.ac的模板configure.scan

~$ autoscan
~$ cat configure.scan
#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

AC_PREREQ([2.67])
AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS])
AC_CONFIG_SRCDIR([hello.c])
AC_CONFIG_HEADERS([config.h])

# Checks for programs.
AC_PROG_CC

# Checks for libraries.

# Checks for header files.

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.

AC_CONFIG_FILES([Makefile])
AC_OUTPUT

需要修改configure.scan的不问内容并保存为configure.ac。为了方便,直接用如下指令生成configure.ac:

~$ cat > configure.ac << EOF
#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

AC_PREREQ([2.67])
AC_INIT([hello], [1.0], [[email protected]])
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
AC_CONFIG_SRCDIR([hello.c])
AC_CONFIG_HEADERS([config.h])

# Checks for programs.
AC_PROG_CC

# Checks for libraries.
# Checks for header files.
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
EOF

可以看出,只是修改了AC_INIT行,并添加了AM_INIT_AUTOMAKE行。

3.5 使用autoreconf直接生成可执行configure并执行编译:

~$ autoreconf --install
configure.ac:6: installing `./install-sh'
configure.ac:6: installing `./missing'
Makefile.am: installing `./depcomp'
~$ ./configure
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables...
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking for style of include used by make... GNU
checking dependency style of gcc... gcc3
configure: creating ./config.status
config.status: creating Makefile
config.status: creating config.h
config.status: executing depfiles commands
~$ make
make  all-am
make[1]: Entering directory `/tmp/hello'
gcc -DHAVE_CONFIG_H -I.     -g -O2 -MT hello.o -MD -MP -MF .deps/hello.Tpo -c -o hello.o hello.c
mv -f .deps/hello.Tpo .deps/hello.Po
gcc  -g -O2   -o hello hello.o
make[1]: Leaving directory `/tmp/hello'
~$ ./hello
hello auto-tools!

3.6 生成发行包并检测完整性:

~$ make dist && make distcheck
/bin/sh ./config.status --recheck
running CONFIG_SHELL=/bin/sh /bin/sh ./configure --no-create --no-recursion
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables...
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking for style of include used by make... GNU
checking dependency style of gcc... gcc3
configure: creating ./config.status
 /bin/sh ./config.status
config.status: creating Makefile
config.status: creating config.h
config.status: config.h is unchanged
config.status: executing depfiles commands
{ test ! -d "hello-1.0" || { find "hello-1.0" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -fr "hello-1.0"; }; }
test -d "hello-1.0" || mkdir "hello-1.0"
test -n "" \
    || find "hello-1.0" -type d ! -perm -755 \
            -exec chmod u+rwx,go+rx {} \; -o \
      ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
      ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
      ! -type d ! -perm -444 -exec /bin/sh /tmp/hello/install-sh -c -m a+r {} {} \; \
    || chmod -R a+r "hello-1.0"
tardir=hello-1.0 && /bin/sh /tmp/hello/missing --run tar chof - "$tardir" | GZIP=--best gzip -c >hello-1.0.tar.gz
{ test ! -d "hello-1.0" || { find "hello-1.0" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -fr "hello-1.0"; }; }
{ test ! -d "hello-1.0" || { find "hello-1.0" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -fr "hello-1.0"; }; }
test -d "hello-1.0" || mkdir "hello-1.0"
test -n "" \
    || find "hello-1.0" -type d ! -perm -755 \
            -exec chmod u+rwx,go+rx {} \; -o \
      ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
      ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
      ! -type d ! -perm -444 -exec /bin/sh /tmp/hello/install-sh -c -m a+r {} {} \; \
    || chmod -R a+r "hello-1.0"
tardir=hello-1.0 && /bin/sh /tmp/hello/missing --run tar chof - "$tardir" | GZIP=--best gzip -c >hello-1.0.tar.gz
{ test ! -d "hello-1.0" || { find "hello-1.0" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -fr "hello-1.0"; }; }
case 'hello-1.0.tar.gz' in \
    *.tar.gz*) \
      GZIP=--best gzip -dc hello-1.0.tar.gz | /bin/sh /tmp/hello/missing --run tar xf - ;;\
    *.tar.bz2*) \
      bzip2 -dc hello-1.0.tar.bz2 | /bin/sh /tmp/hello/missing --run tar xf - ;;\
    *.tar.lzma*) \
      lzma -dc hello-1.0.tar.lzma | /bin/sh /tmp/hello/missing --run tar xf - ;;\
    *.tar.xz*) \
      xz -dc hello-1.0.tar.xz | /bin/sh /tmp/hello/missing --run tar xf - ;;\
    *.tar.Z*) \
      uncompress -c hello-1.0.tar.Z | /bin/sh /tmp/hello/missing --run tar xf - ;;\
    *.shar.gz*) \
      GZIP=--best gzip -dc hello-1.0.shar.gz | unshar ;;\
    *.zip*) \
      unzip hello-1.0.zip ;;\
    esac
chmod -R a-w hello-1.0; chmod a+w hello-1.0
mkdir hello-1.0/_build
mkdir hello-1.0/_inst
chmod a-w hello-1.0
test -d hello-1.0/_build || exit 0; \
    dc_install_base=`CDPATH="${ZSH_VERSION+.}:" && cd hello-1.0/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
      && dc_destdir="${TMPDIR-/tmp}/am-dc-$/" \
      && am__cwd=`pwd` \
      && CDPATH="${ZSH_VERSION+.}:" && cd hello-1.0/_build \
      && ../configure --srcdir=.. --prefix="$dc_install_base" \
         \
      && make  \
      && make  dvi \
      && make  check \
      && make  install \
      && make  installcheck \
      && make  uninstall \
      && make  distuninstallcheck_dir="$dc_install_base" \
            distuninstallcheck \
      && chmod -R a-w "$dc_install_base" \
      && ({ \
           (cd ../.. && umask 077 && mkdir "$dc_destdir") \
           && make  DESTDIR="$dc_destdir" install \
           && make  DESTDIR="$dc_destdir" uninstall \
           && make  DESTDIR="$dc_destdir" \
                distuninstallcheck_dir="$dc_destdir" distuninstallcheck; \
          } || { rm -rf "$dc_destdir"; exit 1; }) \
      && rm -rf "$dc_destdir" \
      && make  dist \
      && rm -rf hello-1.0.tar.gz \
      && make  distcleancheck \
      && cd "$am__cwd" \
      || exit 1
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables...
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking for style of include used by make... GNU
checking dependency style of gcc... gcc3
configure: creating ./config.status
config.status: creating Makefile
config.status: creating config.h
config.status: executing depfiles commands
make[1]: Entering directory `/tmp/hello/hello-1.0/_build'
make  all-am
make[2]: Entering directory `/tmp/hello/hello-1.0/_build'
gcc -DHAVE_CONFIG_H -I. -I..     -g -O2 -MT hello.o -MD -MP -MF .deps/hello.Tpo -c -o hello.o ../hello.c
mv -f .deps/hello.Tpo .deps/hello.Po
gcc  -g -O2   -o hello hello.o
make[2]: Leaving directory `/tmp/hello/hello-1.0/_build'
make[1]: Leaving directory `/tmp/hello/hello-1.0/_build'
make[1]: Entering directory `/tmp/hello/hello-1.0/_build'
make[1]: Nothing to be done for `dvi'.
make[1]: Leaving directory `/tmp/hello/hello-1.0/_build'
make[1]: Entering directory `/tmp/hello/hello-1.0/_build'
make[1]: Nothing to be done for `check'.
make[1]: Leaving directory `/tmp/hello/hello-1.0/_build'
make[1]: Entering directory `/tmp/hello/hello-1.0/_build'
make[2]: Entering directory `/tmp/hello/hello-1.0/_build'
test -z "/tmp/hello/hello-1.0/_inst/bin" || /bin/mkdir -p "/tmp/hello/hello-1.0/_inst/bin"
  /usr/bin/install -c hello '/tmp/hello/hello-1.0/_inst/bin'
make[2]: Nothing to be done for `install-data-am'.
make[2]: Leaving directory `/tmp/hello/hello-1.0/_build'
make[1]: Leaving directory `/tmp/hello/hello-1.0/_build'
make[1]: Entering directory `/tmp/hello/hello-1.0/_build'
make[1]: Nothing to be done for `installcheck'.
make[1]: Leaving directory `/tmp/hello/hello-1.0/_build'
make[1]: Entering directory `/tmp/hello/hello-1.0/_build'
 ( cd '/tmp/hello/hello-1.0/_inst/bin' && rm -f hello )
make[1]: Leaving directory `/tmp/hello/hello-1.0/_build'
make[1]: Entering directory `/tmp/hello/hello-1.0/_build'
make[1]: Leaving directory `/tmp/hello/hello-1.0/_build'
make[1]: Entering directory `/tmp/hello/hello-1.0/_build'
make[2]: Entering directory `/tmp/hello/hello-1.0/_build'
test -z "/tmp/hello/hello-1.0/_inst/bin" || /bin/mkdir -p "/tmp/am-dc-8010//tmp/hello/hello-1.0/_inst/bin"
  /usr/bin/install -c hello '/tmp/am-dc-8010//tmp/hello/hello-1.0/_inst/bin'
make[2]: Nothing to be done for `install-data-am'.
make[2]: Leaving directory `/tmp/hello/hello-1.0/_build'
make[1]: Leaving directory `/tmp/hello/hello-1.0/_build'
make[1]: Entering directory `/tmp/hello/hello-1.0/_build'
 ( cd '/tmp/am-dc-8010//tmp/hello/hello-1.0/_inst/bin' && rm -f hello )
make[1]: Leaving directory `/tmp/hello/hello-1.0/_build'
make[1]: Entering directory `/tmp/hello/hello-1.0/_build'
make[1]: Leaving directory `/tmp/hello/hello-1.0/_build'
make[1]: Entering directory `/tmp/hello/hello-1.0/_build'
{ test ! -d "hello-1.0" || { find "hello-1.0" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -fr "hello-1.0"; }; }
test -d "hello-1.0" || mkdir "hello-1.0"
test -n "" \
    || find "hello-1.0" -type d ! -perm -755 \
            -exec chmod u+rwx,go+rx {} \; -o \
      ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
      ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
      ! -type d ! -perm -444 -exec /bin/sh /tmp/hello/hello-1.0/install-sh -c -m a+r {} {} \; \
    || chmod -R a+r "hello-1.0"
tardir=hello-1.0 && /bin/sh /tmp/hello/hello-1.0/missing --run tar chof - "$tardir" | GZIP=--best gzip -c >hello-1.0.tar.gz
{ test ! -d "hello-1.0" || { find "hello-1.0" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -fr "hello-1.0"; }; }
make[1]: Leaving directory `/tmp/hello/hello-1.0/_build'
make[1]: Entering directory `/tmp/hello/hello-1.0/_build'
test -z "hello" || rm -f hello
rm -f *.o
rm -f *.tab.c
test -z "" || rm -f
test . = ".." || test -z "" || rm -f
rm -f config.h stamp-h1
rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
rm -f config.status config.cache config.log configure.lineno config.status.lineno
rm -rf ./.deps
rm -f Makefile
make[1]: Leaving directory `/tmp/hello/hello-1.0/_build'
{ test ! -d "hello-1.0" || { find "hello-1.0" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -fr "hello-1.0"; }; }
===========================================
hello-1.0 archives ready for distribution:
hello-1.0.tar.gz
===========================================

一般项目并不是简单的一个.c文件。通常包括多个(嵌套的)目录。并且需要执行差异化的编译和安装,下一篇文章示范如何在一个实际项目中应用autoconf