ビルドシステムを作る

これまでの経験上、ビルドシステムをちゃんとつくらなかったプロジェクトはどれも途中で投げ出していたので、autotools を使って環境をちゃんとつくるところから始めていくことにしました。

ディレクトリ構成

ざっと以下のような形にすることをイメージしました。

-+- src/ (ソースコードを置く)
 |
 +- doc/ (Doxygen で生成したドキュメントなどを置く)
 |
 +- config.h
 |
 +- configure
 |
 :

configure.in を書く。

autoconf や automake の info を見ながらこつこつと書きました。とりあえずは以下のようになりました。

AC_PREREQ(2.57)
AC_INIT(mod_mysql, 0.0, moriyoshi@users.sourceforge.net)
AM_INIT_AUTOMAKE(mod_mysql, 0.0)
AC_CONFIG_SRCDIR([src/mod_mysql.cpp])
AM_CONFIG_HEADER(config.h)
AM_MAINTAINER_MODE

AC_SUBST(PACKAGE_VERSION)
AC_SUBST(PACKAGE_NAME)
AC_SUBST(PACKAGE_TARNAME)

enable_static=no

AC_PROG_CXX
AC_PROG_CC
AC_PROG_LN_S
AC_PROG_INSTALL
AM_PROG_LIBTOOL

AC_CHECK_PROGS([DOXYGEN], [doxygen])
AC_SUBST(DOXYGEN)

AC_HEADER_STDC
AC_CHECK_HEADERS([string.h])

AC_HEADER_STDBOOL
AC_C_CONST
AC_C_INLINE
AC_TYPE_SIZE_T

AC_FUNC_MEMCMP
AC_CHECK_FUNCS([memmove memset strrchr])

AC_DEFUN([MOD_MYSQL_CHECK_APXS], [
  APXS=
  AC_MSG_CHECKING([apxs location])
  for _path in m4_translit($1, [
], [ ]); do
    if test -x "$_path"; then
      APXS="$_path"
      break
    fi
  done

  if test -z "$APXS"; then
    AC_MSG_RESULT([not found])
    $3
  else
    AC_MSG_RESULT([$APXS])
    $2
  fi
])

AC_ARG_WITH([apxs], [  --with-apxs=PATH-TO-APXS    specify APXS location], [
  MOD_MYSQL_CHECK_APXS(["$withval"], [], [
    AC_MSG_ERROR([could not find apxs in "$withval"])
  ])
], [
  MOD_MYSQL_CHECK_APXS([
    /usr/sbin/apxs
    /usr/local/sbin/apxs
    /usr/bin/apxs
    /usr/local/bin/apxs
    /opt/apache/bin/apxs
    /usr/local/apache/bin/apxs
    /usr/sbin/apxs2
    /usr/local/sbin/apxs2
    /usr/bin/apxs2
    /usr/local/bin/apxs2
    /opt/apache/bin/apxs2
    /usr/local/apache/bin/apxs2
  ], [], [
    AC_MSG_ERROR([could not determine apxs location])
  ])
])

CFLAGS="$CFLAGS `$APXS -q CFLAGS`"
INCLUDES="$INCLUDES -I`$APXS -q INCLUDEDIR`"
MODULEDIR="`$APXS -q LIBEXECDIR`"

AC_SUBST(APXS)
AC_SUBST(INCLUDES)
AC_SUBST(MODULEDIR)

AC_OUTPUT([Makefile src/Makefile])

MOD_MYSQL_CHECK_APXS は、apxs を見つけるための関数です。m4_translit で改行をスペースに変換するということをやっている以外は普通のシェルスクリプトです。

Makefile.am を書く

ビルドに必要な各ディレクトリに Makefile.am を置く必要があります。以下のような感じにしました。

SUBDIRS=src
lib_LTLIBRARIES=mod_mysql.la
mod_mysql_la_LDFLAGS=-module -avoid-version
mod_mysql_la_SOURCES= \
	mod_mysql.cpp
mod_mysql_la_LIBADD=@LIBS@
NOINST=mod_mysql.la
INCLUDES=@INCLUDES@
libdir=@MODULEDIR@

autotools の実行

  • autoconf は automake と aclocal と autoheader に依存する。
  • automake は autoheader と libtoolize に依存する。
  • libtoolize は aclocal に依存する。

という状況なので、
aclocal → libtoolize → autoheader → automake → autoconf
の順番で呼び出せば OK でした。

試行錯誤した結果、各ツールのオプションでいくつか重要なものがあることに気づいたのでメモしておきます。

libtoolize:

    --automake        work silently, and assume that Automake is in use
-c, --copy            copy files rather than symlinking them

automake:

      --include-deps     enable dependency tracking code
      --foreign          set strictness to foreign
  -a, --add-missing      add missing standard files to package
  -c, --copy             with -a, copy missing files (default is symlink)
  • -c を付け忘れるとファイルが /usr/share 以下の autotools のディレクトリから symlink されてしまい「うっ」ということになります。automake で -a がないとビルドに必要なスクリプトがインストールされませんでした。
  • --foreign を付けないと勝手に GPL が記載された COPYING ファイルとかがインストールされてしまいます。

autogen.sh

autotools を使ってビルドシステムを実現しているプロジェクトは大抵 autogen.sh というスクリプトをプロジェクトのルートディレクトリに置いています *1が、これは上記の autotools の呼出を自動的にやってくれるものと暗に期待されています。

この流儀にしたがって autogen.sh を作ることにしました。中身は以下です。

aclocal
libtoolize -c --force
autoheader
automake -c -a --foreign
autoconf

*1:ApachePHP は buildconf、これは両プロジェクトに関わっている Sascha Schumann 氏による独自ビルドシステムを採用しているため。