Компиляция и выполнение Python

kompilyaciya i vypolnenie python Интеграция Python/C

Чтобы создать самостоятельно выполняемую программу из этого файла исходного программного кода C, необходимо скомпоновать результат его компиляции с файлом библиотеки Python. В данной главе под «библиотекой» обычно подразумевается двоичный файл библиотеки, создаваемый при компиляции Python, а не стандартная библиотека Python.

На сегодняшний день все, что касается Python и может потребоваться в C, компилируется в один библиотечный файл при сборке интерпретатора (например, libpython3.1.dll в Cygwin). Функция main программы поступает из программного кода C, а в зависимости от расширений, установленных для Python, может потребоваться компоновка внешних библиотек, к которым обращается библиотека Python.

В предположении, что никаких дополнительных библиотек расширений не требуется, в примере 20.24 представлен минимальный make- файл для Cygwin в Windows, с помощью которого собирается программа на C из примера 20.23. Как всегда, конкретные особенности make- файла зависят от платформы, поэтому ищите дополнительные указания в руководствах по Python. Данный make-файл использует путь подключаемых файлов Python при поиске Py thon.h на этапе компиляции и добавляет файл библиотеки Python на конечном этапе компоновки, чтобы сделать возможными вызовы API в программе на C.

Пример 20.24. PP4E\Integrate\Embed\Basics\makefile.1

#  make-файл для Cygwin, создающий выполняемую программу на C

#  со встроенным Python, в предположении, что не требуется

#  компоновка с библиотеками внешних модулей;

#  использует заголовочные файлы Python, подключает файл библиотеки Python;

#  те и другие могут находиться в других каталогах (например, /usr);

PYLIB = /usr/local/bin

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

embed-simple: embed-simple.o

gcc embed-simple.o -L$(PYLIB) -lpython3.1 -g -o embed-simple

embed-simple.o: embed-simple.c

gcc embed-simple.c -c -g -I$(PYINC)

Чтобы собрать программу с помощью этого файла, запустите утилиту make с этим файлом, как обычно (как и прежде, не забывайте, что отступы в make-файлах должны оформляться с помощью символов табуляции):

/PP4E/Integrate/Embed/Basics$ make -f makefile.1

gcc embed-simple.c -c -g -I/usr/local/include/python3.1

gcc embed-simple.o -L/usr/local/bin -lpython3.1 -g -o embed-simple

На практике все может оказаться не так просто, и понадобится терпение, чтобы добиться результата. В действительности, для сборки всех программ из этого раздела в Cygwin я использовал make-файл из примера 20.25.

Пример 20.25. PP4E\Integrate\Embed\Basics\makefile.basics

# make-файл для сборки сразу всех 5 примеров встраивания в Cygwin

PYLIB = /usr/local/bin

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

BASICS = embed-simple.exe \ embed-string.exe \ embed-object.exe \ embed-dict.exe \ embed-bytecode.exe

all: $(BASICS)

embed%.exe: embed%.o

gcc embed$*.o -L$(PYLIB) -lpython3.1 -g -o $@

embed%.o: embed%.c

gcc embed$*.c -c -g -I$(PYINC)

clean:

rm -f *.o *.pyc $(BASICS) core

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

Одно замечание: если вы будете много заниматься встраиванием и столкнетесь с проблемами внешних зависимостей, на некоторых платформах может потребоваться скомпилировать Python на своей машине из исходных текстов, от клю чив все ненужные расширения в файлах с настройками (подробности смотрите в пакете с исходными текстами Python). В результате будет создана библиотека Python с минимумом внешних зависимостей, компоновать программы с которой значительно легче.

Получив рабочий make-файл, запускайте его для сборки программ C с подключенными библиотеками Python:

/PP4E/Integrate/Embed/Basics$ make -f makefile.basics clean rm -f *.o *.pyc embed-simple.exe embed-string.exe embed-object.exe embed-dict.exe embed-bytecode.exe core

/PP4E/Integrate/Embed/Basics$ make -f makefile.basics

