Простой пример SWIG

prostoj primer swig Интеграция Python/C

Чтобы не писать программный код на C вручную, как в предыдущем разделе, а воспользоваться инструментом SWIG, достаточно написать функцию на языке C, которую нужно использовать из Python, без всякой логики интеграции с Python, как если бы функцию требовалось вызывать только из C. В примере 20.4 демонстрируется переделанная версия функции из примера 20.1.

Пример 20.4. PP4E\Integrate\Extend\HelloLib\hellolib.c

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

*  простой файл библиотеки на C с единственной функцией "message",

*  которая предназначена для использования в программах Python.

*  Здесь нет ничего, что говорило бы о Python, — эта функция на языке C

*  может вызываться из программ на C, а также из Python

*  (с помощью связующего программного кода).

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

#include <string.h>

#include <hellolib.h>

static char result[1024]; /* не экспортируется */

char * message(char *label) /* экспортируется */

{

strcpy(result, "Hello, "); /* создать строку C */ strcat(result, label); /* добавить label */ return result; /* вернуть результат */

}

Теперь определим обычный заголовочный файл C и объявим эту функцию внешней, как показано в примере 20.5. Это можно счесть излишеством для такого маленького примера, но это подчеркивает суть.

Пример 20.5. PP4E\Integrate\Extend\HelloLib\hellolib.h

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

*   Определяет имена, экспортируемые файлом hellolib.c в пространство имен C,

*   а не программ Python — экспортируемые имена для последних определяются

*   в таблице регистрации методов в программном коде модуля расширения

*   Python, а не в этом файле .h;

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

extern char *message(char *label);

Теперь вместо всего связующего программного кода расширения Python, показанного в предыдущем разделе, напишем входной файл объявлений типов SWIG, как в примере 20.6.

Пример 20.6. PP4E\Integrate\Extend\Swig\hellolib.i

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

*   Файл описания модуля Swig для файла библиотеки на C.

*   Создание расширения выполняется командой "swigpython hellolib.i".

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

%module hellowrap

%{

#include <hellolib.h>

%}

extern char *message(char*); /* или: %include "../HelloLib/hellolib.h" */

/* или: %include hellolib.h, и испол. флаг -I arg */

Этот файл описывает сигнатуру функции C. Вообще говоря, SWIG сканирует файлы, содержащие объявления ANSI C и C++. Его входной файл может иметь вид описания интерфейса (обычно с расширением .i) или быть заголовочным файлом или файлом с исходным программным кодом C/C++. Формат файлов интерфейсов, подобных этому, чаще всего используется для ввода — они могут содержать комментарии в формате C или C++, объявления типов, как в стандартных заголовочных файлах, и директивы SWIG, начинающиеся с %. Например:

%module

Определяет имя модуля, которое будет использоваться при импорте в Python.

%{…%}

Содержит программный код, добавляемый в создаваемый файл оболочки дословно.

extern

Объявляет экспортируемые имена в обычном синтаксисе ANSI C/ C++.

%include

Заставляет SWIG сканировать другой файл (флаги -I определяют пути поиска).

В этом примере можно было заставить SWIG прочесть файл заголовков hellolib.h, представленный в примере 20.5, непосредственно. Но одним из преимуществ специальных входных файлов SWIG, таких как hello- lib.i, является то, что с их помощью можно отобрать функции, которые будут заключены в оболочку и экспортированы в Python, и это дает более полный контроль над процессом генерации.

SWIG — это вспомогательная программа, которая запускается из сценариев компиляции, а не язык программирования, поэтому здесь особенно нечего больше показывать. Просто добавьте в свой make-файл запуск SWIG и скомпилируйте его вывод для компоновки с Python. В примере 20.7 демонстрируется способ осуществления этого в Cygwin.

Пример 20.7. PP4E\Integrate\Extend\Swig\makefile.hellolib-swig

##########################################################################

#   Использование SWIG для интеграции hellolib.c с программами Python

#   в Cygwin. В текущей версии SWIG (>1.3.13) библиотека DLL должна иметь

#   ведущий "_" в имени, потому что также создается файл .py без "_" в имени.

##########################################################################

PYLIB = /usr/local/bin

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

CLIB = ../HelloLib

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

#   библиотека плюс ее обертка

_hellowrap.dll: hellolib_wrap.o $(CLIB)/hellolib.o

gcc -shared hellolib_wrap.o $(CLIB)/hellolib.o \

-L$(PYLIB) -lpython3.1 -o $@

#   генерирует модуль-обертку

hellolib_wrap.o: hellolib_wrap.c $(CLIB)/hellolib.h

gcc hellolib_wrap.c -g -I$(CLIB) -I$(PYINC) -c -o $@

hellolib_wrap.c: hellolib.i

$(SWIG) -python -I$(CLIB) hellolib.i

#   программный код библиотеки C (в другом каталоге)

$(CLIB)/hellolib.o: $(CLIB)/hellolib.c $(CLIB)/hellolib.h

gcc $(CLIB)/hellolib.c -g -I$(CLIB) -c -o $(CLIB)/hellolib.o

clean

