Это мой первый опыт встраивания Python в C++.
Я просто пытаюсь создать простую программу, чтобы понять, как она работает.
Ниже приведен мой код.
main.cpp
#define PY_SSIZE_T_CLEAN
#include </usr/include/python3.8/Python.h>
#include <iostream>
int main(int argc, char *argv[]){
PyObject *pName, *pModule, *pFunc, *pArgs, *pValue;
Py_Initialize();
pName = PyUnicode_FromString((char*)"script");
pModule = PyImport_Import(pName);
pFunc = PyObject_GetAttrString(pModule, (char*)"test");
pArgs = PyTuple_Pack(1, PyUnicode_FromString((char*)"Greg"));
pValue = PyObject_CallObject(pFunc, pArgs);
auto result = _PyUnicode_AsString(pValue);
std::cout << result << std::endl;
Py_Finalize();
}
script.py
def test(person):
return "What's up " + person;
Вот как я компилировал в Linux
g++ -I/usr/include/python3.8/ main.cpp -L/usr/lib/python3.8/config-3.8-x86_64-linux-gnu -lpython3.8 -o output
Я компилирую так, потому что (#include <Python.h> доставлял мне проблемы, да, я пробовал sudo apt-get install python3.8-dev)
Файл успешно компилируется, но когда я пытаюсь запустить ./output, я получаю следующую ошибку.
Segmentation fault (core dumped)
Я искал, что означает эта ошибка, и там говорится, что ошибка сегментации — это особый тип ошибки, вызванный доступом к памяти, которая «не принадлежит вам».
Но какое воспоминание не принадлежит мне? Это файл питона?
Любое руководство будет высоко оценено.
Сейчас самое время научиться пользоваться отладчиком (например, gdb); но вы всегда можете начать с так называемого printf debugging
. Вставьте оператор печати между каждым оператором, чтобы увидеть, где он умирает. Однако gdb намного мощнее.
Также проверьте свои возвраты. Любой из них может вернуть NULL, потому что что-то не так, как вы ожидали.
Я помещаю операторы печати после каждой строки, и при вызове pFunc = PyObject_GetAttrString(pModule, (char*)"test");
происходит сбой.
Отлично, а что такое pModule на тот момент?
@scriptKiddie123 Так ты не проверил, является ли pModule
NULL
после звонка pModule = PyImport_Import(pName);
?
Подсказка: if (variable == NULL)
и функция API PyErr_Print()
будут вашими друзьями, чтобы выяснить, что пошло не так.
Я написал этот код сразу после pModule = PyImport_Import(pName)
if (pModule){ std::cout << "True"<<std::endl; } else{ std::cout <<"False"<<std::endl; } Он вернул False, что означает, что pModule имеет значение Null.
После каждого из этих утверждений вам нужно будет проверить наличие ошибок, используя что-то вроде:
if (varname == NULL) {
cout << “An error occured” << endl;
PyErr_Print();
return EXIT_FAILURE;
}
Это проверит, если уровень python через ошибку; и если это так, попросит его распечатать трассировку Python на экране и выйти. Вы можете использовать эту трассировку, чтобы выяснить, в чем заключается ваша ошибка.
Любая из этих функций может дать сбой, и вам необходимо проверить ее, прежде чем продолжить. Из-за этого использование Python C API чрезвычайно неудобно. Большинство функций C API, которые возвращают указатель, при ошибке возвращают NULL, и передача NULL в любую функцию без предварительной проверки неизбежно приведет к сбою.
Вы получаете ошибку сегментации при доступе к указателю NULL, поскольку почти все современные системы сопоставляют доступ к NULL с ошибкой сегментации или каким-либо сбоем для обнаружения ошибок программирования.
Кроме того, не преобразовывайте строки в (char *). Они уже должны быть (const char *), что и ожидает API Python в большинстве мест.
ModuleNotFoundError: нет модуля с именем «скрипт». Должно быть, я неправильно назначаю pName.
Это означает, что он не может найти ваш script.py. Ваш pName в порядке, так как он распечатал имя script
. Вам нужно будет выяснить, где он хочет, чтобы ваш script.py был. Насколько я могу судить, он использует sys.path
точно так же, как и Python.
Они оба находятся в одном каталоге. Вы подразумеваете, что это может быть проблема пути?
И если вы запустите «python3.8» в том же каталоге, что и созданный вами исполняемый файл, будет ли работать import script
?
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append(\".\")");
Это сделало работу
Segfault может произойти по любому количеству причин. Это неопределенное поведение, если python пытается изменить строковый литерал, поэтому никогда не отбрасывайте
const
от них. Вы можете попытаться отладить программу на С++ и посмотреть, что именно вызывает ее.