'Python's C extension with more than one header
I have been updating a Python package developed in Python 2.7, so far so good until I got to the C extensions. My C (plib.c) file imports the classes below:
#include <Python.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <xyz.h>
The corresponding init file was like this:
PyMODINIT_FUNC initplib(void)
{
PyObject *plib_module;
plib_module = Py_InitModule("xyz.plib", plib_methods);
PyModule_AddStringConstant(plib_module, "plib_api_version", plib_api_version);
}
My setup.py looks like this:
plib = distutils.core.Extension('xyz.plib ',
sources = ['src/plib.c'],
include_dirs = incdirs,
library_dirs = libdirs,
libraries = libs,
extra_compile_args = ['-Wall', '-pedantic']
#,
#'extra_link_args = ['-fPIC']
)
distutils.core.setup(name = 'xyz',
version = '0.1',
packages = ['xyz'],
ext_modules = [plib])
I can then call plib from my python file as import plib.
However, Python 3.X requires me to do something a bit different:
static struct PyModuleDef plib= {
PyModuleDef_HEAD_INIT,
"xyz.plib ", /* name of module */
"", /* module documentation, may be NULL */
-1, /* size of per-interpreter state of the module, or -1 if the module keeps state in global variables. */
plib_methods
};
PyMODINIT_FUNC PyInit_initclib(void)
{
return PyModule_Create(&plib);
}
I have tried different names with no success, I still not able to load the xyz.h header and therefore I get the error:
'unresolved external symbol'
Can anyone tell me what I'm doing wrong
EDIT a workable example
Calculating the kth prime number (Taken from somewhere else)
primeheader.h
extern int kthPrime(int n);
c_prime.c
#include <stdio.h>
#include "primeheader.h"
int isPrime(int n) {
for (int i=2; i<n/2; i++) {
if (n%i == 0)
return 0;
}
return 1;
}
int kthPrime(int k) {
int candidate = 2;
while (k) {
if (isPrime(candidate))
k--;
candidate++;
}
return candidate-1;
}
// Driver code
int main() {
printf("%d\n", kthPrime(10000));
return 0;
}
compile c_prime:
gcc -c c_prime.c
fastprime.c
#include <Python.h>
#include "primeheader.h"
// A static function which takes PyObjects arguments and returns a PyObject result
static PyObject* py_kthPrime(PyObject* self, PyObject* args) {
int n;
if (!PyArg_ParseTuple(args, "i", &n)) // Validate and parse the arguments received to function so that its usable by C
return NULL;
return Py_BuildValue("i", kthPrime(n)); // Get result from C, wrap it up with a PyObject and return it
}
// Define a collection of methods callable from our module
static PyMethodDef PyFastPrimeMethods[] = {
{"kthPrime", py_kthPrime, METH_VARARGS, "Finds the kth prime number"}
};
// Module definition
static struct PyModuleDef fastprimemodule = {
PyModuleDef_HEAD_INIT,
"fastprime",
"This module calculates the kth prime number",
-1,
PyFastPrimeMethods
};
// This method is called when you import your code in python. It instantiates the module and returns a reference to it
PyMODINIT_FUNC PyInit_fastprime(void)
{
return PyModule_Create(&fastprimemodule);
}
setup.py
from distutils.core import setup, Extension
setup(name='fastprime',
ext_modules=[
Extension('fastprime',
['fastprime.c'],
extra_objects=["c_prime.o"] # Relocatable compiled code of the c_prime to prevent recompiling each time
)
]
)
Build module
python setup.py build
Errors
c_prime.o : error LNK2001: unresolved external symbol __main
c_prime.o : error LNK2001: unresolved external symbol printf
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|