## UNIX 用のビルドシステム: config.m4

拡張モジュールの config.m4 ファイルは、 UNIX のビルドシステムに対して「その拡張モジュールがサポートしている configure オプション」「依存する外部ライブラリ」 「コンパイル対象となるソースファイル」などの情報を伝えるものです。 一般的に用いられる autoconf マクロ (PHP 固有のものおよび autoconf 組み込みのもの) については Zend Engine 2 API リファレンス を参照ください。

ヒント

インストールしている autoconf のバージョンによって、拡張モジュールの開発時に違いが出てきます。 PHP 5.3 以前のバージョンでは、いちばんよい結果が得られるのが autoconf バージョン 2.13 でした。 しかし、バージョン 2.59 までを使っても動作します。 PHP 5.4 以降では、autoconf のバージョン 2.59 以降しか使えません。バージョンが新しいほどよい結果が得られます。

例1 config.m4 ファイルの例

    dnl $Id$
    dnl config.m4 for extension example

    PHP_ARG_WITH(example, for example support,
    [  --with-example[=FILE]       Include example support. File is the optional path to example-config])
    PHP_ARG_ENABLE(example-debug, whether to enable debugging support in example,
    [  --enable-example-debug        example: Enable debugging support in example], no, no)
    PHP_ARG_WITH(example-extra, for extra libraries for example,
    [  --with-example-extra=DIR      example: Location of extra libraries for example], no, no)

    dnl Check whether the extension is enabled at all
    if test "$PHP_EXAMPLE" != "no"; then

      dnl Check for example-config. First try any path that was given to us, then look in $PATH
      AC_MSG_CHECKING([for example-config])
      EXAMPLE_CONFIG="example-config"
      if test "$PHP_EXAMPLE" != "yes"; then
        EXAMPLE_PATH=$PHP_EXAMPLE
      else
        EXAMPLE_PATH=`$php_shtool path $EXAMPLE_CONFIG`
      fi

      dnl If a usable example-config was found, use it
      if test -f "$EXAMPLE_PATH" && test -x "$EXAMPLE_PATH" && $EXAMPLE_PATH --version > /dev/null 2>&1; then
        AC_MSG_RESULT([$EXAMPLE_PATH])
        EXAMPLE_LIB_NAME=`$EXAMPLE_PATH --libname`
        EXAMPLE_INCDIRS=`$EXAMPLE_PATH --incdirs`
        EXAMPLE_LIBS=`$EXAMPLE_PATH --libs`

        dnl Check that the library works properly
        PHP_CHECK_LIBRARY($EXAMPLE_LIB_NAME, example_critical_function,
        [
          dnl Add the necessary include dirs
          PHP_EVAL_INCLINE($EXAMPLE_INCDIRS)
          dnl Add the necessary libraries and library dirs
          PHP_EVAL_LIBLINE($EXAMPLE_LIBS, EXAMPLE_SHARED_LIBADD)
        ],[
          dnl Bail out
          AC_MSG_ERROR([example library not found. Check config.log for more information.])
        ],[$EXAMPLE_LIBS]
        )
      else
        dnl No usable example-config, bail
        AC_MSG_RESULT([not found])
        AC_MSG_ERROR([Please check your example installation.])
      fi

      dnl Check whether to enable debugging
      if test "$PHP_EXAMPLE_DEBUG" != "no"; then
        dnl Yes, so set the C macro
        AC_DEFINE(USE_EXAMPLE_DEBUG,1,[Include debugging support in example])
      fi

      dnl Check for the extra support
      if test "$PHP_EXAMPLE_EXTRA" != "no"; then
        if test "$PHP_EXAMPLE_EXTRA" == "yes"; then
          AC_MSG_ERROR([You must specify a path when using --with-example-extra])
        fi

        PHP_CHECK_LIBRARY(example-extra, example_critical_extra_function,
        [
          dnl Add the neccessary paths
          PHP_ADD_INCLUDE($PHP_EXAMPLE_EXTRA/include)
          PHP_ADD_LIBRARY_WITH_PATH(example-extra, $PHP_EXAMPLE_EXTRA/lib, EXAMPLE_SHARED_LIBADD)
          AC_DEFINE(HAVE_EXAMPLEEXTRALIB,1,[Whether example-extra support is present and requested])
          EXAMPLE_SOURCES="$EXAMPLE_SOURCES example_extra.c"
        ],[
          AC_MSG_ERROR([example-extra lib not found. See config.log for more information.])
        ],[-L$PHP_EXAMPLE_EXTRA/lib]
        )
      fi

      dnl Finally, tell the build system about the extension and what files are needed
      PHP_NEW_EXTENSION(example, example.c $EXAMPLE_SOURCES, $ext_shared)
      PHP_SUBST(EXAMPLE_SHARED_LIBADD)
    fi

### autoconf の構文についての簡単な説明