gcc embed-simple.c -c -g -I/usr/local/include/python3.1

gcc embed-simple.o -L/usr/local/bin -lpython3.1 -g -o embed-simple.exe

gcc embed-string.c -c -g -I/usr/local/include/python3.1

gcc embed-string.o -L/usr/local/bin -lpython3.1 -g -o embed-string.exe

gcc embed-object.c -c -g -I/usr/local/include/python3.1

gcc embed-object.o -L/usr/local/bin -lpython3.1 -g -o embed-object.exe

gcc embed-dict.c -c -g -I/usr/local/include/python3.1

gcc embed-dict.o -L/usr/local/bin -lpython3.1 -g -o embed-dict.exe

gcc embed-bytecode.c -c -g -I/usr/local/include/python3.1

gcc embed-bytecode.o -L/usr/local/bin -lpython3.1 -g -o embed-bytecode.exe rm embed-dict.o embed-object.o embed-simple.o embed-bytecode.o embed-string.o

После сборки с любым make-файлом вы можете запустить получившуюся программу на C, как обычно:

/PP4E/Integrate/Embed/Basics$ ./embed-simple embed-simple

The meaning of life

THE MEANING OF PYTHON

Этот вывод производят в основном инструкциями, вызывающими функцию Python print, которые C посылает присоединенной библиотеке Python. Это напоминает использование программистом интерактивной оболочки Python.

Разумеется, строки с программным кодом на языке Python, выполняемые программой на C, вероятно, не стоит жестко определять в программе C, как показано в этом примере. Вместо этого их можно загружать из текстового файла или получать из графического интерфейса, извлекать из файлов HTML или XML, получать из базы данных или через сокеты и так далее. При использовании таких внешних источников строки с программным кодом Python, выполняемые из C, можно произвольно изменять без необходимости перекомпилировать выполняющую их программу на C. Они могут изменяться на сайте или конечными пользователями системы. Чтобы использовать строки программного кода с максимальной пользой, мы должны перейти к более гибким инструментам API.

Практические особенности: В Python 3.1 и Cygwin для Windows мне пришлось сначала включить в переменную окружения PYTHONPATH текущий рабочий каталог, чтобы обеспечить работоспособность примеров встраивания, с помощью команды export PYTHONPATH=.. Кроме того, мне потребовалось использовать команду ./embed-simple для запуска программы, потому что каталог . также изначально отсутствовал в переменной оболочки PATH и он не записывается в нее при установке Cygwin.

В вашем случае ситуация может быть иной, но если вы столкнетесь с проблемами, попробуйте выполнить встроенные команды Python import sys и print sys.path из C, чтобы посмотреть, как в действительности выглядит путь поиска модулей Python, а за дополнительной информацией о настройке пути поиска для встраиваемых приложений обращайтесь к руководству «Python/C API».

Выполнение строк программного кода

с использованием результатов и пространств имен

В примере 20.26 используются следующие вызовы API для выполнения строк программного кода, возвращающих значения выражений в C:

Py_Initialize

Инициализирует присоединенные библиотеки Python, как и раньше.

PyImport_ImportModule

Импортирует модуль Python и возвращает указатель на него.

PyModule_GetDict

Загружает объект словаря атрибутов модуля.

PyRun_String

Выполняет строку программного кода в явно указанных пространствах имен.

PyObject_SetAttrString

Присваивает значение атрибуту объекта, имя которого определяется аргументом namestring.

PyArg_Parse

Преобразует объект возвращаемого значения Python в формат C.

С помощью функции, выполняющей импорт, загружается пространство имен модуля usermod, представленного в примере 20.22, чтобы строки программного кода в нем могли выполняться непосредственно и обращаться к именам, определенным в этом модуле, не квалифицируя их. Функция PyImport_ImportModule напоминает инструкцию Python import, но объект импортированного модуля возвращается в C, а не присваивается переменной Python. Поэтому она скорее похожа на встроенную функцию Python __import__.

