2012年8月1日 星期三

使用 Autoconf, Automake, Libtool

很久以前用 latex 寫的, 不知道還是不是這樣的用法。後來覺得自己的小程式用上 autobuild tool 實在太 "搞剛", 解決 autobuild 的問題比寫程式還花時間, 現在以手工刻 makefile 為主。

這是用 latex2html 轉出來的。

目錄


摘要:

本文件介紹如何使用 autoconf, automake, libtool 來產生編譯原始碼所需要的檔案, ex : configure, Makefile ...


1 autobuild 簡介

GNU autobuild 系統包含了 autoconf, automake, libtool。 autoconf 需要編寫 configure.ac, automake 需要編寫 Makefile.am, configure.ac 由 M4 巨集和 shell script 構成。 所以在 configure.ac 可以看到 M4 巨集和 shell script。 而 configure.ac 可以先用 autoscan 來產生一個範本 (configure.scan), 先複製成 configure.ac 再修改需要的 M4 巨集即可。
automake 則是用來產生 Makefile.in, 再讓 configure 根據 Makefile.in 產生 Makefile。
libtool 則是產生 static/shared library 的 script。

2 autobuild 版本

autoscan (GNU Autoconf) 2.59 Written by David J. MacKenzie and Akim Demaille.
Copyright (C) 2003 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
autoconf (GNU Autoconf) 2.59 Written by David J. MacKenzie and Akim Demaille.
Copyright (C) 2003 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
automake (GNU automake) 1.9.5 Written by Tom Tromey <tromey@redhat.com>.
Copyright 2005 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
由於各版本的 M4 巨集寫法有些差異, 以下介紹以我目前所接觸的最新版本為主, 若是之前的版本不一定適用。


3 hello example C version

這是 C 版本的 hello。
#include <stdio.h>

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

$ autoscan
autom4te: configure.ac: no such file or directory
autoscan: /usr/bin/autom4te failed with exit status: 1
configure.scan 內容:
# Process this file with autoconf to produce a configure script.

