web-dev-qa-db-ja.com

実行時にctypesのLD_LIBRARY_PATHを変更する

Ctypesがライブラリをどこにでもロードできるように、実行時にこの環境変数をどのように更新しますか?私は以下を試しましたが、どちらもうまくいかないようです。

from ctypes import *
os.environ['LD_LIBRARY_PATH'] = "/home/starlon/Projects/pyCFA635/lib"  
os.putenv('LD_LIBRARY_PATH', "/home/starlon/Projects/pyCFA635/lib")  
lib = CDLL("libevaluator.so")
37
Scott

Python=などのプログラムが実行されているときには、ダイナミックローダー(ld.so.1または類似のもの)はすでにLD_LIBRARY_PATHを読み込んでおり、その後の変更に気づきません。したがって、 Pythonソフトウェア自体がLD_LIBRARY_PATHを評価し、それを使用してdlopen()のライブラリの使用可能なパス名を作成します。スクリプトで変数を設定すると、効果。

あなたがそれがうまくいかないと言うなら、Pythonはすべての可能なライブラリ名を構築して試していないと思う;それはおそらくLD_LIBRARY_PATHだけに依存しているでしょう。

41

CDLLまたはcdll.LoadLibrary()への完全修飾パスを指定した場合でも、Pythonを呼び出す前にLD_LIBRARY_PATHを設定する必要がある場合があります。ロードする共有ライブラリが明示的に別の共有ライブラリを参照し、そのライブラリの.soに「rpath」が設定されていない場合、すでにロードされていても、ライブラリは見つかりません。ライブラリ内のrpathは、そのライブラリに必要な他のライブラリを検索するために使用される検索パスを指定します

たとえば、私が作成したものではない、相互に依存するサードパーティライブラリのセットがある場合があります。 b.soはa.soを参照します。事前にa.soを読み込んでも、

ctypes.cdll.LoadLibrary('/abs/path/to/a.so')
ctypes.cdll.LoadLibrary('/abs/path/to/b.so')

B.soはrpathなしで単に「a.so」を参照しているため、2番目のロードでエラーが発生し、b.soはそれが正しいa.soであることを認識していません。したがって、前もってLD_LIBRARY_PATHを設定して「/ abs/path/to」を含める必要があります。

LD_LIBRARY_PATHを設定する必要がないようにするには、.soファイルのrpathエントリを変更します。 Linuxでは、これを行うユーティリティが2つあります。chrpathと patchelf です。 chrpathはUbuntuリポジトリから入手できます。一度もなかった.soのrpathを変更することはできません。 patchelfはより柔軟です。

30
Dan Halbert

CDLLには完全修飾パス名を渡すことができるため、たとえば、.soがpythonスクリプトと同じディレクトリにあるスクリプトの1つで次のコードを使用しています。

import os
path = os.path.dirname(os.path.realpath(__file__))
dll = CDLL("%s/iface.so"%path)

あなたの場合、以下で十分です。

from ctypes import *
lib = CDLL("/home/starlon/Projects/pyCFA635/lib/libevaluator.so")
16
Gordon Wrigley

次のように、現在の作業ディレクトリに相対するrpathを使用してバイナリをコンパイルします。

gcc -shared -o yourbinary.so yoursource.c otherbinary.so \
    -Wl,-rpath='.',-rpath='./another/relative/rpath' -fpic

次に、実行時にpythonの作業ディレクトリを次のように変更できます。

import os
os.chdir('/path/to/your/binaries')

このように、ローダーはotherbinary.soのような他の動的ライブラリも検出します

3
Simon Ramstedt