Однако фактическим выполнением программного кода здесь занимается функция PyRun_String. Она принимает строку программного кода, флаг режима парсера и указатели на объекты словарей, которые будут играть роль глобального и локального пространств имен при выполнении строки программного кода. Флаг режима может иметь значение Py_eval_input для выполнения выражения или Py_file_input для выполнения инструкции. При выполнении выражения эта функция возвращает результат вычисления выражения (в виде указателя на объект PyObject*). Два аргумента с указателями на словари пространств имен позволяют различать глобальную и локальную области видимости, но обычно они задают один и тот же словарь, благодаря чему программный код выполняется в одном пространстве имен.

Пример 20.26. PP4E\Integrate\Embed\Basics\embed-string.c

/* строки программного кода с результатами и пространствами имен */

#include <Python.h>

main() {

char *cstr;

PyObject *pstr, *pmod, *pdict;

printf("embed-string\n");

Py_Initialize();

/* получить usermod.message */

pmod = PyImport_ImportModule("usermod");

pdict = PyModule_GetDict(pmod);

pstr = PyRun_String("message", Py_eval_input, pdict, pdict);

/* преобразовать в C */

PyArg_Parse(pstr, "s", &cstr); printf("%s\n", cstr);

/* присвоить usermod.X */

PyObject_SetAttrString(pmod, "X", pstr);

/* вывести usermod.transform(X) */

(void) PyRun_String("print(transform(X))", Py_file_input, pdict, pdict); Py_DECREF(pmod);

Py_DECREF(pstr); Py_Finalize();

}

После компиляции и запуска этот файл выводит те же результаты, что и его предшественник:

/PP4E/Integrate/Embed/Basics$ ./embed-string embed-string

The meaning of life

THE MEANING OF PYTHON

Но здесь выполняются совершенно иные действия. На этот раз C загружает, преобразует и выводит значение атрибута message модуля Python путем непосредственного выполнения выражения и присваивает значение глобальной переменной (X) в пространстве имен модуля, которая играет роль входных данных для функции Python print.

Благодаря тому, что функция выполнения строки в этой версии позволяет задавать пространства имен, можно лучше расчленить встроенный программный код, выполняемый системой, — для разных групп можно определять отдельные пространства имен, чтобы избежать изменения переменных в других группах. А так как эта функция возвращает результат, облегчается связь со встроенным программным кодом; результаты выражений являются выходными данными, а присваивания глобальным переменным в пространстве имен, в котором выполняется программный код, позволяют передавать входные данные.

Прежде чем двинуться дальше, я должен остановиться на трех проблемах, возникающих здесь. Во-первых, эта программа также уменьшает счетчики ссылок для объектов, передаваемых ей из Python, с помощью функции Py_DECREF, описанной в руководствах по Python/C API. Строго говоря, вызывать эти функции здесь необязательно (память объектов все равно освобождается при выходе из программ), но они демонстрируют, как интерфейсы встраивания должны управлять счетчиками ссылок, когда Python передает владение ими в C. Если бы, скажем, это была функция, вызываемая из более крупной системы, обычно потребовалось бы уменьшить счетчик, чтобы позволить Python освободить память объектов.

Во-вторых, в настоящей программе следует сразу проверять значения, возвращаемые все ми функциями API, чтобы обнаруживать ошибки (например, неудачу при импорте). В данном примере проверка ошибок была опущена для упрощения программного кода, но ее обязательно следует выполнять, чтобы повысить надежность программ.

И, в-третьих, имеется родственная функция, позволяющая выполнять сразу весь файл с программным кодом, но она не демонстрируется в этой главе: PyRun_File. Поскольку всегда имеется возможность загрузить текст из файла и выполнить его как единственную строку с помощью PyRun_String, основное преимущество функции PyRun_File сводится к отсутствию необходимости выделять память для содержимого файла. В таких строках, содержащих многострочный текст, для разделения строк как обычно используется символ \n, а блоки программного кода выделяются отступами.

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

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

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