Mac OS Xでプログラムの依存ライブラリや実際のロード状況を見る方法


# 背景
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
```

もう少し時間が取れたらビルドし直しにもチャレンジしてみます。