soファイルの名前を変えても別プログラムからリンクがうまくいかなかった問題での対応。
Introduction
NVIDIA Caffeを改造したライブラリを作っているのですが、都合上オリジナルのNVIDIA Caffe (libcaffe.so) と共存させる必要があり、その改造Caffe (以下libcaffemod.so) をシステムにインストールします。
オリジナルのNVIDIA Caffeの出力は下記。
1 | ls -la |
単純にファイル名を変えて、システム (/usr/lib/x86_64-linux-gnu/)にインストールしたところでうまく動きません。
というのも、単純に名前を変えてリンクしようとしてもうまくいきません。
例えば、下記の簡単なプログラム。
1 |
|
これに、libcaffe.so.0.17.3をlibcaffemod.soに名前を変えてコピーしリンクさせてみます。
CMakeLists.txtは下記。
1 | cmake_minimum_required(VERSION 3.0.0) |
実行してみます。単純にCaffeのバージョンを出力するだけです。
ではリンクしているsoファイルは何になるか?
1 | ldd build/CaffeModExample | grep caffe |
名前変更前にリンクしています。
動いているのはリンク先の同じディレクトリにオリジナルのlibcaffeが存在するからです。
libcaffe.soを全部削除するとプログラムが動かなくなります。
どうするべきか。
How to?
共有オブジェクトファイルは内部に共有オブジェクトの名前を保持しています。
これが原因で、リンク先がファイル名変更前になっていたのです。
1 | objdump -p libcaffemod.so | grep SONAME |
正攻法はNVIDIA CaffeのMakefileやCMakeLists.txtを書き換えて、正しい名前で出力するようにするべきです。
が、単純に変更してもうまくビルドできませんでした。
なので別の方法を。
PatchELF
PatchELFというLinuxの ELF (Executable and Linkable Format)ファイル を操作するツールを使います。
バイナリで配布はされていないのでソースからビルドします。
最新版を使ってください。少し古い版の0.8はうまく動きませんでした。
1 | wget https://github.com/NixOS/patchelf/archive/0.10.tar.gz |
make installはしてもしなくても。
同じディレクトリのsrc配下にバイナリが生成されるので。
これを使って先のlibcaffemod.soを変更します。
**–set-soname** コマンドを使います。最初の引数が新しい名前、最後が対象ファイルのパスです。
1 | src/patchelf --set-soname libcaffemod.so libcaffemod.so |
見事に変更されました。
一度サンプルプログラムのbuildを削除してからビルドし直して、lddでリンク先を確認してみます。
1 | ldd build/CaffeModExample | grep caffe |
きちんと変わっていますね。