Linux(CentOS, Ubuntu)のサーバーでデータ解析を行う際に,anaconda環境でRやPythonの管理を行っています。R関連のライブラリのエラーで,anacondaの再インストールに追い込まれていました。解決法を探していると,ライブラリの概念に詳しくなったので自分用メモとして記載してます。(めんどくさい方は 5.解決法 のとこだけ読んでください)
2019-10-30 5.解決法に関して追記を行いました。
##1. PythonとRのcondaによる管理と問題点
condaにIRkernelを使うと,RをJupyter notebook上で動かせるようになるのですが, (IRkernelのInstall法はこちら) このやり方だと,R関連のライブラリのpath周りで,よくエラーが起こるようになります。
調べてみると以下のようにcondaを中心にPython,Rのパッケージの管理を行っていると,ライブラリ関係でのトラブルを起こすことは一部ではよく知られているようです。
(記事1, 記事2 , 記事3)
##2. Linuxにおけるライブラリの概念
まず,Linuxのライブラリの概念を理解する必要があります。
動的ライブラリ,静的ライブラリの概念に関して,詳しくはこちら : リンク1 , リンク2, リンク3
ざっくりとですが
ライブラリ : よく使われる関数や変数の集まり。
静的ライブラリ : コード作成時にプログラム内に組み込まれるライブラリ。
動的ライブラリ : コード実行時にプログラムから読み込まれるライブラリ。
今回のケースで問題となるのは動的ライブラリです。
Anacondaをインストール後にはRが関連するブログラムの動的ライブラリへのリンクがおかしくなるようです。
##3. Rにおけるライブラリの概念
Rにおいてはライブラリという言葉は下記の2つの意味のいずれにも使われています。(詳細はこちら)
(1) packageのインストールされる場所
(2) 動的ライブラリ,静的ライブラリの置かれるフォルダの場所
(1)に関してはフォルダ名が"library",(2)は"lib"とつけられています。(検証時 Rはver3.5.0)
Rにおけるライブラリのpathは,R起動後に .libPaths()とすることで確認できます。Rのインストール時のディレクトリを基準として,その直下のlibraryフォルダ(/path/to/the/R-install directory/library/)ような形で決まるようです。(筆者調べ)
そして,R内で新たにpackageをインストールすると .libPaths()の1つめのPathの場所にインストールされます。
ちなみに,R起動前にシェルの環境変数でR_USER_LIBSを指定すると,この.libPaths()の1つめは,$R_USER_LIBSに置き換わります。
##4. Anaconda導入後のライブラリ
Anacondaインストール後に,condaによりRの管理を行っていると,あるときにはRの指定するpathへのライブラリのインストール,あるときにはAnacondaで管理されるフォルダへのライブラリのインストールが起こるようで,結果としてRのプログラムが必要とするライブラリが,Rのライブラリpath (.libPaths())が指定するフォルダに存在しないということが起こるようです。
このため,新たにライブラリへのpathを指定する必要が出てきます。
##5. 解決法
Rに限らず,一般的なすべてのツール/コマンドに対するライブラリへのpathの追加は,環境変数であるLD_LIBRARY_PATHを使用します。詳細1, 詳細2
もしくは,R内の問題だけであれば.libPaths()を書き換えると対応可能になります(書き換え方)。
例えば,condaでRの管理も併用して行っていると
よくlibssl.soなどのライブラリが見つからない,RCurl.soが必要なライブラリを呼び出せない,のようなエラーがでて,Rが起動できなくなったり,パッケージのインストールができなかったりします。
この際に,その動的ライブラリの存在する場所(通常はanacondaのフォルダ以下に含まれることが多い様子)をfindコマンドなどで探して,
(1)そこへのpathをexport LD_LIBRARY_PATH=PATH/TO/THE/R-library:$LD_LIBRARY_PATH
のような形で指定する。
(2)もともとのRの動的ライブラリの場所に,他の場所から必要なライブラリを探してコピー/ペーストする。
などで解決します。
(1)は,他の時にまで影響を与えることが多いので,R起動時直前のみに指定する。(R使用後はもとに戻す。)
(2)は必要なライブラリの数が少ないときはこれでうまく対応できますが,多いときは煩雑です。
###解決法の追記:
上記以外の解決法として,(3)を下記に追加しました。これが一番良いかもです。(が,少々めんどくさい。。。)
(3) 関連するコマンド (例えば,ここではsalmon)がリンクしている動的ライブラリを下記で探す。
ldd $(which salmon)
linux-vdso.so.1 => (0x00007fff88992000)
libtbbmalloc_proxy.so.2 => /Path/To/The/Other/Library/libtbbmalloc_proxy.so.2 (0x00007f69a6706000)
libtbb.so.2 => /Path/To/The/Other/Library/libtbb.so.2 (0x00007f69a66c3000)
libgomp.so.1 => not found
librt.so.1 => /lib64/librt.so.1 (0x00007f69a595b000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f69a5757000)
libstdc++.so.6 => /Path/To/The/Other/Library/libstdc++.so.6 (0x00007f69a652a000)
libm.so.6 => /lib64/libm.so.6 (0x00007f69a5455000)
libgcc_s.so.1 => /Path/To/The/Other/Library/libgcc_s.so.1 (0x00007f69a523f000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f69a5023000)
libc.so.6 => /lib64/libc.so.6 (0x00007f69a4c55000)
/lib64/ld-linux-x86-64.so.2 (0x00007f69a64ec000)
libtbbmalloc.so.2 => /Path/To/The/Other/Library/./libtbbmalloc.so.2 (0x00007f69a4c16000)
ここで,not foundと指定されたlibraryを探しに行く。
例えば,libgomp.so.1を探すと,
色々頑張ると
https://packages.ubuntu.com/xenial/amd64/libgomp1
みたいなページにたどり着きます。(ご自分のOSに合わせて探してください。)
このような場所から,必要なライブラリをダウンロードして,ライブラリのリンクしている場所に設置すると解決するようです。
Dockerを使えれば,このような苦労はなさそうな気がしますが,condaでのtoolとR(IRkernel)の管理が両立するようなdockerってあるんでしょうか?