config.m4 は、GNU autoconf の構文で書かれています。簡単にいうと、 これはシェルスクリプトに強力なマクロ言語を追加したようなものです。 コメントを記述する際には文字列 dnl を使用し、文字列のクォートには角括弧 ([ および ]) を使用します。文字列のクォートは、 必要に応じて何段階でもネストすることができます。この構文の完全な解説は、 » http://www.gnu.org/software/autoconf/manual/ にある autoconf のマニュアルを参照ください。

### PHP_ARG_*: ユーザーに対するオプションの提供

先ほどの config.m4 のサンプルで、 ちょっとしたコメントを除いていちばん最初にあるのは PHP_ARG_WITH() および PHP_ARG_ENABLE() を使用した 3 行です。これらは、configure コマンドで ./configure --help を実行したときに表示される オプションとその説明文を指定するものです。 その名が示すように、両者の違いはそれぞれ --with-* 系のオプションを作成するか --enable-* 系のオプションを作成するかです。 すべての拡張モジュールは、 このどちらかに拡張モジュール名とつけたオプションを提供する必要があります。 これにより、その拡張モジュールを PHP に組み込むかどうかを選択できるようになります。 規約上では、何らかのパラメータ (その拡張モジュールが必要とするライブラリやプログラムの場所など) を指定させる場合には PHP_ARG_WITH() を使うことになっています。 一方、単なるフラグとして使用するオプションの場合は PHP_ARG_ENABLE() を使用します。

例2 configure の出力例

    $ ./configure --help
    ...
      --with-example[=FILE]       Include example support. FILE is the optional path to example-config
      --enable-example-debug        example: Enable debugging support in example
      --with-example-extra=DIR      example: Location of extra libraries for example
    ...

    $ ./configure --with-example=/some/library/path/example-config --disable-example-debug --with-example-extra=/another/library/path
    ...
    checking for example support... yes
    checking whether to enable debugging support in example... no
    checking for extra libraries for example... /another/library/path
    ...

> 注意:

> configure のコール時にどんな順でオプションを指定したかにかかわらず、 内部では config.m4 で指定した順にチェックを行います。

### ユーザーの選択内容の処理

ここまでで、config.m4 を使ってユーザーに対して選択肢を提供できるようになりました。 次は、選択内容に応じて実際の処理を行う番です。 上の例で、3 つのオプションすべてのデフォルト、つまり何も指定しなかったときの値は "no" です。拡張モジュールを有効にするオプションでは、 デフォルトを no にしておくのがおすすめです。 phpize で個別にビルドするときにはこれは上書きされますし、 PHP に組み込む際にデフォルトで拡張モジュールの空間を乱してはいけないからです。 これらの 3 つのオプションを処理するコードは、より複雑なものとなります。

#### --with-example[=FILE] オプションの処理

最初のチェック、つまり --with-example[=FILE] オプションのチェックは、それが設定されているかどうかを調べます。 このオプションは拡張モジュールそのものを組み込むかどうかを決めるものです。 省略されていたり否定形式 (--without-example ) で指定されていたり、あるいは値として "no" が指定されていたりした場合は、それ以降は何も行いません。 上の例では、値として /some/library/path/example-config が指定されているので、このチェックは成功します。

次に、このコードは AC_MSG_CHECKING() をコールします。 これは autoconf のマクロで、標準的な "checking for something" の行を出力してユーザーが example-config にパスを明示したかどうかを調べます。 この例では PHP_EXAMPLE は値 /some/library/path/example-config を受け取り、 それが変数 EXAMPLE_PATH にコピーされます。ユーザーが --with-example だけしか指定しなかった場合は、 このコードは $php_shtool path $EXAMPLE_CONFIG を実行します。これは、そのユーザーの現在の PATH を使用して example-config の場所を探します。 どちらにしても、次に行うのは EXAMPLE_PATH が通常の実行可能ファイルであるかどうか、 そして正常に実行できるかどうかの調査となります。 実行できた場合は AC_MSG_RESULT() がコールされ、 AC_MSG_CHECKING() で始まる出力行を補完します。 それ以外の場合は AC_MSG_ERROR() がコールされ、 指定されたメッセージを表示して configure を即時に終了させます。

次に、このコードは example-config を何度か実行してサイト固有の設定情報を取得します。 その次にコールするのは PHP_CHECK_LIBRARY() です。これは PHP のビルドシステムが autoconf の AC_CHECK_LIB() のラッパーとして用意しているマクロです。 PHP_CHECK_LIBRARY() は、 最初のパラメータで指定したライブラリの 2 番目のパラメータで指定したシンボルをコールするプログラムを コンパイル、リンクして実行します。 成功すると、3 番目のパラメータで指定したスクリプトを実行します。 このスクリプトは PHP ビルドシステムに対して インクルードパスやライブラリパス、ライブラリ名を example-config が返す文字列から通知します。 失敗すると、かわりに 4 番目のパラメータで指定したスクリプトを実行します。 この場合は、AC_MSG_ERROR() がコールされて処理を停止します。

