Я написал модуль расширения в C с именем extmodule.c, и код для него следующий:
#include <Python.h>
//Define a new exception object for our module
static PyObject *extError;
static PyObject* ext_cpu(PyObject* self, PyObject *args)
{
int pid;
int sts=0;
//We expect at least 1 argument to this function
if(!PyArg_ParseTuple(args, "i", &pid))
{
return NULL;
}
printf("Hello, from C World! Pid: %i", pid);
sts=pid;
return Py_BuildValue("i", sts);
}
static PyMethodDef ext_methods[] = {
//PythonName, C-FunctionName, argument_presentation, description
{"cpu", ext_cpu, METH_VARARGS, "Print cpu consumption of a particular process with pid"}
};
PyMODINIT_FUNC
PyInit_ext(void)
{
PyObject *m;
m = PyModule_Create(&ext_methods);
if (m == NULL)
return NULL;
extError = PyErr_NewException("spam.error", NULL, NULL);
Py_INCREF(extError);
PyModule_AddObject(m, "error", extError);
return m;
}
После этого я создал setup.py для создания и установки файла расширения в моей программе python, а код для setup.py выглядит следующим образом:
from distutils.core import setup, Extension
module1 = Extension('ext',
include_dirs = ['/usr/local/include'],
libraries = ['pthread'],
sources = ['extmodule.c'])
setup (name = 'ext',
version = '1.0',
description = 'This is a C extension for Python program',
author = 'Somdip Dey',
url = '',
ext_modules = [module1])
Теперь в командной строке я создал setup.py, используя следующие команды:
>> python setup.py build
run build running build_ext
расширение 'ext' gcc -Wno-unused-result -Wsign -c ompare -Wunreachable -c ode -DNDEBUG -g -fwrapv -o 3 -Wall -Wstrict-прототипы -I/Пользователи /somdipdey/anaconda3/include -arch x86_64 -I/Пользователи /somdipdey/anaconda3/include -arch x86_64 -I/usr/local/include -I/Пользователи /somdipdey/anaco nda3/include/python3.6m [CN09 ] extmodule.c -o build/temp. macosx- 10.7-x86_64-3.6/extmodule.o extmodule.c: 34: 25: предупреждение: несовместимые типы указателей, передающие 'PyMethodDef (*) [1]' параметру типа 'struct PyModuleDef *' [-Wincompatible-pointer-types] m = PyModule_Create (& ext_methods); /Users/somdipdey/anaconda3/include/python3.6m/modsupport.h:158:26: примечание: расширено от макроса 'PyModule_Create' PyModule_Create2 (модуль, PYTHON_API_VERSION) ^ ~~~~~/Пользователи /somdipdey/anaconda3/include/python3.6m/modsupport.h: 150: 60: note: передайте аргумент параметру здесь PyAPI_FUNC (PyObject) PyModule_Create2 (генерируется предупреждение о генерации PyModuleDef, ^ 1. gcc -bundle -undefined dynamic_lookup -L/Пользователи /somdipdey/anaconda3/lib -arch x86_64 -L/Пользователи /somdipdey/anaconda3/lib -arch x86 _64 -arch x86_64 build/temp. macosx- 10.7-x86_64-3.6/extmodule.o -L/Пользователи /somdipdey/anaconda3/lib -L pthread -o build/lib. macosx- 10.7-x86_64-3.6/ext.cpython-36m-darwin.so
>> python setup.py install
Команда установки работала правильно, но сборка дала 1 предупреждение. Теперь, когда я пытаюсь импортировать ext в мою программу python и использовать функцию ext.cpu(integer_value), программа дает мне следующую ошибку:
Ошибка сегментации: 11
Любая идея, что может вызвать проблему и как ее избавиться?
Предупреждение сообщает вам, что именно неправильно: вы передаете PyMethodDef (*)[1]
в PyModule_Create
, когда он ожидает PyModuleDef *
. Это совершенно несвязанные типы. Полученный вами segfault похож на C-версию TypeError
.
Вам нужно создать таблицу определения модуля и передать ее PyModule_Create
.
Если вы исправите это, вы можете или не иметь другого segfault, или данные мусора, или загадочный segfault при выходе, потому что в таблице методов отсутствует пустая строка в конце. C не знают своего размера, как это делают списки Python, поэтому код, который их использует, либо должен проходить вокруг размера в отдельной переменной, либо использовать какое-то "контрольное" значение в последнем слоте. PyMethodDef
использует последнее решение.
Так:
static PyMethodDef ext_methods[] = {
//PythonName, C-FunctionName, argument_presentation, description
{"cpu", ext_cpu, METH_VARARGS, "Print cpu consumption of a particular process with pid"},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef ext_module = {
PyModuleDef_HEAD_INIT,
"ext",
"Extension module that does stuff",
-1,
ext_methods
};
PyMODINIT_FUNC
PyInit_ext(void)
{
PyObject *m;
m = PyModule_Create(&ext_module);
// the rest is the same as before
С этими изменениями ваш модуль строит без предупреждений и:
>>> import ext
>>> ext.cpu(23)
Hello, from C World! Pid: 23
>>> ^D
... все работает нормально.
(Ну, там может быть утечка памяти, но это отдельная проблема...)