-
Notifications
You must be signed in to change notification settings - Fork 2
Making a python module by compiling c code
What I created was a test program in the c language that was compiled to be a python module. This was a first step needed to start wrapping c-code of the drivers for the Kromek multi-channel analyser in python, my top level language of choice. c code is the backbone of the unix/Linux operating system as well as python. I did this in January 2017 on my late 2008 macbook pro, running osx 10.11.6. I created a stripped down virtual environment for development of the Fisk CubeSat code, and the version of python that I installed this module on was 2.7.10. The following may not be necessary for installation but are what programs I was using at the time, I look at the c code in the Xcode interactive development environment (IDE), a mac specific program, with all sorts of developer tools I have installed over the many years I have used my computer. To look at my python code I use the PyCham IDE. Some commands are executed from my mac's terminal environment.
To create this c module I stared by generally following the example of The Python Documentation for Extending and Embedding the Python Interpreter . To help supliment my understanding of c code I used C for Python programmers.
The module I created was named 'spam' (a Monty Python's Flying Circus Reference) and it was used to execute bash (bourne again shell) commands (the terminal environment), a basic implementation of the c language, from python. I used two c files to make this module.
The first was a short header file named "spammodule.h". The file Python.h, is the python header, which "which pulls in the Python API, note: Since Python may define some pre-processor definitions which affect the standard headers on some systems, you must include Python.h before any standard headers are included"
#ifndef spammodule_h
#define spammodule_h
#include <Python/Python.h>
#include <stdio.h>
#endif /* spammodule_h */
The second file, named "spammodule.c" contained the actual definitions. These links convinsed me that this was what I needed to write for this file The Python Documentation for Extending and Embedding the Python Interpreter and C for Python programmers, as follows:
#include "spammodule.h"
// Below the definition of the variable that contains evaluated code
static PyObject *
spam_system(PyObject *self, PyObject *args)
{
const char *command;
int sts;
`if (!PyArg_ParseTuple(args, "s", &command))`
`return NULL;`
`sts = system(command);`
`return Py_BuildValue("i", sts);`
}
// This is the module's initialization functions
static PyMethodDef SpamMethods[] = {
{"system", spam_system, METH_VARARGS,
"Execute a shell command."},
{NULL, NULL, 0, NULL} /* Sentinel */
};
PyMODINIT_FUNC
initspam(void)
{
(void) Py_InitModule("spam", SpamMethods);
}
// below this executes the spam_system variable above when the compiled c program is called
int
main(int argc, char *argv[])
{
/* Pass argv[0] to the Python interpreter */
Py_SetProgramName(argv[0]);
`/* Initialize the Python interpreter. Required. */`
`Py_Initialize();`
`/* Add a static module */`
`initspam();`
}
I used help from Python Documentation for Building C and C++ Extensions with distutils to install this module.
To install the module you must create the python file 'setup.py' and you may need to install the 'distutils' package if it is not preinstalled on your machine. To test whatever version of python to see if distutils is installed, open up python and try the command import distutils
My 'setup.py' file looked like this:
from distutils.core import setup, Extension
spamModule = Extension('spam', sources=['cppDriverCode/spammodule.c'])
setup(name='spamName', version='1.0', description='this is test package for wrapping c code in python',
ext_modules = [spamModule])
Note that while the c files where names 'spammodule.h' and 'spammodule.c' but I am naming the python module 'spam' to conform with convention.
If you wish to install the module for the global version of python on you system (the version that is called when you execute 'python' from the terminal) then the installation can be completed by using cd in the terminal to get to the location of 'spammodule.h' and 'spammodule.c' and running the following:
python setup.py build
python setup.py install
I needed to call the version of python that was being used by my virtual development environment and refenence a 'setup.py' function that was in a directory called 'cppDriverCode' so my istallation looked like this:
/Users/chw3k5/Documents/Fisk/fiskCubeSat/venv/bin/python cppDriverCode/setup.py build
/Users/chw3k5/Documents/Fisk/fiskCubeSat/venv/bin/python cppDriverCode/setup.py install
To test that the module was installed I open up python and ran the following two lines
import spam
print spam.system("ls -l")
which printed the same result as the the terminal command 'ls -l'. The output of this python code like this when I got everything installed and working:
total 32
-rw-r--r-- 1 chw3k5 staff 14 Jan 19 16:09 README.md
drwxr-xr-x 7 chw3k5 staff 238 Jan 26 09:49 build
drwxr-xr-x 81 chw3k5 staff 2754 Jan 26 11:04 cppDriverCode
-rw-r--r-- 1 chw3k5 staff 463 Jan 25 14:08 dataGetter.py
-rw-r--r-- 1 chw3k5 staff 46 Jan 25 16:08 kromekControl.py
-rw-r--r-- 1 chw3k5 staff 3006 Jan 25 14:08 peakFinder.py
drwxr-xr-x 3 chw3k5 staff 102 Jan 24 12:15 testData
drwxr-xr-x 7 chw3k5 staff 238 Jan 23 11:53 venv
0