Мой проект предоставляет статическую библиотеку (назовем ее static.lib
) интерпретатору CPython (3.8). Он состоит из статической библиотеки, которая, в свою очередь, зависит от драйвера DLL FTDI. После прочтения этой темы кажется, что оптимальным решением для предоставления сторонних DLL является объединение их вместе с пакетом Python, чтобы убедиться, что DLL находится в том же каталоге, что и двоичный файл .pyd
.
Проблема, с которой я сталкиваюсь, заключается в том, что после запуска pip install .
для моего пакета требуемая DLL (назовем ее required.dll
) помещается в site-packages/package/required.dll
, а фактическая библиотека расширений C (назовем ее package.pyd
) помещается в site-packages/package.pyd
.
Поскольку он находится не в том же каталоге, когда я пытаюсь использовать библиотеку в Python, я получаю
ImportError: DLL load failed while importing package: The specified module could not be found.
Ниже мой 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++"
),
],
)
Структура каталога для проекта выглядит следующим образом:
/
setup.py
.tox
src/
...package/
......wrapper.py
......__init__.py
......_clibs/
.........inc/
.........src/
............api.cpp
............utils.cpp
.........libs/
............required.dll
............static.lib
Я также использую tox
для управления виртуальной средой.
Предлагаемые ответы здесь и здесь описывают очень похожий setup.py
и тот же метод включения DLL - через package_data
вариант. Ответы, кажется, предполагают, что DLL и .pyd
затем помещаются на один уровень, чего не происходит со мной. Я не могу понять, чего мне не хватает, чтобы получить такое же поведение.
python 3.8.6
setuptools 51.0.0
pip 20.3.1
TL;DR DLL помещается в каталог, отличный от бинарного .pyd
, что делает его невидимым для загрузчика Windows.
Также по теме: stackoverflow.com/q/62662816/5769463
Это отличные ответы, однако я все еще сталкиваюсь с проблемами, описанными в моем исходном посте. Пробовал размещать required.dll
в разных каталогах - результат тот же. Я отредактирую ответ, чтобы также включить макет каталога моего пакета.
Откуда PIP знает, как собрать library.pyd? Я не вижу ссылки на него в setup.py.
@CristiFati library.pyd
является продуктом setup.py
, замените library.pyd
любым именем, которое в конечном итоге будет присвоено двоичному файлу. Чтобы соответствовать сценарию, который я предоставил, это должно быть package.pyd
или его вариант. Извиняюсь за путаницу, я пытался скрыть настоящие имена библиотек, не относящиеся к этому вопросу, это просто несоответствие.
Немного покопавшись, я нашел способ, который сработал для меня. Эта тема пролила свет на проблемы с загрузкой DLL в Windows и самые последние (Python 3.8) разработки по этому вопросу.
Решение, которое я выбрал, было позаимствовано у numpy
.
Чтобы правильно связать библиотеки DLL с вашим расширением C:
sdist
и дистрибутивами колес.Грубо говоря, добавление package_data
к вашему setup.py
должно помочь (минус махинации с файлами МАНИФЕСТА и использование package_data
, подробнее читайте здесь)
package_data = {"your package name": ["path_to_DLLs/*"]},
Чтобы реализовать № 3, в качестве опции в вашем __init__.py
для пакета добавьте следующее (взято на 99% построчно из numpy
__config__.py
, которое автоматически генерируется их очень сложной системой сборки.
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
Любая обратная связь очень ценится. Тема, связанная с этим тикетом, говорит о необходимости лучшей документации для подключения расширений C, и я не смог ее найти. До сих пор расширения C + Windows + setuptools
вызывали невероятное разочарование.
Отвечает ли это на ваш вопрос? Включение и распространение сторонних библиотек с расширением Python C