Hey, here is a crazy idea: lets have the unicorns do all the work! Whoa! another idea!
This project is a demonstration of embedding a Python module within a C/C++ application. Numpy is used to help work with numeric data. Cython is used as glue. This project has been developed with the following dependencies:
- Python-2.7.2, http://python.org/download/releases/2.7.2/
- Cython-0.14.1, http://www.lfd.uci.edu/~gohlke/pythonlibs/
- Numpy-1.6.0 (MKL), http://www.lfd.uci.edu/~gohlke/pythonlibs/
I started to separate files Python vs. C/C++. This may not be fully functional at this point....
Files in this project
work_module.py This is the Python module containing super awesome stuff that someone wishes to embed within their C++ application. This module is unaware of being embeded, and may also in turn import other pure Python module or even external extensions written in C, C++, or FORTRAN. Numpy is imported to help work with arrays of data.
wrapper_inner.pyx This file is a Cython module that is the starting point for creating an embeddable wrapper for the python module above. Cython is used here since it helps take care of creating C/C++ code that knows how to talk to both the CPython C-API and the Numpy C-API. Cython will also take care of Python object reference counters. In this module we can code that will receive normal C/C++ arguments and turn them into something to be passed into the Python work module. This module will also help with the reverse, taking results generated by Python and Numpy and sending them back to the caller as normal C/C++ variables. In this example I created a CDEF Cython function called "inner_work".
wrapper_outer.hpp This file contains a simple C++ function that will serve as the primary interface to the c/C++ host application that is embedding this stuff. This function takes care of three things: a) Initialize the Python interpreter, if its not already running b) Call the Cython-generated inner wrapper function to perform desired work via embeded Python c) Finalize the Python interpreter ??????
example_application.cpp This is an example a C++ user application calling the embedded Python to get some useful work done. This file must include the above file wrapper_outer.hpp.
setup.py This is the usual Python setup.py file. It is used here solely to build the Python extension for wrapper_inner.pyx. Run this as: "python setup.py build_ext --inplace". The --inplace parameter simply forces the resulting .pyd file to be placed in the current folder. Running setup.py takes care of two things:
a) Call "Cythonize" the wrapper_inner.pyx file into a wrapper_inner.cpp file. b) Compile the resulting wrapper_inner.cpp file into a wrapper_inner.pyd extension module (really just a DLL).
setup.cfg This file is optional and simply enables replacing the above setup command with "python setup.py build". It contains at least the two following lines:
CMakeList.txt CMake configuration file that describes how to configure, compile, and build the example C++ application example_application.cpp. Run CMake, then compile the project using your prefered compiler. This file is used to indentify the location of the system's Python and Numpy header files.
Running Cython via the setup.py file above essentially "Cythonizes" the above wrapper_inner.pyx file and generates the C/C++ files needed to perform the actual embedding process. Do NOT edit any of these automatically-generated files. Any editing must be done to the files listed above.
wrapper_inner.cpp Generated by Cython as part of running "setup.py build". This file is the C++ equivalent of version of the user-generated file wrapper_inner.pyx. Do NOT edit this file!
wrapper_inner.h Basic header file describing the C/C++ functions exposed from the inner_wrapper. Do NOT edit this file! and also do NOT include this file!
wrapper_inner_api.h This is the file to be included within the outter wrapper C++ file. This API header file defines the very important function(s) import_<your_name_here>(), where <your_name_here> corresponds to a CDEF Cython function within the inner wrapper .pyx file. In this example this function is called "import_wrapper_inner()". Do NOT edit this file!
wrapper_inner.pyd This is the compiled Python external extension module for the inner wrapper. It is really just a fancy DLL, but Python can import it just like any other module. In this example project it will be importated automatically via the CPython C-API from within the inner wrapper API function call import_wrapper_inner().
- Write and edit the project files. This mostly involves copying the user-generated files from a previous project and then editing.
- Build the Cython extension: python.exe ./setup.py build
- Setup the application project: cmake -G "Visual Studio 9 2008 Win64" ..
- Build the application solution with your compiler (Visual Studio 2008 for me)
References, in order of potential usefulness
Quote from here: "Using the api method does not require the C code using the declarations to be linked with the extension module in any way, as the Python import machinery is used to make the connection dynamically"
More helpful link: http://docs.scipy.org/doc/numpy/reference/c-api.html http://docs.scipy.org/doc/numpy/reference/c-api.array.html#array-structure-and-data-access http://docs.scipy.org/doc/numpy/reference/c-api.array.html#data-access http://docs.scipy.org/doc/numpy/reference/c-api.array.html#from-scratch http://docs.scipy.org/doc/numpy/reference/c-api.array.html#from-other-objects http://docs.scipy.org/doc/numpy/reference/c-api.array.html#general-check-of-python-type http://docs.scipy.org/doc/numpy/reference/c-api.array.html#data-type-checking http://docs.scipy.org/doc/numpy/reference/c-api.array.html#converting-data-types http://docs.scipy.org/doc/numpy/reference/c-api.array.html#special-functions-for-pyarray-object http://docs.scipy.org/doc/numpy/reference/c-api.array.html#conversion http://docs.scipy.org/doc/numpy/reference/c-api.array.html#shape-manipulation
http://www.freenet.org.nz/python/embeddingpyrex/ Cython has changed enough over recent years that this example no longer works.