背景
YosemiteのApacheに Subversionの mod_dav_svn.soや mod_authz_svn.soをロードさせようとしていろいろトラブルが起こりました。原因は、Subversionライブラリが参照している sqliteのライブラリのバージョンと、Yosemite標準のApache(httpd)が参照している sqliteのバージョンが違ったためでした。
ところが、いざそれを解決しようとおもうといろいろと苦労がありました。その際に、OS X上で依存ライブラリの検査などを散々やったので、あとで思い出すためにツールの使い方をメモしておきます。
プログラムの依存ライブラリを見るコマンド otool
まず、このsqliteの問題をググってみると「httpd.conの LoadModuleのロード順を変えるとうまくいく」などの報告が出てきます。ところがその方法を試してもうまくいかなかったので、自分の環境で何が起こっているのかを調査しました。
Macの場合は otool -L というコマンドを使うと、あるプログラムがどのライブラリに依存しているかを見ることができます。これを使って httpdの依存ライブラリを見てみましょう。
ohnaka@ohnaka-mbp:~[172]otool -L /usr/sbin/httpd
/usr/sbin/httpd:
/usr/lib/libpcre.0.dylib (compatibility version 1.0.0, current version 1.1.0)
/usr/lib/libaprutil-1.0.dylib (compatibility version 4.0.0, current version 4.0.0)
/usr/lib/libexpat.1.dylib (compatibility version 7.0.0, current version 7.2.0)
/usr/lib/libiconv.2.dylib (compatibility version 7.0.0, current version 7.0.0)
/usr/lib/libsqlite3.dylib (compatibility version 9.0.0, current version 166.0.0) ←****これ****
/System/Library/Frameworks/LDAP.framework/Versions/A/LDAP (compatibility version 1.0.0, current version 2.4.0)
/usr/lib/libapr-1.0.dylib (compatibility version 5.0.0, current version 5.8.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1213.0.0)
ということで、/usr/lib/sqlite3.dylib に依存していることがわかります。一方、自分でビルドした mod_dav_svn.soを見てみると……
server:~ ohnaka$ otool -L /Volumes/Shared/SvnRepos/apache/libexec/mod_dav_svn.so
/Volumes/Shared/SvnRepos/apache/libexec/mod_dav_svn.so:
/usr/local/lib/libsvn_repos-1.0.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/local/lib/libsvn_fs-1.0.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/local/lib/libsvn_fs_fs-1.0.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/local/lib/libsvn_delta-1.0.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/local/lib/libsvn_fs_util-1.0.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/local/lib/libsvn_subr-1.0.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/libaprutil-1.0.dylib (compatibility version 4.0.0, current version 4.0.0)
/usr/lib/libapr-1.0.dylib (compatibility version 5.0.0, current version 5.8.0)
/usr/lib/libexpat.1.dylib (compatibility version 7.0.0, current version 7.2.0)
/usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.5)
/usr/lib/libsqlite3.dylib (compatibility version 9.0.0, current version 168.0.0) ←****これ****
/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 1151.16.0)
/System/Library/Frameworks/Security.framework/Versions/A/Security (compatibility version 1.0.0, current version 57031.1.35)
/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices (compatibility version 1.0.0, current version 62.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1213.0.0)
とまあ、こちらも /usr/lib/libsqlite3.dylibに依存しています。これは僕がビルドするときに、./configure後に config.statusを直接書き換えて、/usr/lib/以下の sqliteを使うように明示的に指定したためで、それ自体はうまくいっているようです。
稼働中のプロセスがロードしているライブラリを調べる vmmap
これで、大丈夫かと思ったのですが、うまく動きませんでした。原因を探るため、実際に稼働している httpdがどのライブラリをロードしているのかを見てみます。これは vmmap というコマンドを使えば可能です。
まずは、プロセスのIDを調べます。
server:~ ohnaka$ ps auxww | grep httpd
_www 1317 0.0 0.0 2520396 1072 ?? S 9:39AM 0:00.00 /usr/sbin/httpd ....
PIDは 1317 です。ではロードしているライブラリを見てみましょう。root権限が必要なので sudoします。
server:~ ohnaka$ sudo vmmap 1317
Password:
Process: httpd [1317]
Path: /usr/sbin/httpd
Load Address: 0x10032c000
Identifier: httpd
Version: 793
Code Type: X86-64
Parent Process: httpd [504]
Date/Time: 2014-11-12 10:05:22.915 +0900
OS Version: Mac OS X 10.10 (14A389)
Report Version: 7
Analysis Tool: /Applications/Xcode.app/Contents/Developer/usr/bin/vmmap
Analysis Tool Version: Xcode 6.1 (6A1052d)
----
Virtual Memory Map of process 1317 (httpd)
Output report format: 2.3 -- 64-bit process
==== Non-writable regions for process 1317
REGION TYPE START - END [ VSIZE] PRT/MAX SHRMOD REGION DETAIL
__TEXT 000000010032c000-00000001003ad000 [ 516K] r-x/rwx SM=COW /usr/sbin/httpd
__LINKEDIT 00000001003b6000-00000001003ec000 [ 216K] r--/rwx SM=COW /usr/sbin/httpd
MALLOC (admin) 00000001003ed000-00000001003ee000 [ 4K] r--/rwx SM=COW
MALLOC (admin) 00000001003ef000-00000001003f0000 [ 4K] r--/rwx SM=COW
__TEXT 00000001003f0000-000000010041f000 [ 188K] r-x/rwx SM=COW /usr/lib/libpcre.0.dylib
__LINKEDIT 0000000100420000-0000000100423000 [ 12K] r--/rwx SM=COW /usr/lib/libpcre.0.dylib
VM_ALLOCATE 0000000100423000-0000000100424000 [ 4K] r--/rw- SM=SHM
__TEXT 0000000100426000-0000000100440000 [ 104K] r-x/rwx SM=COW /usr/lib/libaprutil-1.0.dylib
__LINKEDIT 0000000100441000-000000010044b000 [ 40K] r--/rwx SM=COW /usr/lib/libaprutil-1.0.dylib
__TEXT 000000010044b000-000000010044d000 [ 8K] r-x/rwx SM=COW /usr/libexec/apache2/mod_authn_file.so
__LINKEDIT 000000010044e000-0000000100450000 [ 8K] r--/rwx SM=COW /usr/libexec/apache2/mod_authn_file.so
__TEXT 0000000100451000-000000010046a000 [ 100K] r-x/rwx SM=COW /usr/lib/libapr-1.0.dylib
__LINKEDIT 000000010046b000-0000000100477000 [ 48K] r--/rwx SM=COW /usr/lib/libapr-1.0.dylib
MALLOC (admin) 0000000100477000-0000000100478000 [ 4K] ---/rwx SM=NUL
MALLOC (admin) 000000010048d000-000000010048f000 [ 8K] ---/rwx SM=NUL
:
大量に出てきました。sqliteでgrepしてみます。
server:~ ohnaka$ sudo vmmap 1317 | grep sqlite
__TEXT 00000001008a0000-000000010093a000 [ 616K] r-x/rwx SM=COW /usr/local/Cellar/sqlite/3.8.7.1/lib/libsqlite3.0.dylib
__LINKEDIT 000000010093f000-000000010094f000 [ 64K] r--/rwx SM=COW /usr/local/Cellar/sqlite/3.8.7.1/lib/libsqlite3.0.dylib
__TEXT 00007fff8a705000-00007fff8a848000 [ 1292K] r-x/r-x SM=COW /usr/lib/libsqlite3.dylib
__DATA 000000010093a000-000000010093f000 [ 20K] rw-/rwx SM=COW /usr/local/Cellar/sqlite/3.8.7.1/lib/libsqlite3.0.dylib
__DATA 00007fff7861e000-00007fff78623000 [ 20K] rw-/rwx SM=COW /usr/lib/libsqlite3.dylib
あら、なぜか /usr/local/Celler/sqlite/ という homebrewで入れた sqliteにも依存があり、両方がロードされています。誰が依存しているんでしょう? Apache自体ということはないので、自分がビルドした mod_dav_svn.soに違いありません。
ここで、もう一度 mod_dav_svn.so の依存ライブラリを見直してみると、
/usr/local/lib/libsvn_repos-1.0.dylib (compatibility version 1.0.0, current version 1.0.0)
という /usr/local/lib 以下のライブラリに依存しています。 /usr/local/lib はhomebrewで入れたものに違いありません。これの依存ライブラリも otool -L で見てみます。
server:~ ohnaka$ otool -L /usr/local/lib/libsvn_repos-1.0.dylib
/usr/local/lib/libsvn_repos-1.0.dylib:
/usr/local/lib/libsvn_repos-1.0.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/local/Cellar/subversion/1.8.10_1/lib/libsvn_fs-1.0.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/local/Cellar/subversion/1.8.10_1/lib/libsvn_fs_fs-1.0.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/local/Cellar/subversion/1.8.10_1/lib/libsvn_delta-1.0.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/local/Cellar/subversion/1.8.10_1/lib/libsvn_fs_util-1.0.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/local/Cellar/subversion/1.8.10_1/lib/libsvn_subr-1.0.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/libexpat.1.dylib (compatibility version 7.0.0, current version 7.2.0)
/usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.5)
/usr/local/opt/sqlite/lib/libsqlite3.0.dylib (compatibility version 9.0.0, current version 9.6.0) ←****これ****
/usr/lib/libaprutil-1.0.dylib (compatibility version 4.0.0, current version 4.0.0)
/usr/lib/libapr-1.0.dylib (compatibility version 5.0.0, current version 5.8.0)
/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 1151.16.0)
/System/Library/Frameworks/Security.framework/Versions/A/Security (compatibility version 1.0.0, current version 57031.1.35)
/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices (compatibility version 1.0.0, current version 62.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1213.0.0)
やはり、/usr/local/opt/sqlite/lib/libsqlite3.0.dylib というのに依存しています。
なお、vmmap とはパスが違いますが、/usr/local/opt/sqliteは /usr/local/Celler/sqliteへのシンボリックリンクです。vmmapでは実体のパスが表示されているだけで同一のものです。
依存関係を図示すると、以下のようになっています。
httpd -+---------------------------------------------------> libsqlite3 (/usr/lib)
+- mod_dav_svn.so -+------------------------------^
+- libsvn_* (/usr/local/Celler) -> libsqlite3 (/usr/local/Celler)
結論
ということで、
- subversionの主要ライブラリは homebrewでインストール
- mod_dav_svn.so だけソースからビルド
というのに無理があるようです。本当は、OS X自体が/usr/bin/svnコマンドを持っているので(開発者用のコマンドラインツールを入れているから?)、subversionのライブラリも一緒に /usr/lib にいれておいてくれれば、それを使ってmod_dav_svn.soをビルドするだけで済んだのですが、/usr/bin/svn の依存ライブラリを見てみると、以下のようになっていて、関連ライブラリはスタティックにリンクされているようです。
ohnaka@ohnaka-mbp:~[177]otool -L /usr/bin/svn
/usr/bin/svn:
/usr/lib/libxcselect.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1213.0.0)
これを直すためには、homebrewを使わずに libsvn_fs-1.0.dylib などの Subversionライブラリ自体をソースコードからビルドしなおして、/usr/lib/libsqlite3 を使うように作り直す必要がありそうです。
実際にはそこまではやらず、結局 リポジトリを作るときに --pre-1.6-compatible というオプションをつけ、sqliteを使わないリポジトリにすることでお茶を濁しました。
# sudo svnadmin create --pre-1.6-compatible myrepos
もう少し時間が取れたらビルドし直しにもチャレンジしてみます。