Linux/ビルドとyumの混在

ソースからのビルドと yum からのインストールの混在について(2017-03-21)


正直、私もまだ手探りの話題です。



私のCentOS 7 環境で、OpenSSLを最新版にしたいのですが、
1.1.0 には大きな変更が入ったらしく、そのライブラリを利用したパッケージは
このページ記載時点では 1.0.x を使ったものが多いです。

yum install/updateできる 1.0.1 と、最新ソースからの 1.1.0 で
混ぜるな危険状態です。

それでも最新版を入れたい
物好き or のっぴきならない状況の人々に、自分の屍を越えて行ってもらうためにも、
試してみた内容をメモしておきます。

何か対策を講じる際に、そのヒントになれば幸いです。

仮想ホスト、Docker、その他諸々、を使えばいいじゃない

申し開きもございません。
バージョンごとに環境を分けた方がシンプルですよね~・・・


だが断る、という方は続きをどうぞ。

インストールする場所の指定について

まず、前提として、
コマンド、ヘッダファイル(~.h)、ライブラリ(lib~)など
はっきり住み分けることができるかは、install 前に確認しましょう。

多くのパッケージは、ソースからビルドする際の

configure;   make;   make insall;

という流れの中の最初、./configure の各オプションで、
読み込むべきヘッダファイルやライブラリ等を設定します。
(./configure --help や付属の各テキストで確認できます)

ここでインストール先のディレクトリ(prefixなどで指定)をはじめとした
各オプションのデフォルト値を確認する必要があります。
既存のパッケージ、ビルドの新パッケージがごっちゃになると収集がつかなくなります。

例として、 postfix はデフォルトの prefix は「/」だったはずです*1

ソースからビルドする場合の openssl-1.1.0eでは、INSTALL テキストにデフォルトは
/usr/local に入ると書いてありました。
私の CentOS7 環境だと、yum install openssl-devel で入れた 1.0.1版は
/bin/openssl や /usr/include/openssl へ入りました。
一応、/usr と /usr/local それぞれに分かれたイメージでしょうか。

コマンドの優先順位について

PATHでコントロールできるよね、という話です。

まず前提条件として、前述のような新旧の openssl が入った状態です。
/usr には yum install した openssl(1.0.1)
/usr/local には ソースビルドした openssl(1.1.0) があります。

私の環境だと /usr/local 側が優先されています。
(ローカルを見て、システムを見るという順番)

env | grep PATH

環境変数PATH で /usr/local/bin よりも後半に /usr/bin あるのが確認できます。

また、共有ライブラリは
環境変数LD_LIBRARY_PATH や、/etc/ld.so.conf* 、それらを読み込む ldconfig コマンド等で
順番を指定することになります。

これらである程度は新・旧をコントロールできると思います。

・・・ある程度、としか言えないのは、やっぱり各パッケージの実装方法次第だからです。
極端な例だと、モジュール内部でPATHを指定している場合は順番変更しようがない、とか。

ビルドの優先順位について

make できない、困った、という話です。

話が再び、ソースのビルドに戻りますが、
以下、squid-3.5.24 をビルドした際の現象です。

# ./configure --with-openssl=/usr
# make
(中略)
../../src/ssl/gadgets.h:83:45: error: ‘CRYPTO_LOCK_X509’ was not declared in this scope
 typedef LockingPointer<X509, X509_free_cpp, CRYPTO_LOCK_X509> X509_Pointer;

config.logを見ても
with-openssl は有効になって、
「-I/usr/include」「-L/usr/lib64 -lssl -lcrypto」 のように更新されていますが、
make の結果は、CRYPTO_LOCK~に必要な openssl/crypto.h が読めていない。
/usr/include (古い 1.0.1版)ではなく
/usr/local/include (新しい 1.1.0版)を読んでいるようです。

・・・解せぬ。


ここで脱線、少し実験をします。

# vi test.c
(以下、C でハローワールドを作成)
#include <stdio.h>
int main()
{
       printf("Hello World!\n");
}
# gcc -v test.c
(以下、コンパイル時の詳細出力からの抜粋です)
#include <...> search starts here:
 /usr/lib/gcc/x86_64-redhat-linux/x.x.x/include
 /usr/local/include
 /usr/include
End of search list.

つまり、この環境ではシステムのデフォルトとして、
/usr/local/include、/usr/include の順にヘッダを探します。
先ほど make エラーになったのはこれが原因のようです。先に /usr/local/include を読んでしまうと。

この順序に割り込む方法として環境変数 CPATH がありますが、

# export CPATH=/usr/include
# gcc -v test.c
(中略)
ignoring duplicate directory "/usr/include"
 as it is a non-system directory that duplicates a system directory

システムデフォルトのPATH(/usr/include)は定義しても無視されてしまいました。
無視されちゃったら、順番を変えられませんがな・・・
よって、 /usr/include/openssl を /usr/local/include/openssl より優先させるために
少し回りくどく定義します。
以下、同じものをシステムデフォルトのPATH以外の場所に用意する方法で。

# mkdir /my_path/my_include
# cp -pir /usr/include/openssl /my_path/my_include/
# export CPATH=/my_path/my_include
(中略)
#include <...> search starts here:
 /my_path/my_include
 /usr/lib/gcc/x86_64-redhat-linux/x.x.x/include
 /usr/local/include
 /usr/include
End of search list.

もっとスマートな方法もありそうですが、とにかく、
システム初期値と重複しないPATHで、/usr/local よりも先に読み込ませることはできました。
これで旧opensslをベースに make を行うことができます。


これで、squid の話にもどって

# mkdir /my_path/my_include
# cp -pir /usr/include/openssl /my_path/my_include/
# export CPATH=/my_path/my_include
# ./configure --with-openssl=/usr
# make

これで古いバージョンのincludeヘッダを読ませることができました。
apach-2.4.25 でも同じことやりました。(./configure --with-ssl=/usrと、CPATH指定)

ちなみに同じ混在環境の dovecot-2.2.28 の場合は、その逆?で
「./configure LDFLAGS=-L/usr/local/lib64」のように
LDFLAGSで新しい方を指定してあげないと、
古い方(/lib64)を読みに行って make エラーになってしまいました。 (undefined reference to `OPENSSL_sk_pop_free' など)


新旧混在で、どんな不測の事態が起きるのかまだ分かりませんが、
まぁ、何をやったところで不測の事態は起きる時は起き・・・うまくいくといいですね [smile]

ただ、少なくとも前述の通り、めんどくさいです [worried]
make する度に、前述の通りCPATHやら何かしらの手を加える必要があります。

以上、ご参考まで。
このメモが何かのヒントになればと思います。


*1 で、一旦収集がつかなくなり、自環境のOSを入れ直しました。