📜 ⬆️ ⬇️

Python, Modules, SWIG, Windows

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:
  1. Create a new project to create a Windows DLL
  2. 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 )
  3. 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
  4. 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?)
  5. 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.
  6. 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?
  7. 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

 # -*- coding: utf-8 -*- import distutils from distutils.core import setup, Extension setup(name = "Simple example from the SWIG website", version = "0.007", ext_modules = [Extension( "_example", #  :    ["example.i","example.cxx"], swig_opts=['-threads', '-c++'], #  :  swig  )] ); 


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.

Source: https://habr.com/ru/post/139790/


All Articles