- PVSM.RU - https://www.pvsm.ru -
Эта статья – описание моих экспериментов по сборке модулей для Python. Мне понадобился высокоуровневый интерфейс к библиотеке LibRaw [1], притом в первую очередь под Windows.
Последний раз модуль для питона на C++ я писал в 2004 году, модуль был к мертворожденной (к счастью не мной) библиотеке ( я тупо продавал свои умения за зарплату). Естественно, навыки не закрепились. Помню, что SWIG [2] сильно облегчил мне работу, поскольку нужен был объектный интерфейс, а «ручками» его писать ломало. Память у меня профессиональная – то есть избирательная и короткая, поэтому пришлось прыгать сначала.
Это статья только про настройку SWIG [3] для Python под Windows. Писать же модули с использованием SWIG гораздо проще [2], чем всё настроить (кстати, у меня такое впечатление, что это парадигма современного программирования).
Первым делом я полез в яндексогугл. Epic fail — все советы и воркарраунды устарели года на три. В итоге, следуя им, мне, например, пришлось совершать абсолютно ненужные шаги по сборке питона из исходников. Лишних шагов в статье нет, хотя питон собирается на раз. Но если будете собирать, то полезный совет: возьмите из «коробочной» поставки файл Include/pycohfig.h и тихо положите его в собранную версию — пригодится.
Хорошие новости. Для сборки модулей можно использовать Microsoft Visual C++ Express Edition 2008 [4], поскольку Питон с 2.6 собирается им. До этого приходилось либо компилировать питон из исходников, либо откапывать покрытый мхом VC++ 7.0, а я то и 6.0. Ещё более хорошие новости — модули можно компилировать MinGW [5]. Кстати? тестовый модуль я откомпилировал gcc «включенным» в Strawberry Perl (довольно цинично если вспомнить древние питоно-перловые войны). Просто потому что это первый gcc в Path.
Итак, нам нужно взять пример из SWIG и превратить его в модуль. Для этого есть два способа.
Но сперва нужно установить собранный по Windows SWIG [6] (swigwin-2.0.4) и желательно прописать его в PATH. Примеры поставляются с ним же.
Нам понадобиться установить переменные среды окружения.
PYTHON_INCLUDE = С:PythonInclude PYTHON_LIB = C:PythonLibspython27.lib
Дальше можно схалтурить — взять один из готовых примеров, для которых уже созданы солюшен (.sln) и проект. И спокойно, на его базе, сделать свой модуль. Например, открыть SWIGExamplespythonclass. Переименовать examples.i, examples.cxx и examples_wrap.cxx, соответственно, в mymodule.i, mymodule.cxx и mymodule_wrap.cxx.
Как показал только что поставленный опыт всё прекрасно работает.
Для более въедливых товарищей печенька инструкция на английском [7]. Как всегда, малость устаревшая (или, возможно, слишком новая). Пользуясь ею дословно, мне не удалось добиться профита. Поэтому ниже инструкция на руском, сокращённая и проверенная. Итак:
my_module.cxx (или .c) для наших классов/функций, my_module.i для описания интерфейса. И прописываем, но не создаем my_module_wrap.cxx. Первые два файла, я, естественнно, подрезал из тех же примеров, но можно взять их например с википедии [2])
my_module.i, в свойствах (Custom build setup) устанавливаем:swig.exe -c++ -python $(InputPath) $(InputName)_wrap.cxx -c++ в первом случае. И расширение .cxx (достаточно .c) во втором. Этим мы создадим файл my_module_wrap.c(xx) из интерфейсного файла my_module.i
$(PYTHON_INCLUDE) (Зря его что-ли задавали?)
"$(PYTHON_LIB)"$(ProjectDir)_$(ProjectName).pydЧто не может не радовать питон уже заточен под то, чтобы собирать модули использую distutils [8] (в предыдущих версиях требовалось 3 килограмма шаманства [9] ). При этом мы можем использовать как и вышеупомянутый (не к ночи) MVC 2008, так и свободный MinGW.
О маленьких граблях поджидающих нас на этом пути, я, почёсывая лоб, сейчас расскажу.
Опять же, бесчеловечные эксперименты будем ставить на примере из SWIG. Итак, в директории SWIG/examples/classes создаём файл setup.py
# -*- coding: utf-8 -*-
import distutils
from distutils.core import setup, Extension
setup(name = "Simple example from the SWIG website",
version = "0.007",
ext_modules = [Extension(
"_example", # грабель первый: не забываем _
["example.i","example.cxx"],
swig_opts=['-threads', '-c++'], # грабель второй: опции swig тут
)]
);
Подчеркивание. Если указать без него получим ошибку LINK : error LNK2001: unresolved external symbol initexample.
Откуда она растёт?
Python при создании модуля «ручками» ожидает, что в скомпилированном модуле (бинарной части) будет функция с имением init<имя_модуля>. Чтобы модуль, написанный на C/C++ мог вкурить её при загрузке бинарного модуля (и сообщить питону, что всё ок). Враппер (SWIG) её честно создаёт.
SWIG же создаёт в конечном итоге два(!) файла для нашего модуля: <имя_модуля>.py — питоновская обертка, содержащая нативные вызовы функций будущего модуля и _<имя_модуля>.pyd (обратите внимание на подчеркивание) — бинарная библиотека. Дело в том, что бинарную библиотеку можно загрузить «в питон» той же самой инструкцией import, что и нативную. Соотсветсвенно, имена нативной обертки и бинарной библиотеки должны различаться. Они и различаются — на подчеркивание.
SWIG ожидает от нас, что бинарная библиотека будет с подчеркиванием, поэтому создал функцию с именем init_<имя_модуля>, про кторую линкер ничего не знает. Вот и ошибка.
Мне потребовалось некотрое время лазания по исходникам, чтобы понять как передвавть опции командной строки в вызов командной строки swig. По умолчанию distutil ожидает, что мы работаем с C. Поэтому потребовалось указать параметр -c++ (параметр -threads добавлен «для понтов», но может кому окажется не бесполезным).
Теперь, когда мы разобрались, собрать модуль можно двумя способами:
Собрать, использую MVC:
python setup.py build
Собрать, используя MinGW:
python setup.py build -cmingw32
Оба способа протестированы и работают. Даже странно.
Любые советы (как можно было сделать проще) приветствуются. Критика тоже (но желательно с указанием как именно надо было сделать). Надеюсь мне не придётся ещё раз перписывать статью более чем наполовину, что произошло после первого же комментария. После которого я копнул чуть глубже, чем было до того.
Статья об питоновском интерфейсе к LibRaw и собственно он сам в исходниках воспоследуют, как только интерфейс напишется. Понятно, что установить его можно будет без вышеуказанных колдунств.
Автор: mclander
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/python/3477
Ссылки в тексте:
[1] LibRaw: http://www.libraw.org/
[2] SWIG: http://ru.wikipedia.org/wiki/SWIG
[3] SWIG: http://www.swig.org/
[4] Microsoft Visual C++ Express Edition 2008: http://www.microsoft.com/visualstudio/en-us/products/2008-editions/express
[5] MinGW: http://ru.wikipedia.org/wiki/MinGW
[6] SWIG : http://www.swig.org/download.html
[7] инструкция на английском: http://www.swig.org/Doc1.3/Python.html#Python_nn12
[8] distutils: http://docs.python.org/release/3.2/library/distutils.html#module-distutils
[9] 3 килограмма шаманства: http://www.sebsauvage.net/python/mingw.html
Нажмите здесь для печати.