rm -f *.dll *.o *.pyc core

force:

rm -f *.dll *.o *.pyc core hellolib_wrap.c hellowrap.py

При запуске входного файла hellolob.i в этом make-файле SWIG создаст два файла:

hellolib_wrap.c

Связующий программный код модуля расширения на C.

hellolibwrap.py

Модуль Python, импортирующий сгенерированный модуль расширения на C.

Первый получает имя по имени входного файла, а второй — из директивы %module. В действительности, в настоящее время SWIG генерирует два модуля: для достижения интеграции он использует комбинацию программного кода на языках Python и C code. В конечном итоге сценарии импортируют сгенерированный файл модуля на языке Python, который импортирует сгенерированный и скомпилированный модуль на C. Если вы готовы пробиваться до конца, то сгенерированный программный код можно найти в пакете с примерами для книги; следует учесть, что он может измениться со временем и является слишком обобщенным, чтобы быть простым.

Для создания модуля C этот make-файл просто запускает SWIG, чтобы получить связующий программный код, компилирует полученный результат, компилирует оригинальный программный код библиотеки на C и затем объединяет результаты с компилированной оберткой, создавая _hellowrap.dll, библиотеки DLL, которую будет загружать hellowrap.py при импортировании в сценариях Python:

/PP4E/Integrate/Extend/Swig$ dir hellolib.i makefile.hellolib-swig

/PP4E/Integrate/Extend/Swig$ make -f makefile.hellolib-swig /cygdrive/c/temp/swigwin-2.0.0/swig -python -I../HelloLib hellolib.i gcc hellolib_wrap.c -g -I../HelloLib -I/usr/local/include/python3.1

-c -o hellolib_wrap.o

gcc ../HelloLib/hellolib.c -g -I../HelloLib -c -o ../HelloLib/hellolib.o gcc -shared hellolib_wrap.o ../HelloLib/hellolib.o \

-L/usr/local/bin -lpython3.1 -o _hellowrap.dll

/PP4E/Integrate/Extend/Swig$ dir

_hellowrap.dll hellolib_wrap.c hellowrap.py

hellolib.i hellolib_wrap.o makefile.hellolib-swig

В результате получается файл динамически загружаемого модуля расширения на C, готовый к импортированию программным кодом на языке Python. Подобно всем модулям файл _hellowrap.dll, вместе с hello wrap.py, должен быть помещен в каталог, находящийся в пути поиска модулей Python (их можно оставить в каталоге, где выполнялась компиляция, если импортирующий сценарий запускается из того же каталога). Обратите внимание, что имя файла библиотеки .dll должно начинаться с символа подчеркивания. Это является обязательным требованием SWIG, потому что этот инструмент дополнительно создает файл .py с тем же именем без подчеркивания — если имена будут совпадать, то импортироваться сможет только какой-то один модуль, а нам необходимы оба (сценарии должны импортировать модуль .py, который в свою очередь импортирует библиотеку .dll).

Как обычно в программировании на языке C, вам, возможно, придется повозиться с make-файлом, чтобы заставить его работать в вашей системе. Однако как только вам удастся запустить make-файл, работу можно считать законченной. Сгенерированный модуль на C используется точно так же, как созданная вручную версия, показанная выше, за исключением того, что SWIG позаботился об автоматизации наиболее сложных этапов. Передача вызовов функций из Python в программный код на C, представленный в примере 20.4, и возврат результатов осуществляется через сгенерированный инструментом SWIG слой — благодаря SWIG все это «просто работает»:

/PP4E/Integrate/Extend/Swig$ python

>  >> import hellowrap # импортировать связующий слой + файл библиотеки

>  >> hellowrap.message(‘swig world’) # при импорте всегда

Hello, swig world # первым просматривается cwd

>  >> hellowrap.__file__

‘hellowrap.py’

>  >> dir(hellowrap)

[‘__builtins__’, ‘__doc__’, ‘__file__’, ‘__name__’, ‘_hellowrap’, ‘message’]

>  >> hellowrap._hellowrap

<module ‘_hellowrap’ from ‘_hellowrap.dll’>

Иными словами, научившись пользоваться SWIG, можно в целом забыть детали интеграции, о которых рассказывалось в этой главе. На самом деле SWIG настолько сведущ в генерации связующего программного кода Python, что обычно значительно проще и менее чревато ошибками писать расширения на C для Python сначала как чистые библиотеки C или C++, а затем добавлять их в Python, пропуская файлы заголовков через SWIG, как продемонстрировано здесь.

Мы лишь слегка коснулись возможностей SWIG. Гораздо больше информации об этом инструменте можно почерпнуть из его руководства по Python, доступного на сайте http://www.swig.org. Несмотря на простоту примеров в этой главе, SWIG обладает достаточно широкими возможностями интеграции библиотек, таких же сложных, как расширения Windows и широко используемые графические библиотеки, например OpenGL. Мы еще вернемся к этому инструменту далее в этой главе и исследуем его модель «теневых классов», предназначенную для обертывания классов C++. А теперь перейдем к изучению примера более полезного расширения.

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

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

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