Обертывание функций окружения C с помощью SWIG

obertyvanie funkcij okruzheniya c s pomoshhju swig Интеграция Python/C

Модули расширения можно писать вручную, как мы это только что сделали, но это совершенно необязательно. Поскольку этот пример в действительности просто создает обертки для имеющихся функций в стандартных библиотеках C, весь файл cenviron.c с программным кодом C, представленным в примере 20.8, можно заменить простым входным файлом SWIG, который выглядит, как показано в примере 20.12:

Пример 20.12. PP4E\Integrate\Extend\Swig\Environ\environ.i

/**************************************************************************

* Файл Swig описания модуля, чтобы сгенерировать весь программный код обертки * Python для функций getenv/putenv из библиотеки C: "swig -python environ.i". **************************************************************************/

%module environ

extern char * getenv(const char *varname);

extern int putenv(char *assignment);

И все готово. Ну, почти — все же нужно еще пропустить этот файл через SWIG и скомпилировать полученный вывод. Как и прежде, просто добавьте в свой make-файл строки для вызова SWIG, скомпилируйте результат в разделяемый объект для динамического связывания и все будет готово. В примере 20.13 представлен make-файл для Cygwin, который решает эту задачу.

Пример 20.13. PP4E\Integrate\Extend\Swig\Environ\makefile.environ-swig

# компилирует расширение environ из программного кода, сгенерированного SWIG

PYLIB = /usr/local/bin

PYINC = /usr/local/include/python3.1

SWIG = /cygdrive/c/temp/swigwin-2.0.0/swig

_environ.dll: environ_wrap.c

gcc environ_wrap.c -g -I$(PYINC) -L$(PYLIB) -lpython3.1 -shared -o $@

environ_wrap.c: environ.i

$(SWIG) -python environ.i

clean: rm -f *.o *.dll *.pyc core environ_wrap.c environ.py

При запуске с файлом environ.i утилита SWIG создаст два файла и два модуля — environ.py (интерфейсный модуль Python) и environ_wrap.c (файл модуля со связующим программным кодом, который будет скомпилирован в файл _environ.dll и будет импортироваться файлом .py). Так как функции, для которых здесь создаются обертки, находятся в стандартных присоединяемых библиотеках C, объединять с генерируемым программным кодом нечего — этот make-файл просто запускает SWIG и компилирует файл обертки в модуль расширения C, готовый к импортированию:

/PP4E/Integrate/Extend/Swig/Environ$ make -f makefile.environ-swig /cygdrive/c/temp/swigwin-2.0.0/swig -python environ.i

gcc environ_wrap.c -g -I/usr/local/include/python3.1 -L/usr/local/bin -lpython3.1

sharedo _environ.dll

И вот теперь действительно все. Полученный модуль расширения на C связывается при импортировании и используется как прежде (за исключением того, что все сложности были решены с помощью SWIG):

/PP4E/Integrate/Extend/Swig/Environ$ ls

_environ.dll environ.i environ.py environ_wrap.c makefile.environ-swig

/PP4E/Integrate/Extend/Swig/Environ$ python

>>> import environ

>>> environ.getenv(‘USER’)

‘gilligan’

>>> environ.__name__, environ.__file__, environ

(‘environ’, ‘environ.py’, <module ‘environ’ from ‘environ.py’>)

>>> dir(environ)

[ … ‘_environ’, ‘getenv’, ‘putenv’ … ]

Если внимательно рассмотреть последний листинг сеанса, можно заметить, что на этот раз я не вызывал функцию putenv. Как оказывается, тому есть веская причина: функция putenv в библиотеке C ожидает получить строку вида «USER=Gilligan», которая станет частью окружения. Для программного кода C это означает, что мы должны выделить новый блок памяти для передачи функции — для удовлетворения этого требования в примере 20.8 мы использовали функцию malloc. Однако нет простого и непосредственного способа обеспечить выделение памяти на стороне Python. В предыдущей версии Python было достаточно сохранить строку, передаваемую функции putenv, во временной переменной Python, но в Python 3.X и/или SWIG 2.0 этот прием больше не работает. Для исправления ситуации можно либо написать собственную функцию на C, либо использовать средства SWIG отображения типов, которые позволяют настраивать обработку передачи данных. В интересах экономии места мы оставим решение этой проблемы в качестве самостоятельного упражнения — подробности смотрите в документации SWIG.

Использованная литература:

Марк Лутц — Программирование на Python, 4-е издание, II том, 2011

Каталог сайтов Всего.ру
Оцените статью
Секреты программирования
Добавить комментарий