AC_PREREQ(2.59)
AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS)
AC_CONFIG_SRCDIR([hello.c])
AC_CONFIG_HEADER([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_OUTPUT

$ cp  configure.scan configure.ac
現在我們要修改 configure.ac, 使其符合我們的需要。 首先先移除 AC_CONFIG_HEADER([config.h]), 因為目前我們沒有用到 config.h。
加入和 automake 有關的 M4 巨集。
AM_INIT_AUTOMAKE
AC_CONFIG_FILES(Makefile)
AM_INIT_AUTOMAKE 初始化 automake。 AC_CONFIG_FILES(Makefile) 會由 Makefile.in 來產生 Makefile, 而 Makefile.in 由 Makefile.am 來產生。
修改 AC_INIT 參數: AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS) 應該很直覺, FULL-PACKAGE-NAME -> hello, VERSION -> 0.1, BUG-REPORT-ADDRESS -> cname@mail.com。 這三個參數分別為 package 的 name, 版本, bug report 到那裡。 以下為修改後的 configure.ac:
#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

AC_PREREQ(2.59)
AC_INIT(hello, 0.1, cname@mail.com)
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([hello.c])

#AC_CONFIG_HEADER([config.h])

# Checks for programs.
AC_PROG_CC
AC_CONFIG_FILES(Makefile)

# Checks for libraries.

# Checks for header files.

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.
AC_OUTPUT
再來看看 Makefile.am

bin_PROGRAMS=hello
hello_SOURCES=hello.c
這個更直覺, 完全不需要解釋了吧!?
再來便是執行一系列的程式來產生所需要的檔案了。

aclocal
autoconf
automake -a
第一次執行 automake -a 會有以下的訊息:
automake: Makefile.am: required file `./NEWS' not found
automake: Makefile.am: required file `./README' not found
automake: Makefile.am: required file `./AUTHORS' not found
automake: Makefile.am: required file `./ChangeLog' not found
這是因為 automake 需要這些檔案, 而 automake 無法自動產生, 所以我們自己來產生。
$ touch NEWS README AUTHOR ChangeLog
再執行 automake -a 一次。 應該就沒問題了。
執行 configure script 看看有無錯誤。

./configure
make
來測試看有沒有正確產生 hello, 並執行看看。
make distcheck
會作一系列的測試, 並產生 hello-0.1.tar.gz, hello, 0.1 就是 AC_INIT 的前兩個參數。 可以試試看

make install
make distclean
這些 makefile rule。 如何? 是不是比自己寫 makfile 容易多了。

4 hello example C++ version

這是 C++ 版本的 hello。
#include <iostream>


int main()
{
  using namespace std;

  cout << "hello" << endl;
  return 0;
}
一樣先執行 autoscan, 再把 configure.scan copy 成 configure.ac。 autoscan 會得知目前的語言是 C++ 語言, 並會產生相對應的 M4 巨集。 修改方式和 C 版本的 hello 一樣, 注意 AC_PROG_CXX, 這會測試是否有 C++ compiler, 也就是 g++。 照著 section 3 再執行一遍, 應該可以順利成功。
由於我大部份使用 C++, 所以下面的例子全部以 C++ 為主。

5 加入 libtool


5.1 libtool 簡介

libtool 是用來產生 library 的 script, 可以用來產生 shared/static library。 由於每個系統產生 library 的方法不同, libtool 把有支援到的平台, 以同樣的方式來產生 library。 下面的命令可以產生 static/shared library。
libtool --mode=link g++ -o libgraph.la svga.lo shape.lo \
geometry.lo view.lo painter.lo draw.lo color_convert.lo \
-rpath /usr/local/lib
而 libtool 命令會去執行下面的 g++ 命令。

g++ -shared   .libs/svga.o .libs/shape.o .libs/geometry.o \
.libs/view.o .libs/painter.o .libs/draw.o .libs/color_convert.o  \
-lstdc++ -lm -lc -lgcc_s   -Wl,-soname -Wl,libgraph.so.0 \
-o .libs/libgraph.so.0.0.0
(cd .libs && rm -f libgraph.so.0 && ln -s libgraph.so.0.0.0 libgraph.so.0)
(cd .libs && rm -f libgraph.so && ln -s libgraph.so.0.0.0 libgraph.so)
ar cru .libs/libgraph.a  svga.o shape.o geometry.o view.o painter.o \
draw.o color_convert.o
ranlib .libs/libgraph.a
creating libgraph.la
(cd .libs && rm -f libgraph.la && ln -s ../libgraph.la libgraph.la)
$ exit
在 autoconf, automake 加入一些 M4 巨集及變數, 便可以呼叫 libtool 來幫我們產生 library。想要單獨使用 libtool 的朋友, 請自行參考 libtool 手冊。

5.2 加入 libtool 支援

在 configure.ac 新增 AC_PROG_LIBTOOL, 就可以了。 至於 Makefile.am:
bin_PROGRAMS=hello1
hello1_SOURCES=hello1.cpp
hello1_LDADD=libh.la
lib_LTLIBRARIES=libh.la
libh_la_SOURCES=h.cpp h.h
新的變數名稱有:
hello1_LDADD=libh.la
lib_LTLIBRARIES=libh.la
libh_la_SOURCES=h.cpp h.h
hello1_LDADD 會讓 hello1.o 和 libh.la 作 link, lib_LTLIBRARIES 會用 libtool 產生 libh.la, 會有 shared/static 兩種, 在 .lib 目錄裡。 libh_la_SOURCES 這個 library 的原始程式。
libh_la 就是將 libh.la 的 . 符號以 _ 替換掉, 若是 library 檔名為 libabc.la 就以 libabc_la_SOURCES 為 Makefile.am 的變數名稱。
接著執行
aclocal
autoconf
libtoolize --force 
automake -a
libtoolize --force 會產生新的 script 檔案,
config.guess
config.sub
ltmain.sh'
以下是完整的 configure.ac
#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

AC_PREREQ(2.59)
AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS)
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([hello1.cpp])
#AC_CONFIG_HEADER([config.h])

