実行バイナリにシェアードライブラリの検索パスを埋め込みたい

本番環境、テスト環境両方ともdnf、yumでパッケージインストールだけで済めば良いのですが、そうでない場合がありますよね？
良くあるパターンとしては、PHPはパッケージでインストールしたOpenSSLを使用して、ApacheだけソースコードからビルドしてインストールしたOpenSSLを使いたい場合です。

 

PHPは外部にさらすわけではないので、ローカルのOpenSSLにリンクさせ、外部に解放するApacheは最新のOpenSSLにリンクさせたいってニーズがあるかと思います。
よくLD_LIBRARY_PATHやld.so.confにライブラリの検索パスを定義して解決する手法を見ますが、これをやってしまうとシステム全体に影響が出てしまい、ある意味PHPとApacheの住み分けができなくなってしまいます。

 

そこで理想的な解決手段として取り得るのが、実行バイナリにシェアードライブラリの検索パスを埋め込み、実行時にシェアードライブラリを探しに行くパスを指定してしまうことです。この手法を用いるとPHP用のOpenSSL、Apache用のOpenSSLと言った複数バージョンのOpenSSLを使い分けることが可能となります。ただし、ハードルが少し高く、PHP、Apache両方ともソースコードからビルドする必要があります。

 

なぜかというと、検索パスの指定、実行バイナリへの埋め込みはバイナリを生成するコンパイル時にしかできないからです。それでは、実際の例を見ていきましょう。

