5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

PHP4をAlpineLinuxでビルドする話

Last updated at Posted at 2018-12-24

はじめに

この記事はPHP Advent Calendar 2018の24日目の記事です。

西日本応援プロジェクト真夏の大LT大会で徳丸さんが古くはphp-3.0.18から最新のバージョンまでmacOS上に環境構築しているという話をしていたので、同じようなことをAlpineLinuxでやったらどうなるのか、という記録がこの記事です。
あらかじめ書いておくと、徳丸さんの発表とちがって、この記事は基本的に無益です。

前提

  • docker for Mac を利用
  • AlpineLinux 3.8
  • AlpineLinuxのパッケージングシステム(abuild/apk)を利用する
  • Apache1.3用のmod_php版とCLI版(php-4.2.x以前はCGI版)をビルド

初めてabuildを使いましたが、RPMより書きやすい気がしますね。

成果物

作ったものは、http://github.com/odz/a-php にあります。

Dockerfile
FROM alpine:3.8

ARG PHP_VERSION

ADD https://odz.github.com/a-php/oda.org@gmail.com.rsa.pub /etc/apk/keys
RUN echo 'https://odz.github.com/a-php/php' >> /etc/apk/repositories && \
        apk add \
                php-apache1.3~${PHP_VERSION} \
                php-pear~${PHP_VERSION}

CMD ["/usr/bin/apache", "-F"]

このようなDockerfileを作成して、

docker build --build-arg PHP_VERSION=4.0.0 -t php:4.0.0 .

などとすれば、Apache 1.3、PHP 4.0.0のDocker Imageができます。
Document Rootは /var/www/localhost/htdocsです。

Apache 1.3

mod_php版をビルドするためにはまず、Apache 1.3が必要だが、さすがにいまどきの環境ににApache 1.3のパッケージはないので、自力でビルドする。が、Apache 1.3もそれなりにパッチをあてないとビルドできない。

getline.patch

getlineという関数が標準ライブラリのものと名前が衝突しているので、名前を変更しないと行けない。

libc-decl.patch

glibcには sys_sliglist というシンボルが定義されているのだが、Alpine Linuxで利用している musl libc にはそんなものはないのと、判定をミスっていて
glibc 2.0以前向けにrlim_ttypedefしようとしているのでこれを削除。

busybox_sed.patch

busybox の sed が GNU sed と違って \+ を解釈できないので、修正。よくわかっていないけど、\+ は GNU sed の拡張ということで良いよね?

no-setsid.patch

これはあてなくてもビルド自体はできる。

Apache 1.3 は foreground で動かす場合(-Fオプション指定)もsetsid(2) をコールし、エラーの場合はプロセス終了してしまうのである。説明はめんどいので飛ばすが、Docker で Apache を動かす場合に、この仕様は大変つらい感じなので、setsid(2) をコールしないように修正。

-fgnu89-inline

gcc の古いバージョンでは extern inline を指定された関数はインライン展開されたあと、関数定義自体は残らないらしい。いまのデフォルト動作はそうではないのだが、そのような動作にするためには-fgnu89-inlineオプションを指定すれば良いらしい。これを指定しないとmultiple definitionでリンク時にエラーになる。

Apache 1.3 でいうと以下のコードですね。

os.h
#define INLINE extern ap_inline

INLINE int ap_os_is_path_absolute(const char *file);

#include "os-inline.c"
os-inline.c
INLINE int ap_os_is_path_absolute(const char *file)
{
  return file[0] == '/';
}

PHP 4.0.0

number4.tar.gz

bcmath を有効にしようとすると

You do not have the bcmath package. Please read the README.BCMATH file.

といわれそのとおりに README.BCMATH を読むとライセンスの問題でBC Math ライブラリは PHP とは別配布になったので、http://www.php.net/extra/number4.tar.gz からダウンロードしてくるべし、みたいなことが書いてあるわけです。が、そのURLにアクセスしてもダウンロードできない。

結構苦労して探してどこかからダウンロードしてきたのだけど、どこだったかはよく覚えていない。

ちなみに、ライセンス問題が解決されたのか PHP 4.0.4 からは同梱されるようになっている。

extern-static.patch

古い gcc では同一変数名でextern付きの宣言とstatic付きの宣言が重複していても
問題なかったらしい。GCC 4 以降はそのようなコードはエラーになるようになっているので、
変数名を変更して対応。ap_php_opterrap_php_optind に関してはそもそもextern宣言の方が不要なので削除。

ちなみに、PHP 4.0.5 で問題は修正され、このパッチは不要になる。

mysql-obsolete.patch

PHP 4.0.0 は MySQL 3.x 時代に存在していたmysql_createdbmysql_dropdbを参照しているため、リンクまでうまく行っても実行時にシンボルが足りないため、実行時にエラーになる。古い MySQL を持ってくるのでも良いのだけど、めんどいのでPHP側を修正して対応。

なお、これも PHP 4.1.0 で同様の対応が取られるのでパッチ不要になる。

mariadb-port.patch

Alpine Linux には MySQL ではなく、MariaDB が提供されているので、
この記事でのPHPのビルドにも MariaDB を利用しているんだが、
MariaDB の Client Library は関数名、ヘッダ名もオリジナルと合わせているし、
ライブラリの名前も libmariadb.so だけでなく、libmysqlclient.so も提供されているくせに
MYSQL_PORTがdefineされないという状態である。おしいな。

ということで、#define MYSQL_PORT MARIADB_PORTとしておく。

zend_optimization.patch

sed s/-O[0-9]*// として最適化オプションを削除したコンパイルオプションを生成しようとしているのだが、Alpine Linuxのデフォルト状態だと-Osオプションが指定されているので、
この状態だとsだけ残って悲しいことになる。ということで、sed s/-O[s0-9]*//に修正して対応。

これも PHP 4.0.5 で同様の対応が取られる。

zlib.patch

zlib には

gzFile gzopen(const char *, const char *);
int    gzclose(gzFile file);
int    gzgetc(gzFile file);

といった関数群があって、PHP はこれらへのbindingが提供されているのだが、PHP 4.0.0の時期のコード自体は全般的に gzopen の戻り値や gzgetc へのパラメータの型をgzFileではなく、gzFile *と勘違いしている模様である。

zlib 1.2.5 までは typedef void *gzFileなので問題ないが、zlib 1.2.6 以降は typedef struct gzFile_s *gzFileであり、gzgetcはこの構造体のメンバにアクセスするマクロになっているので、
この辺の兼ね合いで zlib 1.2.6 以降だとコンパイルエラーになるという。

gzgetcだけ care しておけばとりあえずビルドはできる。テストはしてない。

この問題は PHP 4.3.0 で gzgetc 他の実装が修正されパッチ不要になる。

その他

いろいろ試していて気づいたのだが、PHP 4.0.0 は php.iniextension_dirディレクティブの設定が効かないというバグがあるようだ。このため、extensionディレクティブはフルパスで指定する必要がある。
なぜ、そんなバグが放置したままリリースされたのか・・・

時間切れ

ここまで書いて時間切れ。
いろいろあるので、あとで追記する。

5
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?