AC_PROG_LIBTOOL

AC_CONFIG_FILES([Makefile])

# Checks for programs.
AC_PROG_CXX

# Checks for libraries.

# Checks for header files.

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.
AC_OUTPUT
以下是完整的 Makefile.am
bin_PROGRAMS=hello1
hello1_SOURCES=hello1.cpp 
hello1_LDADD=libh.la
lib_LTLIBRARIES=libh.la 
libh_la_SOURCES=h.cpp h.h
所有原始碼檔案:
h.cpp  hello1.cpp  hello2.cpp  h.h
hello1.cpp hello2.cpp 是兩個含有 main 的程式檔案, h.h h.cpp 則含有一個 function 來讓 hello1.cpp hello2.cpp 呼叫, 也是構成 libh.la library 的原始程式。

6 產生兩個以上的執行檔

這很容易, 把 Makefile.am 改成
bin_PROGRAMS=hello1 hello2
hello1_SOURCES=hello1.cpp 
hello1_LDADD=libh.la
hello2_SOURCES=hello2.cpp 
hello2_LDADD=libh.la
lib_LTLIBRARIES=libh.la 
libh_la_SOURCES=h.cpp h.h
產生 hello2 相關的變數 (hello2_SOURCES, hello2_LDADD), bin_PROGRAMS 則加入一個 hello2。以此類推就可以產生多個執行檔。

7 使用 config.h

經由 autobuild 產生的 Makefile 會產生很多的 -D 巨集定義, AC_CONFIG_HEADER([config.h]) 可以產生 config.h 裡面會定義一些巨集, 而我們的程式

#if HAVE_CONFIG_H
#include "config.h"
#endif
即可使用這些巨集定義, 而 Makefile 也不會有很多的 -DAAA -DBBB -DCCC, 可以減少 Makefile 的大小。
這是在還沒有使用 AC_CONFIG_HEADER([config.h]) 所產生的 Makefile 其中的巨集定義。

DEFS = -DPACKAGE_NAME=\"FULL-PACKAGE-NAME\" -DPACKAGE_TARNAME=\"full-package-name\" 
-DPACKAGE_VERSION=\"VERSION\" -DPACKAGE_STRING=\"FULL-PACKAGE-NAME\ VERSION\" 
-DPACKAGE_BUGREPORT=\"BUG-REPORT-ADDRESS\" -DPACKAGE=\"full-package-name\" 
-DVERSION=\"VERSION\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 
-DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 
-DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_DLFCN_H=1
 
在使用 AC_CONFIG_HEADER([config.h]) 之後, Makefile 的 DEFS 如下:

DEFS = -DHAVE_CONFIG_H
所有的巨集定義都在 config.h 裡了。

/* config.h.  Generated by configure.  */
/* config.h.in.  Generated from configure.ac by autoheader.  */

/* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1

/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1

/* Define to 1 if you have the `vga' library (-lvga). */
#define HAVE_LIBVGA 1

/* Define to 1 if you have the `vgagl' library (-lvgagl). */
#define HAVE_LIBVGAGL 1

/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1

/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1

/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1

/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1

/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1

/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1

/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1

/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1

/* Name of package */
#define PACKAGE "svgalib_test"

/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "descent@gmail.com"

/* Define to the full name of this package. */
#define PACKAGE_NAME "svgalib_test"

/* Define to the full name and version of this package. */
#define PACKAGE_STRING "svgalib_test 0.0.1"

/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "svgalib_test"

/* Define to the version of this package. */
#define PACKAGE_VERSION "0.0.1"

/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1

/* Version number of package */
#define VERSION "0.0.1"

/* Define to empty if `const' does not conform to ANSI C. */
/* #undef const */
執行
aclocal
autoconf
autoheader
libtoolize --force 
automake -a
現在要多執行一支程式: autoheader, 用來產生 config.h。

8 把原始碼放到 src 的目錄裡