## PHPのインストール
### 周辺ライブラリのインストール
```
dnf config-manager --set-enabled powertools
dnf install epel-release
dnf install libtool \
            gcc-c++ \
            gcc-toolset-11-gcc-c++

dnf install wget \
            tar \
            gcc \
            make \
            zlib \
            zlib-devel \
            expat \
            expat-devel \
            libtool \
            pcre \
            pcre-devel -y

dnf install readline \
            readline-devel -y

dnf install autoconf \
            uw-imap \
            uw-imap-devel \
            libzip \
            libzip-devel \
            zlib \
            zlib-devel \
            curl \
            libcurl \
            libcurl-devel \
            libssh \
            libssh-config \
            libssh-devel \
            gd \
            gd-devel \
            libpng \
            libpng-devel \
            freetype \
            freetype-devel \
            fontconfig \
            fontconfig-devel \
            libjpeg-turbo \
            libjpeg-turbo-devel \
            libXpm \
            libXpm-devel \
            libtiff \
            libtiff-devel \
            libxslt \
            libxslt-devel \
            re2c \
            libxml2 \
            libxml2-devel \
            libwebp \
            libwebp-devel \
            oniguruma \
            oniguruma-devel \
            sqlite-devel
```
```
wget https://imagemagick.org/archive/ImageMagick.tar.gz
tar xvfz ImageMagick.tar.gz
cd ImageMagick-7.1.1-43
./configure --prefix=/var/home/lib/imagic
make all
make install
```
### PHPソースコードのダウンロード・展開
```
./configure \
--prefix=/var/home/ap/php \
--enable-fpm \
--with-config-file-path=/var/home/ap/php/etc \
--enable-libgcc \
--with-openssl \
--with-zlib \
--with-zlib-dir=/usr \
--enable-gd \
--with-freetype \
--with-jpeg \
--with-xpm \
--with-webp \
--enable-bcmath \
--with-bz2 \
--enable-calendar \
--with-curl \
--enable-dba=shared \
--enable-exif \
--with-curl \
--enable-gd-jis-conv \
--with-gettext \
--enable-mbstring \
--with-mysqli=mysqlnd \
--with-pdo-mysql=mysqlnd \
--enable-pcntl \
--with-readline \
--enable-soap \
--enable-sockets \
--with-xsl \
--with-imap \
--with-imap-ssl \
--with-libdir=lib64 \
--with-kerberos \
--enable-opcache \
--enable-shared 

make all
make install
```
### 各種拡張モジュールのインストール
```
wget https://pecl.php.net/get/apcu-5.1.22.tgz
※ https://pecl.php.net/package/APCu

tar xvfz apcu-5.1.22.tgz
cd apcu-5.1.22/
/var/home/ap/php/bin/phpize
./configure --enable-apcu --with-php-config=/var/home/ap/php/bin/php-config
make all
make install
Installing shared extensions:     /var/home/ap/php/lib/php/extensions/no-debug-non-zts-20210902/
Installing header files:          /var/home/ap/php/include/php/
```
```
※https://pecl.php.net/package/imagick
wget https://pecl.php.net/get/imagick-3.7.0.tgz
tar xvfz imagick-3.7.0.tgz
cd imagick-3.7.0
/var/home/ap/php/bin/phpize
PKG_CONFIG_PATH=/var/home/lib/imagic/lib/pkgconfig/ \
./configure --prefix=/var/home/ap/php/lib/php/extensions/no-debug-non-zts-20210902 --with-libdir=/var/home/lib/imagic/lib --with-php-config=/var/home/ap/php/bin/php-config
make all
cp modules/imagick.so /var/home/ap/php/lib/php/extensions/no-debug-non-zts-20210902/
```
### シェアードライブラリのリンク先を確認する
```
cd /var/home/ap/php/bin
ldd ./php
        linux-vdso.so.1 (0x00007ffe377dc000)
        libcrypt.so.1 => /lib64/libcrypt.so.1 (0x00007fc6452ee000)
        libc-client.so.2007 => /lib64/libc-client.so.2007 (0x00007fc644fd8000)
        libresolv.so.2 => /lib64/libresolv.so.2 (0x00007fc644dc0000)
        libreadline.so.7 => /lib64/libreadline.so.7 (0x00007fc644b71000)
        libncurses.so.6 => /lib64/libncurses.so.6 (0x00007fc644946000)
        libtinfo.so.6 => /lib64/libtinfo.so.6 (0x00007fc644719000)
        librt.so.1 => /lib64/librt.so.1 (0x00007fc644511000)
        libbz2.so.1 => /lib64/libbz2.so.1 (0x00007fc644300000)
        libutil.so.1 => /lib64/libutil.so.1 (0x00007fc6440fc000)
        libm.so.6 => /lib64/libm.so.6 (0x00007fc643d7a000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007fc643b76000)
        libxml2.so.2 => /lib64/libxml2.so.2 (0x00007fc64380e000)
        libgssapi_krb5.so.2 => /lib64/libgssapi_krb5.so.2 (0x00007fc6435b9000)
        libkrb5.so.3 => /lib64/libkrb5.so.3 (0x00007fc6432ce000)
        libk5crypto.so.3 => /lib64/libk5crypto.so.3 (0x00007fc6430b7000)
        libcom_err.so.2 => /lib64/libcom_err.so.2 (0x00007fc642eb3000)
        libssl.so.1.1 => /lib64/libssl.so.1.1 (0x00007fc642c1e000)
        libcrypto.so.1.1 => /lib64/libcrypto.so.1.1 (0x00007fc642733000)
        libsqlite3.so.0 => /lib64/libsqlite3.so.0 (0x00007fc64241f000)
        libz.so.1 => /lib64/libz.so.1 (0x00007fc642207000)
        libcurl.so.4 => /lib64/libcurl.so.4 (0x00007fc641f78000)
        libpng16.so.16 => /lib64/libpng16.so.16 (0x00007fc641d43000)
        libwebp.so.7 => /lib64/libwebp.so.7 (0x00007fc641ad5000)
        libjpeg.so.62 => /lib64/libjpeg.so.62 (0x00007fc64186c000)
        libXpm.so.4 => /lib64/libXpm.so.4 (0x00007fc641659000)
        libX11.so.6 => /lib64/libX11.so.6 (0x00007fc641315000)
        libfreetype.so.6 => /lib64/libfreetype.so.6 (0x00007fc641059000)
        libonig.so.5 => /lib64/libonig.so.5 (0x00007fc640dd5000)
        libxslt.so.1 => /lib64/libxslt.so.1 (0x00007fc640b94000)
        libexslt.so.0 => /lib64/libexslt.so.0 (0x00007fc64097d000)
        libgcrypt.so.20 => /lib64/libgcrypt.so.20 (0x00007fc64065f000)
        libgpg-error.so.0 => /lib64/libgpg-error.so.0 (0x00007fc64043e000)
        libc.so.6 => /lib64/libc.so.6 (0x00007fc640068000)
        libpam.so.0 => /lib64/libpam.so.0 (0x00007fc63fe58000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fc63fc38000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fc645517000)
        liblzma.so.5 => /lib64/liblzma.so.5 (0x00007fc63fa11000)
        libkrb5support.so.0 => /lib64/libkrb5support.so.0 (0x00007fc63f800000)
        libkeyutils.so.1 => /lib64/libkeyutils.so.1 (0x00007fc63f5fc000)
        libnghttp2.so.14 => /lib64/libnghttp2.so.14 (0x00007fc63f3d5000)
        libidn2.so.0 => /lib64/libidn2.so.0 (0x00007fc63f1b7000)
        libssh.so.4 => /lib64/libssh.so.4 (0x00007fc63ef47000)
        libpsl.so.5 => /lib64/libpsl.so.5 (0x00007fc63ed36000)
        libldap-2.4.so.2 => /lib64/libldap-2.4.so.2 (0x00007fc63eae7000)
        liblber-2.4.so.2 => /lib64/liblber-2.4.so.2 (0x00007fc63e8d7000)
        libbrotlidec.so.1 => /lib64/libbrotlidec.so.1 (0x00007fc63e6ca000)
        libxcb.so.1 => /lib64/libxcb.so.1 (0x00007fc63e4a1000)
        libaudit.so.1 => /lib64/libaudit.so.1 (0x00007fc63e270000)
        libselinux.so.1 => /lib64/libselinux.so.1 (0x00007fc63e045000)
        libunistring.so.2 => /lib64/libunistring.so.2 (0x00007fc63dcc4000)
        libsasl2.so.3 => /lib64/libsasl2.so.3 (0x00007fc63daa6000)
        libbrotlicommon.so.1 => /lib64/libbrotlicommon.so.1 (0x00007fc63d885000)
        libXau.so.6 => /lib64/libXau.so.6 (0x00007fc63d681000)
        libcap-ng.so.0 => /lib64/libcap-ng.so.0 (0x00007fc63d47b000)
        libpcre2-8.so.0 => /lib64/libpcre2-8.so.0 (0x00007fc63d1f7000)
```
上記、リンクの情報を見ていただければ、パッケージでインストールしたOpenSSLにリンクしていることが確認できます。
それでは、続いてソースコードからインストールしたOpenSSLにリンクするApacheのインストールを行ってみましょう。
注）OpenSSL3.3.2が/var/home/lib/opensslにインストールされていることを前提とします。
## Apacheのインストール
### 周辺ライブラリのインストール
```
dnf install jansson \
            jansson-devel \
            wget \
            tar \
            gcc \
            make \
            zlib \
            zlib-devel \
            expat \
            expat-devel \
            libtool \
            pcre \
            pcre-devel -y
```
```
wget https://dlcdn.apache.org//apr/apr-1.7.4.tar.gz
tar xvfz apr-1.7.4.tar.gz
cd apr-1.7.4
./configure \
--prefix=/var/home/lib/apr \
--enable-shared \
--enable-threads \
--enable-posix-shm

make all
make install

mv /var/home/lib/apr /var/home/lib/apr1.7.4
ln -s /var/home/lib/apr1.7.4 /var/home/lib/apr
```
```
wget https://dlcdn.apache.org//apr/apr-util-1.6.3.tar.gz
tar xvfz apr-util-1.6.3.tar.gz
cd apr-util-1.6.3
./configure \
--prefix=/var/home/lib/apr-util \
--with-apr=/var/home/lib/apr/bin/apr-1-config

make all
make install

mv /var/home/lib/apr-util /var/home/lib/apr-util1.6.3
ln -s /var/home/lib/apr-util1.6.3 /var/home/lib/apr-util
```
```
dnf install libxml2 libxml2-devel libev libev-devel jansson jansson-devel c-ares c-ares-devel
wget https://github.com/nghttp2/nghttp2/releases/download/v1.62.1/nghttp2-1.62.1.tar.gz
tar xvfz nghttp2-1.62.1.tar.gz
cd nghttp2-1.62.1
./configure --prefix=/var/home/lib/nghttp2 \
            --enable-lib-only
gmake
(約3分かかる)
gmake install

mv /var/home/lib/nghttp2 /var/home/lib/nghttp2-1.62.1
ln -s /var/home/lib/nghttp2-1.62.1 /var/home/lib/nghttp2
```
### Apacheソースコードのダウンロード・展開
```
wget https://dlcdn.apache.org/httpd/httpd-2.4.62.tar.gz
tar xvfz httpd-2.4.62.tar.gz
```
### Apacheコンパイル・インストール
LDFLAGSに-Wl,-rpathをセットすることでバイナリに検索パスを埋め込むことができます。
```
cd httpd-2.4.62
LDFLAGS="-Wl,-rpath=/var/home/lib/openssl/lib64" \
./configure \
  --prefix=/var/home/ap/apache \
  --with-apr=/var/home/lib/apr \
  --with-apr-util=/var/home/lib/apr-util \
  --enable-ssl \
  --enable-so \
  --enable-mods-shared=all \
  --enable-mpms-shared=all \
  --with-ssl=/var/home/lib/openssl \
  --with-nghttp2=/var/home/lib/nghttp2

LDFLAGS="-Wl,-rpath=/var/home/lib/openssl/lib64" \
make all

LDFLAGS="-Wl,-rpath=/var/home/lib/openssl/lib64" \
make install

mv /var/home/ap/apache /var/home/ap/apache2.4.62
ln -s /var/home/ap/apache2.4.62 /var/home/ap/apache
```
### シェアードライブラリのリンク先を確認する
```
cd /var/home/ap/apache/modules
ldd mod_ssl.so

        linux-vdso.so.1 (0x00007ffca9539000)
        libssl.so.3 => /var/home/lib/openssl/lib64/libssl.so.3 (0x00007f8a30190000)
        libcrypto.so.3 => /var/home/lib/openssl/lib64/libcrypto.so.3 (0x00007f8a2fa40000)
        libuuid.so.1 => /lib64/libuuid.so.1 (0x00007f8a2f838000)
        librt.so.1 => /lib64/librt.so.1 (0x00007f8a2f630000)
        libcrypt.so.1 => /lib64/libcrypt.so.1 (0x00007f8a2f407000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f8a2f1e7000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007f8a2efe3000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f8a2ec0d000)
        libz.so.1 => /lib64/libz.so.1 (0x00007f8a2e9f5000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f8a306cf000)
```
上記を参照いただければわかりますが、ソースコードからインストールしたOpenSSLにリンクしていることがわかります。
ちなみに下記コマンドでmod_ssl.soの中を見ると以下の結果が得られます。
```
readelf -d mod_ssl.so

Dynamic section at offset 0x3ad10 contains 33 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libssl.so.3]
 0x0000000000000001 (NEEDED)             Shared library: [libcrypto.so.3]
 0x0000000000000001 (NEEDED)             Shared library: [libuuid.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [librt.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libcrypt.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libpthread.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libdl.so.2]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x000000000000000e (SONAME)             Library soname: [mod_ssl.so]
 0x000000000000000f (RPATH)              Library rpath: [/var/home/lib/openssl/lib64]
 0x000000000000000c (INIT)               0xb160
 0x000000000000000d (FINI)               0x2b048
 0x0000000000000019 (INIT_ARRAY)         0x239e30
 0x000000000000001b (INIT_ARRAYSZ)       8 (bytes)
 0x000000000000001a (FINI_ARRAY)         0x239e38
 0x000000000000001c (FINI_ARRAYSZ)       8 (bytes)
 0x000000006ffffef5 (GNU_HASH)           0x1f0
 0x0000000000000005 (STRTAB)             0x3518
 0x0000000000000006 (SYMTAB)             0x218
 0x000000000000000a (STRSZ)              10185 (bytes)
 0x000000000000000b (SYMENT)             24 (bytes)
 0x0000000000000003 (PLTGOT)             0x23b000
 0x0000000000000002 (PLTRELSZ)           12648 (bytes)
 0x0000000000000014 (PLTREL)             RELA
 0x0000000000000017 (JMPREL)             0x7ff8
 0x0000000000000007 (RELA)               0x6198
 0x0000000000000008 (RELASZ)             7776 (bytes)
 0x0000000000000009 (RELAENT)            24 (bytes)
 0x000000006ffffffe (VERNEED)            0x6128
 0x000000006fffffff (VERNEEDNUM)         3
 0x000000006ffffff0 (VERSYM)             0x5ce2
 0x000000006ffffff9 (RELACOUNT)          302
 0x0000000000000000 (NULL)               0x0
```
mod_ssl.so内にLibrary rpathが定義されており、ソースコードからインストールしたOpenSSLのディレクトリを検索しに行くようパスが埋め込まれています。

このようにするとシステム上に複数バージョンのOpenSSLを同居させ、それぞれのアプリケーションから使い分けすることができるようになります。
以上となります。お疲れ様でした！