2012-02-04 6 views
5

Estoy tratando de obtener código de código abierto funcionando (el proyecto es here). Es una gran base de código C++ con un contenedor python (muy) delgado que usa CDLL para cargar el C++ y llamar a algunas funciones C que están disponibles para permitir el desarrollo de scripts Python primitivos del código.python cargando c lib con CDLL, no ve bibliotecas en la ruta de Python

Sin embargo, el código inicial de importación se estrella porque no puede encontrar los archivos .so sentados junto a él en site-packages:

en el archivo instalado:

from ctypes import * 

try: 
    self.lib = CDLL("_lammps.so") 
except: 
    try: 
    self.lib = CDLL("_lammps_serial.so") 
    except: 
    raise OSError,"Could not load LAMMPS dynamic library" 

y en un script o el intérprete:

from lammps import lammps 
l = lammps() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "lammps.py", line 42, in __init__ 
    raise OSError,"Could not load LAMMPS dynamic library" 
OSError: Could not load LAMMPS dynamic library 

Otras respuestas might seem to have this covered, pero esto sólo funciona si CDLL() se llama dentro de la escritura de hecho invocado (o el directorio de trabajo del aviso que ejecutó el intérprete), es decir, si la 'ruta relativa' está en espacio de usuario, en lugar de python-biblioteca-espacio.

¿Cómo instalamos con seguridad para importar una biblioteca C/C++ que construimos nosotros mismos? Sin contaminar las ubicaciones de la biblioteca del sistema como /usr/lib, que no es muy pitónico, no veo una solución fácil.

(EDIT: corregido los nombres de función, refactorización claro inútil lo siento!)

+0

más: la biblioteca en cuestión tenía un símbolo faltante, por lo que este código podría haber enmascarado un error diferente; ¡uno no debe asumir que usted sabe cuál es la excepción del sistema y arrojar la suya! De hecho, la pregunta sigue siendo válida luego de una investigación adicional; el sistema * estaba * arrojando el error correcto la primera vez (probé esto copiando .so a '/ usr/lib' y ejecutando' CDLL() 'desde el prompt interactivo.) – tehwalrus

Respuesta

1

Puede usarse en strace -eopen, verá algo como esto:

open("tls/x86_64/_lammps.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) 
open("tls/_lammps.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) 
open("x86_64/_lammps.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) 
open("_lammps.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) 
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6 
open("/lib/_lammps.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) 
open("/usr/lib/_lammps.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) 

que le muestra todos los lugares donde pitón ctypes busca tu biblioteca. Hasta ahora no he podido encontrar un ajuste de variable de entorno de tiempo de ejecución para agregar ubicaciones de búsqueda en mi sistema, quizás tenga que usar rutas absolutas.

+0

gracias, lo investigaré cuando Tengo un momento. Estoy en Mac OS X, así que tendré que portar tu sugerencia para dtrace (lo que afortunadamente no debería ser tan malo). – tehwalrus

1

Puede usar la variable __file__ en el paquete que está realizando la importación. Simplemente use las diversas funciones de os.path para extraer la ruta completa y absoluta del directorio desde __file__, y luego úsela al nombre de archivo de su biblioteca. Algo así como:

temp = os.path.abspath(__file__) 
temp = os.path.realpath(temp) 
temp = os.path.dirname(temp) 
temp = os.path.join(temp, "_lammps.so") 
lib = CDLL(path) 

También puede ser que desee probar diferentes variaciones de su nombre de archivo de núcleo (es decir, con .dll o .dylib en lugar de .so, y con y sin un prefijo lib, y tal vez incluso con números de versión anexa) si usted quiere ser independiente de la plataforma, y ​​su sistema de construcción podría producir tal cosa. Puede probar varias versiones o simplemente usar glob.glob para encontrar una aceptable.

Tengo que decir que creo que es extraño que no exista tal función en la biblioteca estándar. El ctypes.util.find_library no es lo suficientemente flexible (o minucioso) para este tipo de uso (que yo pensaría que estaba muy extendido). Incluso una función que buscó en el archivo PYTHONPATH hubiera sido bastante útil (aunque no difícil de escribir).

Por otra parte, parece que si simplemente agrega el directorio correcto a LD_LIBRARY_PATH, should be able to load it.

2

Im en Linux, todo lo que hice para solucionar este problema fue puesto a la ruta absoluta del módulo os, y funciona

from ctypes import * 
import os 

xss = cdll.LoadLibrary(os.path.abspath("libxss.so.1")) 
print xss.xss_test_1() 

Ésta es Python 2.7 también.

Cuestiones relacionadas