建立 src 目錄, 將 source code (*.cpp, *.h) 移到 src, 將原本的 Makefile.am 也移到 src, 修改 confiure.ac
AC_CONFIG_FILES([Makefile src/Makefile])
表示要在原始碼目錄和 src 目錄產生 Makefile, 接著在原始碼目錄新增一個 Makefile.am, 其內容為:

SUBDIRS = src
執行
aclocal
autoconf
autoheader
libtoolize --force 
automake -a
執行 configure, 在原始碼目錄可以看見 Makefile, config.h, 而 src 目錄也會產生 Makefile。

9 撰寫自己的 M4 測試

以下的例子會檢查 svgalib 和 libjpeg 是否系統有這兩個 library。
#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

AC_PREREQ(2.59)
AC_INIT(jpeglib_test, 0.0.1, descent@gmail.com)
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([jpeg.cpp])
AC_PROG_LIBTOOL
AC_CONFIG_HEADER([config.h])

# Checks for programs.
AC_PROG_CXX
AC_PROG_CC
AC_CONFIG_FILES([Makefile])

# Checks for libraries.
#AC_CHECK_LIB([vga],main,,[echo "not find svgalib vgagl.";exit 1],)
#AC_CHECK_LIB([vgagl],main,,[echo "not find svgalib vga .";exit 1],[-lvga])

AC_LANG_PUSH([C++])
ORG_LIBS="LIBS"
AC_SUBST([CONFIG_SVGALIB_LIB],["-lvga -lvgagl"])
AC_MSG_CHECKING([we need to link svgalib lib])
LIBS="$CONFIG_SVGALIB_LIB $LIBS"
AC_LINK_IFELSE(
[AC_LANG_PROGRAM(
  [[
    #include <vga.h>
    #include <vgagl.h>
  ]],
  [[
    vga_init();
    int mode=G320x200x256;
    vga_setmode(mode);
    gl_setcontextvga(mode);
    vga_setmode(TEXT);
  ]]
)],
[CONFIG_SVGALIB_LIB="-lvga -lvgagl"; AC_MSG_RESULT(yes);],
[AC_MSG_RESULT(no), CONFIG_SVGALIB_LIB="" ; exit;]
)

LIBS=$ORG_LIBS

#check jpeg lib
AC_SUBST([CONFIG_JPEG_LIB],["-ljpeg"])
AC_MSG_CHECKING([we need to link jpeg lib])

LIBS="$CONFIG_JPEG_LIB $LIB"

AC_LINK_IFELSE(
[AC_LANG_PROGRAM(
  [[
    #include <cstdio> // this shoule before jpeg header file
    #include <cstdlib> // this shoule before jpeg header file
    #include <jpeglib.h>
    #include <jerror.h>

  ]],
  [[
    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;

    cinfo.err = jpeg_std_error (&jerr);

  ]]
)],
[CONFIG_JPEG_LIB="-ljpeg"; AC_MSG_RESULT(yes);],
[AC_MSG_RESULT(no), CONFIG_JPEG_LIB=""; echo "no"; exit;]
)

LIBS=$ORG_LIBS

AC_LANG_POP([C++])

LIBS="$CONFIG_JPEG_LIB $CONFIG_SVGALIB_LIB"

# Checks for header files.

# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST

# Checks for library functions.
AC_OUTPUT

About this document ...

This document was generated using the LaTeX2HTML translator Version 2008 (1.71)
Copyright © 1993, 1994, 1995, 1996, Nikos Drakos, Computer Based Learning Unit, University of Leeds.
Copyright © 1997, 1998, 1999, Ross Moore, Mathematics Department, Macquarie University, Sydney.
The command line arguments were:
latex2html -show_section_numbers -split 0 autobuild.tex


source file: https://github.com/descent/latex_doc/tree/master/autobuild

ref:
convert pdf to html: http://www.pdfonline.com/convert-pdf-to-html/

沒有留言:

張貼留言

使用 google 的 reCAPTCHA 驗證碼, 總算可以輕鬆留言了。

我實在受不了 spam 了, 又不想讓大家的眼睛花掉, 只好放棄匿名留言。這是沒辦法中的辦法了。留言的朋友需要有 google 帳號。