#### --enable-example-debug オプションの処理

--enable-example-debug の処理はずっと単純です。真値が設定されているかどうかだけを調べます。 チェックに成功すると、AC_DEFINE() をコールして C のマクロ USE_EXAMPLE_DEBUG を作成し、拡張モジュールのソースで使用できるようにします。 3 番目のパラメータは config.h 用のコメント文字列です。 これを空のままにしておいても問題はありません。たいていは空のままにします。

#### --with-example-extra=DIR オプションの処理

このサンプルでの説明用に用意した架空の機能 "extra" は --with-example-extra=DIR オプションで要求されるもので、架空のプログラム example-config とは別のものであり、 デフォルトのサーチパスもありません。 そのためユーザーは、必要なライブラリのインストール先を指定する必要があります。 このような設定は実際の拡張モジュールではあまりないかもしれませんが、 説明用として用意しました。

このコードは、あまりなじみのない方法で PHP_EXAMPLE_EXTRA が真値であるかどうかを調べます。 否定形が指定された場合は、それ以降の処理を行いません。 これは、そのユーザーが追加機能を必要としなかったことを表します。 パラメータなしで肯定形が指定された場合は、 AC_MSG_ERROR() がコールされて処理を停止します。 その次に、また PHP_CHECK_LIBRARY() を実行します。 今度は、定義済みのコンパイラオプションはないので、 PHP_ADD_INCLUDE() と PHP_ADD_LIBRARY_WITH_PATH() を使用して必要なインクルードパスやライブラリパス、 追加機能のためのライブラリのフラグを作成します。 AC_DEFINE() もコールされ、 追加機能が要求されていてそれが使用可能であることを通知します。 また、ビルドすべきファイルが別に存在することを示す変数も設定します。 チェックに失敗すると、おなじみの AC_MSG_ERROR() がコールされます。 失敗時のもうひとつの処理法は、次のように AC_MSG_WARNING() をコールすることです。

    AC_MSG_WARNING([example-extra lib not found. example will be built without extra functionality.])

この場合は、configure はエラーではなく警告メッセージを表示し、処理を続行します。 いずれにせよ、失敗をどう処理するのかは拡張モジュールの開発者が決めることです。

### ビルドシステムに対しての決定内容の通知

必要なインクルードファイルやライブラリはすべて指定しました。 必要なオプションやマクロもすべて定義しました。 でも、あとひとつ残っていることがあります。 ビルドシステムに対して、拡張モジュール自身をビルドすることと そのために使用するファイル群を教えてやらなければならないのです。 そのためには PHP_NEW_EXTENSION() マクロをコールします。 このマクロの最初のパラメータは拡張モジュールの名前で、 これはディレクトリ名と一致します。2 番目のパラメータは、 その拡張モジュールを構成するすべてのソースファイルのリストです。 サブディレクトリ内のソースファイルをビルド処理に追加する方法については PHP_ADD_BUILD_DIR() を参照ください。 3 番目のパラメータは、常に $ext_shared でなければなりません。この値は、 configure の際に --with-example[=FILE] 用に PHP_ARG_WITH() がコールされたときに決まります。 4 番目のパラメータでは "SAPI クラス" を指定します。 これは CGI SAPI や CLI SAPI を必要とする場合にのみ有用です。 その他のクラスでは、ここは空のままにしておかなければなりません。 5 番目のパラメータには、拡張モジュールのビルド時の CFLAGS に追加するフラグのリストを指定します。 6 番目のパラメータは boolean 値です。"yes" を指定すると、 拡張モジュール全体のビルドを $CC ではなく $CXX を用いて行います。 3 番目以降のパラメータは、すべてオプションです。 最後に PHP_SUBST() をコールして、 拡張モジュールの共有ビルドを有効にします。 共有モードでの拡張モジュールのビルドをサポートしないようにする方法についての詳細は 拡張モジュールに関する FAQ を参照ください。

### counter 拡張モジュールの config.m4 ファイル

先ほど説明した counter 拡張モジュールの config.m4 ファイルは、上で説明したよりずっとシンプルです。 これは、ビルドシステムのさまざまな機能を使用していないからです。 外部のライブラリや同梱されているライブラリを使わない場合は、 このようにしておくことをお勧めします。

例3 counter の config.m4 ファイル

    dnl

    $

    Id$
    dnl config.m4 for extension counter

    PHP_ARG_ENABLE(counter, for counter support,
    [  --enable-counter            Include counter support])

    dnl Check whether the extension is enabled at all
    if test "$PHP_COUNTER" != "no"; then
      dnl Finally, tell the build system about the extension and what files are needed
      PHP_NEW_EXTENSION(counter, counter.c counter_util.c, $ext_shared)
      PHP_SUBST(COUNTER_SHARED_LIBADD)
    fi