Making Python work with C/C++ can be achieved in a couple of ways, either writing a DLL with a Python API,
or using the ctypes library module.
When working with Python, it is useful to have virtual environments so that we have a clean and isolated Python environment.
Although it is not necessary for this example, I’ll run through the steps necessary:
Then:
c:\> cd c:\python27\scripts
c:\python27\scripts> easy_install virtualenv
c:\python27\scripts> easy_install pip
and then:
C:\Python27\Scripts>virtualenv --distribute --prompt=(myenv) %USERPROFILE%\myenv
New python executable in C:\Users\user\myenv\Scripts\python.exe
Installing distribute...........................................................
................................................................................
....................................................done.
Installing pip.................done.
Then enter your virtualenv
c:\> C:\Users\user\myenv\Scripts\activate.bat
(myenv) c:\>
where you can now use pip install
to download and install python modules into the virtualenv
as necessary.
If you want to use the Python Tools for Visual Studio, ensure that you change %USERPROFILE%
to $(UserProfile)
in the (Python) project settings so that you run Python from the correct virutalenv
.
ctypes example
The library documentation on ctypes can be found here.
If we start from scratch in Visual Studio, we can create a solution that contains two projects: a simple Python program to demonstrate ctypes, and a simple DLL from the VS wizards.
Quoting verbatim from the
Python docs: ctypes exports the cdll, and on Windows windll and oledll objects,
for loading dynamic link libraries. So by using the LoadLibrary
method on cdll
we can load our
DLL into Python, and then start accessing the methods.
The following Python except demonstrates this in practice:
print "Loading dll {0}".format(dll_path)
mydll = cdll.LoadLibrary(dll_path)
result = mydll.fnSimpleDll()
print "Function returned: {0}".format(result)
cppFunction = mydll[1]
cppresult = cppFunction()
print "C++ decorated function by ordinal returned: {0}".format(cppresult)
newCppFunction = getattr(mydll, "?cppFunction@@YAHXZ")
newCppResult = newCppFunction()
print "C++ decorated function by ordinal returned: {0}".format(newCppResult)
print "Finished"
Using depends
, we can examine our DLL and see the ordinals and decorated names (or use a .def file if we really want to).
Prefixing functions in C++ with extern "C"
makes them directly available in Python as if they were a standard Python module as the function names are undecorated.
For a library or project where you use code generation, you can easily generate a Python stub to your DLLs or .so files that is available cross platform.
Other obvious uses are to use Python as a harness for your C/C++ DLLs and run Python based tests against them: this can be particularly useful when Python
has some benefit or feature that C++ does not have built-in or available in your environment, that you might want to take advantage of during testing, such as Regular Expressions,
REST calls, and so on.
Attached is a Zip file containing the example shown here.
- PythonCTypes.zip (requires VS2010,
Python 2.7, PTVS, and a virtualenv as described above).