This article is a description of my experiments on building modules for Python. I needed a high-level interface to the library
LibRaw , moreover, primarily under Windows.
Last time I wrote the module for python in C ++ in 2004. Module to the stillborn (fortunately not by me) library (I stupidly sold my skills for a salary). Naturally, the skills are not fixed. I remember that
SWIG greatly facilitated my work, because I needed an object interface, and it broke me to write with “pens”. My memory is professional - that is, selective and short, so I had to jump first.
This article is just about setting up
SWIG for Python under Windows. Writing modules in C / C ++ using SWIG is
much easier than configuring everything (by the way, I have the impression that this is a paradigm of modern programming).
')
First of all, I got into Yandex. Epic fail - all tips and workouts are out of date by three. Following them, I had to make absolutely unnecessary steps to build python from source. There are no extra steps in the article, although the python is going without problems. But if you collect, then useful advice: take the file Include / pycohfig.h from the “boxed” delivery and quietly put it into the assembled version - it will come in handy.
Good news. You can use
Microsoft Visual C ++ Express Edition 2008 for building modules, since Python 2.6+ is built for them. Before that, I had to either compile a python from sources, or dig out moss-covered VC ++ 7.0, and I even 6.0. Even more good news - modules can be compiled
MinGW . By the way? I compiled the test module with gcc “included” in Strawberry Perl (rather cynically if we recall the ancient python-barley wars). Just because this is the first gcc in Path.
So, we need to take an example from SWIG and turn it into a module. There are two ways to do this.
But, first, you need to install the
SWIG compiled under Windows (swigwin-2.0.4) and register it in the PATH. Examples of use come with it.
Method One: Visual C ++
We need to set the environment variable.
PYTHON_INCLUDE = C: \ Python \ Include
PYTHON_LIB = C: \ Python \ Libs \ python27.lib
Then you can shalturit - take one of the ready-made examples for which the solution (.sln) and the project have already been created. And calmly, at its base, make your module. For example, open
SWIG\Examples\python\class\exmple.sln
. Rename
examples.i
,
examples.cxx
and
examples_wrap.cxx
, respectively, in
mymodule.i
,
mymodule.cxx
and
mymodule_wrap.cxx
.
As the experience just delivered showed, everything works fine.
For more corrosive comrades
cookie instruction in English . As always, a little outdated (or perhaps too new). Using it literally, I could not achieve a profit. The following instructions are in Russian, abbreviated and tested:
- Create a new project to create a Windows DLL
- Create files
my_module.cxx
(or .c) for our classes / functions, my_module.i
to describe the interface. And prescribe (but do not create) my_module_wrap.cxx
. The first two files, I, of course, cut from the same examples, but you can take them for example from Wikipedia )
- Select in the environment
my_module.i
, in the properties ( Custom build setup ) install:
- Command Line : swig.exe -c++ -python $(InputPath)
- Outputs : $(InputName)_wrap.cxx
(For C projects, you do not need to specify the -c++
key in the first case. And the .cxx
extension (.c is enough) in the second.)
As a result, we will create the file my_module_wrap.c(xx)
from the interface file my_module.i
- Next you need to specify the location of the python headers. In the project properties, select Configuration Properties ”/ C ++ and set Additional include directories to
$(PYTHON_INCLUDE)
(In vain did they ask anything?)
- Further according to the plan properties of the linker (Linker):
- Input »Aditional Dependies : "$(PYTHON_LIB)"
- General »Output File : $(ProjectDir)\_$(ProjectName).pyd
In the first case, the quotes do not interfere, and in the second, pay attention to the underscore. Why is it - I will tell below.
- You can build a project. Remember to switch to the Release configuration. To use Debug, it is necessary to collect a python from source codes, and we need it?
- Profit
Method Two: distutils
What can not but rejoice, Python 2.7 has already been sharpened to assemble modules using
distutils (in previous versions
3 kilograms of shamanism were required). At the same time, we can use both the aforementioned (not for the night) MVC 2008, and the free MinGW.
About small rakes waiting for us on this way, I, stroking a forehead, now I will tell.
Again, inhuman experiments will be put on the example of SWIG. So, in the directory
SWIG/examples/classes
create a file
setup.py
Grabel the first.
Underline If you do not specify it, you will receive a
LINK : error LNK2001: unresolved external symbol initexample
.
Where does it grow from?
Python, when creating a module with “hands”, expects that in the compiled module (the binary part) there will be a function with the
init<_>
. Made so that the module written in C / C ++ can taste it when the binary module is loaded (and tell python that everything is ok). Wrapper (SWIG) function honestly creates.
But SWIG creates two (!)
<_>.py
for our module:
<_>.py
is a Python wrapper containing native function calls for the future module and
_<_>.pyd
(note the underscore) - a binary library. The fact is that a binary library can be loaded “into python” with the same
import
statement as the native one (underscore is “implied”). Accordingly, the names of the native wrapper and the binary library should be different. They differ - to underscore.
SWIG expects us to have a binary library with an underscore, so I created a function called init_ <module_name>, about which the linker knows nothing. Here is the mistake.
Grabel the second
It took me some time climbing the source to figure out how to pass command line options to the swig command line call. By default,
distutil
expects us to work with C. Therefore, it was necessary to specify the
-c++
parameter (the
-threads
parameter
-threads
added “for Ponte”, but it may not be useless to whom)
Assembly
Now, when we figured out, you can assemble the module in two ways:
Collect using MVC:
python setup.py build
Assemble using MinGW:
python setup.py build -cmingw32
Both methods are tested and work. Even strange.
Any advice (as it could be made easier) is welcome. Criticism too (but preferably with an indication of exactly how it should have been done). I hope I don’t have to rewrite the article more than half what happened after the first comment. After which I dug a little deeper than before.