Целью использования кросс-инструментов является создание на инструментальной машине файла с двоичным образом (firmware) начального содержимого памяти (как машинные команды, так и данные) для целевой аппаратной системы. Такой файл затем используется для загрузки в конкретные целевые устройства.
В качестве языков программирования встраиваемых систем выступают обычно C (а также его расширенные подмножества типа Embedded C) и ассемблер. Ассемблер используется как в виде вставок в код на языке С, так и в виде отдельных ассемблерных модулей. В случае встраиваемых систем программирование на ассемблере остается важной составляющей создания программ ввиду, как правило, жестких требований к высокой производительности и малому объему программного кода.
На рис представлена типовая схема разработки программ с помощью кросс-инструментария.
Обычно процесс взаимодействия программиста с кросс-инструментами происходит через визуальную интегрированную среду разработки (IDE) со встроенным редактором, механизмами поддержки проектов, различными средствами управления и анализа результатов работы отдельных инструментов.
ТОП ПРОГРАММ с открытым кодом, о которых ты не знал
Рис. 3.2.
Реальные программы обычно состоят из нескольких модулей, каждому из которых соответствует файл с исходными текстами программ (на языках высокого уровня или ассемблера). Компилятор транслирует модули на языке высокого уровня в промежуточные ассемблерные модули.
Ассемблер отвечает за преобразование ассемблерных модулей (как написанных вручную, так и сгенерированных компилятором) в объектные модули с машинными кодами и данными для целевой аппаратуры. В качестве формата объектных модулей обычно используется ELF, включающий в себя различные секции (например, секции исполняемого кода, секции данных, секции с информацией о символах и секции с отладочной информацией).
Компоновщик выполняет сборку нескольких объектных модулей в один абсолютный модуль с объединением соответствующих секций входных объектных файлов. При этом выполняются перемещения символов по абсолютным адресам памяти (автоматически или в соответствии с заданной программистом картой памяти) с соответствующими исправлениями зависящих от них кодов команд и значений данных. На этом заканчивается этап сборки программы. Полученный абсолютный модуль можно преобразовать в образ памяти для непосредственной загрузки в целевую аппаратуру с помощью программатора.
Для программиста взаимодействие с исполняемой моделью аппаратуры осуществляется через отладчик, который позволяет просматривать состояние модели (содержимое памяти, регистров, шин, сигналов) и осуществлять управляемое (в том числе, пошаговое) выполнение целевой программы на уровне отдельных команд или строчек исходного кода. Совместно с отладчиком используются различные виды профилировщиков и средств анализа, визуализирующих необходимые характеристики модели (как статические, так и времени исполнения) и соответствующие статистики. В качестве примеров можно привести:
Лучшая IDE для Python!
- подсчет числа тактов и количества раз исполнения для каждой строчки программы (на уровне исходных кодов языка программирования высокого уровня, на уровне ассемблерных текстов и на уровне дисассемблированных команд процессора);
- визуализация графа вызовов функций и статистика затраченных для каждого узла тактов и количества раз исполнения;
- список функций программы, их размеров в программном коде и отражение количества вызовов и суммарных затрат (тактов) на их выполнение (с учетом и без учета вызова потомков);
- статистика доступа к различным областям памяти;
- статистика используемого объема памяти;
- различные статистики на уровне операционной системы (в терминах задач и примитивов синхронизации, зарегистрированных в системе).
В качестве модели целевой системы для кросс-отладчика чаще всего выступает симулятор, позволяющий моделировать целевую аппаратуру полностью на инструментальной машине. Существуют симуляторы различного уровня абстракции от функционального симулятора на уровне всей системы до симуляторов на уровне системы команд (в том числе потактово-точных) и симуляторов, эмулирующих точную структуру аппаратуры на уровне функциональных блоков и конкретных вентилей. В качестве симулятора в составе инструментария кросс-разработки обычно используется симулятор уровня системы команд (в том числе, с учетом конвейерных эффектов с потактовой точностью). Также отладчик может поддерживать отладку непосредственно аппаратной модели в виде реального чипа, подключаемой к инструментальной машине, что может иметь место на финальных стадиях проектирования и на стадии эксплуатации. Использование настоящей аппаратуры позволяет запускать программы в режиме реального времени, однако программный симулятор предоставляет гораздо больше воз можностей для отладки и анализа программ.
3.3. Разработка приложений для встроенных систем
Разработка приложений для встроенных систем — частный случай так называемой кросс-разработки. В случае кросс-разработки платформа, для которой пишется приложение ( целевая платформа , например, Linux ARM в виде смартфона) отличается от платформы, на которой работает программист и создается исполняемый код для целевой платформы (платформа разработчика, например, Linux x86 в виде обычного PC ). В случае ОС Android аппаратная часть платформы может быть одинакова — x86 , но способ разработки все равно останется кроссплатформенный. Мы рассмотрим четыре составляющих кроссплатформенной разработки — создание исполняемого кода, его запуск , отладка и интегрированные среды разработчика.
Наиболее важной частью кроссплатформенной разработки является набор инструментов для создания исполняемого кода. В него входит компилятор , компоновщик, другие утилиты, набор библиотек для целевой платформы — этого достаточно, чтобы создать исполняемый файл для целевой платформы. Обычно этот набор инструментов является частью или близким родственником GNU Compiler Collection , то есть применяются те же названия, те же ключи командной строки, те же приемы использования. Ниже приведен пример набора инструментов для архитектуры ARM :
Для управления процессом сборки, документирования и т.п. можно использовать те же средства, что и для обычной разработки под Linux.
Запуск объектного кода может быть осуществлен разными способами. Самый естественный — запуск непосредственно на целевом устройстве. Для этого требуется само целевое устройство, подключенное к компьютеру разработчика по USB или Ethernet . Это наиболее надежный способ, но не всегда самый удобный. Финальное тестирование необходимо производить именно на целевом устройстве.
Альтернатива — установить целевую операционную систему на универсальную виртуальную машину на платформе разработчика. В качестве такой машины для Android рекомендуется Android Virtual Device , Virtual Box , также можно использовать VMWare. При этом надо учитывать, что по некоторым параметрам виртуальная машина может отличаться от реального устройства — например, по скорости работы, особенностям периферии и т. п.
Промежуточным вариантом является использование эмулятора, предоставляемого производителем целевой платформы. Фактически это разновидность виртуальной машины, которая, с одной стороны, максимально адаптирована для эмуляции целевой платформы, а с другой стороны, интегрирована со средствами разработки, например, IDE , которые также предоставляются производителем. Примером этого может послужить Intel® HAXM.
В настоящее время для запуска обычно не ограничиваются переносом на целевую платформу одного исполняемого файла, а формируют целый пакет со всеми зависимостями и правилами установки (например, APK для Android или RPM для MeeGo), который затем устанавливается на целевой платформе. С помощью такого же пакета финальная версия приложения попадает на устройства конечных пользователей. Это, с одной стороны, увеличивает переносимость приложения и облегчает запуск сложных приложений, с другой — слегка усложняет и удлиняет процедуру запуска.
При кроссплатформенной разработке процедура отладки приложения изменяется не сильно. Описанный выше gdb можно использовать и для кросс-отладки. Для этого на целевой платформе отлаживаемое приложение запускается из-под gdbserver:
gdbserver host:port exe [args …]
На платформе разработчика запускается gdb и в его консоли устанавливается связь с gdbserver:
target remote host:port
gdb устанавливает соединение с gdbserver согласно указанным host:port и после этого программист может проводить сеанс отладки как в обычном gdb. При использовании интегрированной среды разработки все эти детали взаимодействия gdb скрыты от программиста — зачастую, глядя на экран платформы разработчика, невозможно определить, происходит отладка локально или на целевой платформе.
Еще одним популярным способом отладки при кроссплат-форменной разработке является полный отказ от gdb и интенсивное использование логов.
Современные IDE , такие как QtCreator или Eclipse, поддерживают кросс-платформенную разработку. Эта поддержка может быть встроенной или реализовываться в виде плагинов. В любом случае IDE берут на себя львиную долю организационной работы, освобождая программисту время для творчества. Внешне процесс кросс-разработки с использованием IDE практически не отличается от обычного.
Источник: intuit.ru
Используем Python в своей программе
При разработке прикладных программ иногда возникает необходимость предоставить пользователю какую-то достаточно гибкую, но простую систему для управления программой.
Есть множество вариантов реализации таких систем, но одним из наиболее простых является встраивание в приложение интерпретатора скриптовых языков.
Реализацией этого варианта мы сегодня и займемся. В качестве скриптового языка был выбран Python из-за достаточно большого спектра применения.
Он кроссплатформенный, существуют официальные версии для Windows, Linux и MacOS. В конце концов, о мощи и потенциале этого языка может говорить хотя бы тот факт, что он используется в небезызвестной корпорации Google как основной язык программирования.
На старт
Качаем с www.python.org последний релиз интерпретатора языка и устанавливаем его куда-нибудь. Проверяем наличие следующих файлов:
Теперь ее обсудим.
Первым делом подключается Python.h для получения доступа к Python API.
Перед работой с интерпретатором необходимо обязательно вызывать Py_Initialize, после ее окончания Py_Finalize. Один из способов вызвать на выполнение нужный скрипт – это функция PyRun_SimpleString.
Она принимает в качестве параметра строку со скриптом и выполняет. В приведенном примере функция выведет на экран текущее время. Однако в большинстве случаев этого недостаточно.
Получение результата выполнения функции
Предположим, что нам нужна программа для построения графиков мат. функций. Если это простая функция вроде у = x + 1 ― cos(x), то проблем с вводом не возникнет, достаточно написать простой парсер выражений на основе обратной польской записи. Но функций могут быть и более сложные, например:
- Передаем параметр функции, написанной на Python-е
- Выполняем её
- Получаем результат
def func(x):
if x > 3:
return x + 1
elif 1 < x return 0
else:
return x ** x
Функция, вызывающая скрипт с функцией y(x) из модуля:
double compute(double x)
PyObject *pName, *pModule, *pFunc;
PyObject *pArgs, *pValue;
double result = 0.0;
Py_Initialize();
pName = PyUnicode_FromString(«mod»);
pModule = PyImport_Import(pName);
Py_DECREF(pName);
if (pModule != NULL)
pFunc = PyObject_GetAttrString(pModule, «func»);
if (pFunc PyCallable_Check(pFunc))
pArgs = PyTuple_New(1);
PyTuple_SetItem(pArgs, 0, PyFloat_FromDouble(x));
pValue = PyObject_CallObject(pFunc, pArgs);
Py_DECREF(pArgs);
if (pValue != NULL)
result = PyFloat_AsDouble(pValue);
Py_DECREF(pValue);
>
>
Py_XDECREF(pFunc);
Py_DECREF(pModule);
>
Py_Finalize();
return result;
>
Обсудим использованные функции, не особо вдаваясь в подробности, т. к. цель данной статьи состоит в рассказе об основных моментах встраивания Python’а в приложения. Для получения более подробных сведений можно почитать документацию на официальном сайте.
Функции вида Py*_From* позволяют преобразовывать встроенные типы С/C++ во внутренние типы Python’а. Т. е., например, PyUnicode_FromString преобразует свой строковый параметр во внутреннее юникодовое представление Python’а для того, чтобы интерпретатор языка смог потом с ним (с параметром) работать. Функции вида Py*_As* имеют обратное действие (т.е. преобразовывают типы из внутреннего представления интерпретатора во встроенные типы C/C++).
PyImport_Import позволяет получить доступ к функциям модуля, имя которого указывается в качестве параметра. Тип параметра, разумеется, нужно предварительно преобразовать во внутреннее представление.
Py_DECREF ― макрос, высвобождающий память, занятую используемыми интерпретатором данными. Этот макрос отличается от Py_XDECREF тем, что последний может принимать нулевые значения в качестве параметра. Например, следующий фрагмент преобразует строку «mod» во внутренний тип Python’а и загружает нужный модуль.
pName = PyUnicode_FromString(«mod»);
pModule = PyImport_Import(pName);
Py_DECREF(pName);
После этого объект, содержащий строку, более не нужен, поэтому память очищается при помощи Py_DECREF.
PyObject_GetAttrString возвращает указатель на функцию из модуля, указанного в качестве первого параметра с именем, указанным в качестве второго.
Для передачи параметров функциям используются так называемые «tuples». Далее для простоты будем называть их кортежами. Кортежи – наборы определенного количества значений разных типов. Для создания нового кортежа используется функция PyTuple_New с указанием нужного числа передаваемых аргументов.
Потом кортеж заполняется значениями при помощи PyTuple_SetItem, первый аргумент которой – кортеж, второй – порядковый номер аргумента, а третий – его значение. После этого можно вызвать функцию PyObject_CallObject, передав ей функцию и кортеж аргументов.
Теперь организация ввода пользователем исходных данных не составляет проблемы.
Источник: habr.com
Встраивание Python в другое приложение
В предыдущих главах обсуждалось расширение Python,то есть расширение функциональности Python путем присоединения к нему библиотеки функций языка Си.Можно сделать и наоборот:обогатить ваше приложение на C/C++,встроив в него Python.Встраивание дает вашему приложению возможность реализовать часть функциональности вашего приложения на Python,а не на C или C++.Это можно использовать для многих целей;одним из примеров может быть предоставление пользователям возможности адаптировать приложение под свои нужды,написав некоторые скрипты на Python.Вы также можете использовать это сами,если некоторые функциональные возможности легче написать на Python.
Встраивание Python похоже на его расширение,но не совсем.Разница в том,что при расширении Python основной программой приложения по-прежнему является интерпретатор Python,а при внедрении Python основная программа может не иметь ничего общего с Python-вместо этого некоторые части приложения время от времени вызывают интерпретатор Python для выполнения некоторого кода Python.
Поэтому, если вы встраиваете Python, вы предоставляете свою собственную основную программу. Одной из задач этой основной программы является инициализация интерпретатора Python. По крайней мере, вам нужно вызвать функцию Py_Initialize() . Существуют необязательные вызовы для передачи аргументов командной строки в Python. Затем позже вы можете вызвать интерпретатор из любой части приложения.
Есть несколько разных способов вызвать интерпретатор: вы можете передать строку, содержащую операторы Python, в PyRun_SimpleString() , или вы можете передать указатель файла stdio и имя файла (только для идентификации в сообщениях об ошибках) в PyRun_SimpleFile() . Вы также можете вызывать операции более низкого уровня, описанные в предыдущих главах, для создания и использования объектов Python.
Подробности интерфейса Python на языке C приведены в этом руководстве.Большое количество необходимой информации можно найти здесь.
1.1.Встраивание очень высокого уровня
Простейшей формой встраивания Python является использование интерфейса очень высокого уровня.Этот интерфейс предназначен для выполнения сценария Python без необходимости непосредственного взаимодействия с приложением.Это может быть использовано,например,для выполнения какой-либо операции над файлом.
#define PY_SSIZE_T_CLEAN #include int main(int argc, char *argv[]) < wchar_t *program = Py_DecodeLocale(argv[0], NULL); if (program == NULL) < fprintf(stderr, «Fatal error: cannot decode argv[0]n»); exit(1); > Py_SetProgramName(program); / * необязательно, но рекомендуется * / Py_Initialize(); PyRun_SimpleString(«from time import time,ctimen» «print(‘Today is’, ctime(time()))n»); if (Py_FinalizeEx() < 0) < exit(120); > PyMem_RawFree(program); return 0; >
Функцию Py_SetProgramName() следует вызывать перед Py_Initialize() , чтобы сообщить интерпретатору о путях к библиотекам времени выполнения Python.
Затем интерпретатор Python инициализируется с помощью Py_Initialize() , после чего выполняется жестко запрограммированный скрипт Python, который печатает дату и время. После этого Py_FinalizeEx() выключает интерпретатор, а затем завершает работу программы. В реальной программе вы можете захотеть получить сценарий Python из другого источника, например, из процедуры текстового редактора, файла или базы данных. Получить код Python из файла лучше с помощью функции PyRun_SimpleFile() , которая избавляет вас от необходимости выделять место в памяти и загружать содержимое файла.
1.2.За пределами встраивания очень высокого уровня:Обзор
Высокоуровневый интерфейс дает вам возможность выполнять произвольные фрагменты кода Python из вашего приложения,но обмен значениями данных,мягко говоря,довольно громоздкий.Если вам это нужно,используйте вызовы более низкого уровня.За счет того,что вам придется писать больше кода на языке C,вы сможете добиться практически всего.
Следует отметить,что расширение Python и встраивание Python-это совершенно одинаковая деятельность,несмотря на разное намерение.Большинство тем,обсуждавшихся в предыдущих главах,остаются актуальными.Чтобы показать это,рассмотрим,что на самом деле делает код расширения с Python на C:
- Преобразование значений данных из Python в C,
- Выполните вызов функции в программе на языке C,используя преобразованные значения,и
- Преобразуйте значения данных из вызова из языка C в язык Python.
При встраивании Python это делает код интерфейса:
- Преобразование значений данных из языка C в язык Python,
- Выполните вызов функции интерфейсной процедуры Python,используя преобразованные значения,и
- Преобразуйте значения данных из вызова из Python в C.
Как вы видите,шаги преобразования данных просто меняются местами,чтобы учесть разное направление межъязыковой передачи.Единственное различие заключается в процедуре,которую вы вызываете между обоими преобразованиями данных.При расширении вы вызываете процедуру языка C,при встраивании-процедуру языка Python.
В этой главе не будет обсуждаться,как преобразовывать данные из Python в C и наоборот.Также предполагается,что правильное использование ссылок и работа с ошибками понятны.Поскольку эти аспекты не отличаются от расширения интерпретатора,за необходимой информацией можно обратиться к предыдущим главам.
1.3.Чистое встраивание
Первая программа направлена на выполнение функции в сценарии Python.Как и в разделе об интерфейсе очень высокого уровня,интерпретатор Python не взаимодействует напрямую с приложением (но это изменится в следующем разделе).
Код для запуска функции,определенной в сценарии Python,следующий:
#define PY_SSIZE_T_CLEAN #include int main(int argc, char *argv[]) < PyObject *pName, *pModule, *pFunc; PyObject *pArgs, *pValue; int i; if (argc < 3) < fprintf(stderr,»Usage: call pythonfile funcname [args]n»); return 1; > Py_Initialize(); pName = PyUnicode_DecodeFSDefault(argv[1]); / * Ошибка проверки pName пропущена * / pModule = PyImport_Import(pName); Py_DECREF(pName); if (pModule != NULL) < pFunc = PyObject_GetAttrString(pModule, argv[2]); / * pFunc — это новая ссылка * / if (pFunc PyCallable_Check(pFunc)) < pArgs = PyTuple_New(argc — 3); for (i = 0; i < argc — 3; ++i) < pValue = PyLong_FromLong(atoi(argv[i + 3])); if (!pValue) < Py_DECREF(pArgs); Py_DECREF(pModule); fprintf(stderr, «Cannot convert argumentn»); return 1; > / * Ссылка на pValue украдена здесь: * / PyTuple_SetItem(pArgs, i, pValue); > pValue = PyObject_CallObject(pFunc, pArgs); Py_DECREF(pArgs); if (pValue != NULL) < printf(«Result of call: %ldn», PyLong_AsLong(pValue)); Py_DECREF(pValue); > else < Py_DECREF(pFunc); Py_DECREF(pModule); PyErr_Print(); fprintf(stderr,»Call failedn»); return 1; > > else < if (PyErr_Occurred()) PyErr_Print(); fprintf(stderr, «Cannot find function «%s»n», argv[2]); > Py_XDECREF(pFunc); Py_DECREF(pModule); > else < PyErr_Print(); fprintf(stderr, «Failed to load «%s»n», argv[1]); return 1; > if (Py_FinalizeEx() < 0) < return 120; > return 0; >
Этот код загружает скрипт Python, используя argv[1] , и вызывает функцию, указанную в argv[2] . Его целочисленные аргументы — это другие значения массива argv .Если вы скомпилируете и скомпонуете эту программу (назовем готовый исполняемый файл вызовом ), и используете ее для выполнения скрипта Python, такого как:
def multiply(a,b): print(«Will compute», a, «times», b) c = 0 for i in range(0, a): c = c + b return c
тогда результат должен быть таким:
$ call multiply multiply 3 2 Will compute 3 times 2 Result of call: 6
Хотя программа довольно большая для своей функциональности,большая часть кода предназначена для преобразования данных между Python и C,а также для сообщения об ошибках.Интересная часть в отношении встраивания Python начинается с
Py_Initialize(); pName = PyUnicode_DecodeFSDefault(argv[1]); /* Error checking of pName left out */ pModule = PyImport_Import(pName);
После инициализации интерпретатора скрипт загружается с помощью PyImport_Import() . Эта подпрограмма нуждается в строке Python в качестве аргумента, которая создается с помощью подпрограммы преобразования данных PyUnicode_FromString() .
pFunc = PyObject_GetAttrString(pModule, argv[2]); / * pFunc — это новая ссылка * / if (pFunc PyCallable_Check(pFunc)) < . >Py_XDECREF(pFunc);
После загрузки скрипта искомое имя извлекается с помощью PyObject_GetAttrString() . Если имя существует и возвращаемый объект может быть вызван, вы можете с уверенностью предположить, что это функция. Затем программа продолжает строить кортеж аргументов, как обычно. Затем вызов функции Python выполняется с помощью:
pValue = PyObject_CallObject(pFunc, pArgs);
После возврата из функции pValue либо NULL , либо содержит ссылку на возвращаемое значение функции. Обязательно отпустите ссылку после изучения значения.
1.4.Расширение встроенного Python
До сих пор встроенный интерпретатор Python не имел доступа к функциональности самого приложения.API Python позволяет это сделать путем расширения встроенного интерпретатора.То есть встроенный интерпретатор расширяется с помощью процедур,предоставляемых приложением.Хотя это звучит сложно,на самом деле все не так уж плохо.Просто забудьте на некоторое время,что приложение запускает интерпретатор Python.Вместо этого рассматривайте приложение как набор подпрограмм и напишите некоторый код,который дает Python доступ к этим подпрограммам,точно так же,как вы бы написали обычное расширение Python.Например:
static int numargs=0; / * Возвращаем количество аргументов командной строки приложения * / static PyObject* emb_numargs(PyObject *self, PyObject *args) < if(!PyArg_ParseTuple(args, «:numargs»)) return NULL; return PyLong_FromLong(numargs); > static PyMethodDef EmbMethods[] = < «numargs», emb_numargs, METH_VARARGS, «Return the number of arguments received by the process.»>, NULL, NULL, 0, NULL> >; static PyModuleDef EmbModule = < PyModuleDef_HEAD_INIT, «emb», NULL, -1, EmbMethods, NULL, NULL, NULL, NULL >; static PyObject* PyInit_emb(void) < return PyModule_Create( >
Вставьте приведенный выше код прямо над функцией main() .Кроме того, вставьте следующие два оператора перед вызовом Py_Initialize() :
numargs = argc; PyImport_AppendInittab(«emb»,
Эти две строки инициализируют переменную numargs и делают emb.numargs() доступной для встроенного интерпретатора Python. С этими расширениями скрипт Python может делать такие вещи, как
import emb print(«Number of arguments», emb.numargs())
В реальном приложении методы будут раскрывать API приложения для Python.
1.5.Встраивание Python в C++
Можно также встроить Python в программу на C++;как именно это сделать,зависит от деталей используемой системы C++;в общем случае вам нужно будет написать основную программу на C++и использовать компилятор C++для компиляции и компоновки вашей программы.Нет необходимости перекомпилировать сам Python,используя C++.
1.6.Компиляция и компоновка в Unix-подобных системах
Не обязательно тривиально найти правильные флаги для передачи вашему компилятору (и компоновщику), чтобы встроить интерпретатор Python в ваше приложение, особенно потому, что Python необходимо загружать библиотечные модули, реализованные как динамические расширения C ( файлы .so ), связанные с Это.
Чтобы узнать необходимые флаги компилятора и компоновщика, вы можете выполнить сценарий pythonX.Y-config , который создается как часть процесса установки ( также может быть доступен сценарий python3-config ).У этого скрипта есть несколько опций, из которых вам будут непосредственно полезны следующие:
-
pythonX.Y-config —cflags предоставит вам рекомендуемые флаги при компиляции:
$ /opt/bin/python3.4-config —cflags -I/opt/include/python3.4m -I/opt/include/python3.4m -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes
$ /opt/bin/python3.4-config —ldflags -L/opt/lib/python3.4/config-3.4m -lpthread -ldl -lutil -lm -lpython3.4m -Xlinker -export-dynamic
Чтобы избежать путаницы между несколькими установками Python (и особенно между системным Python и вашим собственным скомпилированным Python), рекомендуется использовать абсолютный путь к pythonX.Y-config , как в приведенном выше примере.
Если эта процедура не работает для вас (она не гарантируется для всех Unix-подобных платформ, однако мы приветствуем сообщения об ошибках ), вам придется прочитать документацию вашей системы о динамической компоновке и/или изучить Makefile Python (используйте sysconfig.get_makefile_filename() , чтобы найти его местоположение) и параметры компиляции. В этом случае модуль sysconfig является полезным инструментом для программного извлечения значений конфигурации, которые вы хотите объединить. Например:
>>> import sysconfig >>> sysconfig.get_config_var(‘LIBS’) ‘-lpthread -ldl -lutil’ >>> sysconfig.get_config_var(‘LINKFORSHARED’) ‘-Xlinker -export-dynamic’
Python 3.11
Скачать документацию Python 3.11.0
Последнее обновление:26 октября 2022 года.
Создание расширений C и C++
Расширение C для CPython-это разделяемая библиотека (например.
Расширение Python с помощью C или C++
Добавить новые встроенные модули Python довольно просто,если вы умеете программировать на языке C.
1.3.Возвращаясь к примеру
Возвращаясь к нашему примеру функции,вы теперь должны понимать это утверждение:Оно возвращает NULL (индикатор ошибки для функций,возвращающих объект
Источник: runebook.dev