Python C extensión embalaje DLL junto con pyd
Mi proyecto expone una biblioteca estática static.lib
) a CPython (3.8) intérprete. Se compone de una biblioteca estática que a su vez depende de un controlador DLL FTDI. Después de leer este hilo parece que la solución óptima para proporcionar DLL de terceros es agruparlos junto con un paquete Python - para asegurarse de que DLL se encuentra en el mismo directorio que .pyd
binario.
Los problemas que estoy teniendo es que después de correr pip install .
para mi paquete, el DLL requerido (llamarlo required.dll
) se coloca en site-packages/package/required.dll
y la biblioteca de extensión C real (llamarlo package.pyd
) se coloca en site-packages/package.pyd
.
Ya que no está en el mismo directorio cuando intento utilizar la biblioteca en Python I get
ImportError: DLL load failed while importing package: The specified module could not be found.
Abajo está mi setup.py
setuptools.setup(
name="package",
version="1.0.0",
packages=setuptools.find_packages(where="src"),
package_dir={"": "src"},
py_modules=[splitext(basename(path))[0] for path in glob("src/*.py")],
use_scm_version=True,
package_data={
"package": [
"_clibs/libs/required.dll",
],
},
ext_modules=[
setuptools.Extension(
"package",
include_dirs=["src/package/_clibs/inc"],
sources=[
"src/package/_clibs/src/api.cpp",
"src/package/_clibs/src/utils.cpp",
],
library_dirs=[
"src/package/_clibs/libs",
],
libraries=["static", "User32"],
language="c++"
),
],
)
El diseño del directorio para el proyecto es el siguiente:
/
setup.py
.tox
src/
...package/
......wrapper.py
......__init__.py
......_clibs/
.........inc/
.........src/
............api.cpp
............utils.cpp
.........libs/
............required.dll
............static.lib
También uso tox
para la gestión del entorno virtual.
Las respuestas propuestas Aquí. y Aquí. esquema un muy similar setup.py
y el mismo método para incluir el DLL package_data
Opción. Las respuestas parecen sugerir que DLL y .pyd
se colocan en el mismo nivel que no sucede para mí. No puedo ubicar lo que me falta para tener el mismo comportamiento.
python 3.8.6
setuptools 51.0.0
pip 20.3.1
TL;DR DLL está siendo colocado en un directorio diferente a .pyd
binario por lo que es invisible para el cargador de Windows
Pregunta hecha hace 3 años, 5 meses, 0 días - Por pixelpioneerx
3 Respuestas:
-
Después de excavar, encontré una manera que funcionó para mí. Este hilo ha arrojado luz sobre los problemas de DLL carga en Windows y los acontecimientos más recientes (Python 3.8) sobre el problema.
La solución con la que fui fue prestada
numpy
. Para empaquetar correctamente los DLLs junto con su extensión C:- Crear un directorio dentro de su paquete que contendrá todos los DLLs requeridos su extensión estará utilizando
- Modifique su procedimiento de construcción para incluir este directorio junto con
sdist
y distribuciones de ruedas - Una vez que el usuario importa su paquete, lo primero que hace es modificar dinámicamente caminos para donde se buscarán los DLLs (dos métodos diferentes dependiendo de si usted está en 3.8 o inferior)
Roughly, adding
package_data
a susetup.py
debe hacer el truco (menos los shenanigans que vienen con archivos MANIFEST y el usopackage_data
, leer más Aquí.)package_data={"your package name": ["path_to_DLLs/*"]},
Para implementar #3, como opción en tu
__init__.py
para el paquete añadir lo siguiente (tomar 99% línea por línea desdenumpy
__config__.py
que se genera automáticamente por su complejo sistema de construcción.import os import sys PATH_TO_DLL = "YOUR DLL DIRECTORY IN YOUR PACKAGE" extra_dll_dir = os.path.join(os.path.dirname(__file__), PATH_TO_DLL) if sys.version_info >= (3, 8): os.add_dll_directory(extra_dll_dir) else: # legacy DLL loading mechanism through PATH env variable manipulations os.environ.setdefault("PATH", "") os.environ["PATH"] += os.pathsep + extra_dll_dir
Cualquier comentario es muy apreciado. El hilo vinculado a este ticket habla de la necesidad de una mejor documentación para la extensión C a bordo y no he podido encontrar ninguna. Hasta ahora, extensiones C + Windows +
setuptools
hecho para una experiencia increíblemente frustrante.Respondida el Dec 17, 2020 a las 03:58 - por algorithmadeptc6cb
Votos positivos: 0 | Votos negativos: 0 -
Para asegurarte de que el archivo DLL requerido se encuentre en el mismo directorio que el archivo
.pyd
al instalar tu paquete a través depip
, puedes realizar los siguientes ajustes en tusetup.py
:- Modifica la sección de `package_data` para incluir el archivo DLL en el mismo directorio que el archivo `.pyd`:
python package_data={ "": ["_clibs/libs/required.dll"], },
- Asegúrate de que el archivo `.pyd` se instale en el directorio correcto también. Puedes hacerlo especificando el atributo `ext_package` para la extensión en el que especificas el nombre de la carpeta principal para tu paquete de extensión:
python ext_modules=[ setuptools.Extension( "package", ... ext_package="package", ... ), ],
Con estos ajustes, al instalar tu paquete a través de
pip install .
, el archivorequired.dll
debería colocarse en el mismo directorio que el archivopackage.pyd
. Esto debería resolver el problema de que el cargador de Windows no pueda encontrar el archivo DLL al cargar la biblioteca desde Python. ¡Espero que esto te ayude a solucionar el error!Respondida el Dec 18, 2020 a las 04:02 - por Gpt
Votos positivos: 0 | Votos negativos: 0 -
El problema es que estás utilizando el valor predeterminado
package_dir
de""
en tusetup.py
. Esto le indica a setuptools que coloque todos los archivos de datos en el directorio raíz del paquete instalado, en lugar del subdirectorio donde se encuentra el módulo que los utiliza.Para resolver este problema, debes especificar el subdirectorio correcto en el que se debe colocar el archivo DLL. Puedes hacer esto modificando tu
package_dir
de la siguiente manera:python package_dir={"package": "src/package"},
Esto le indicará a setuptools que coloque el archivo DLL en el subdirectorio
src/package
del paquete instalado. Una vez que hayas realizado este cambio, vuelve a ejecutarpip install
para instalar el paquete. El archivo DLL ahora debería colocarse en el mismo directorio que el archivo.pyd
y debería poder importar la biblioteca en Python sin errores.Respondida el Dec 18, 2020 a las 04:03 - por Gemini
Votos positivos: 0 | Votos negativos: 0