How do I handle function templates in SWIG? - python

I am getting a "Syntax error in input" error using SWIG on the following line of code
template<typename T>
void print_vec(std::vector<T> vec, int length = -1);
in my .i file, I include the following line
%template(print_vec_int) print_vec<int>;
What am I doing wrong?

You are swigging C++ code, but telling swig it is C. You need to add -c++ to the swig command line.
swig -o x_wrap.cc -c++ -python x.i
If you are using SCons, then you need to update the SWIGFLAGS environment variable:
env = Environment(SWIGFLAGS=['-c++', '-python'])

Related

Running python script from c++ code and use pythons output in c++

I'm have a C++ program that is pretty far developed to do it's own job and now we'd like to add an addition functionality to it and we thought that making said functionality in Python and then calling that python with required inputs from the C++ when needed would be the best way to go as it keeps them separated and allows us to use this python script from elsewhere too.
As a first step I decided to try to make a test program to see how this would work and seems like it was a good idea because I can't get it to work.
How do I run separate python from c++?
I have tried following this guide and while it seems good it doesn't give any information on what compiler options should I run this with?
I have two files, cpp.cpp and python.py
This is my cpp.cpp file:
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <ncurses.h>
#include <Python.h>
using namespace std;
int main() {
std::cout << "C++ program started!\n";
char filename[] = "python.py";
FILE* fp;
Py_Initialize();
fp = _Py_fopen(filename, "r");
PyRun_SimpleFile(fp, filename);
Py_Finalize();
std::cout << "C++ program is ending!\n";
return 0;
}
and my python file is just two printf line:
#print('External Python program running...')
#print('Hello World from Python program')
I then try to compile this, give it all the includes it seems to want and then execute the output file:
g++ -I . -I /home/ahomm/python3.6/Include -I /home/ahomm/python3.6/release cpp.cpp && ./a.out
This is the output I get:
/tmp/cccQsh1p.o: In function `main':
cpp.cpp:(.text+0x3f): undefined reference to `Py_Initialize'
cpp.cpp:(.text+0x52): undefined reference to `_Py_fopen'
cpp.cpp:(.text+0x70): undefined reference to `PyRun_SimpleFileExFlags'
cpp.cpp:(.text+0x75): undefined reference to `Py_Finalize'
collect2: error: ld returned 1 exit status
What am I missing? is just something just a little or completely wrong?
cpp and py files and located in the same directory.
And how do I then read the output of python in C++? Haven't even got to that yet...
You have to link your code with libpython3.x.a/python3.x.lib (x - version of python you use). Which file to link: *.a or *.lib depends of your OS. The files are available with python distribution.
Here is a code with cmake that works for me:
cmake_minimum_required(VERSION 2.8.9)
project (embpy)
add_executable(embpy embpy.cpp)
target_include_directories(embpy PRIVATE /path-to-python/Python38/include/python3.8)
target_link_libraries(embpy /path-to-python/Python38/lib/libpython3.8.a)
the embpy.cpp is the same as yours
Figured it out myself then, the problem was incomplete compiler arguments.
This is what I got it to works with:
g++ -fPIC $(python3.6-config --cflags) cpp.cpp $(python3.6-config --ldflags)
the key missing parts were $(python3.6-config --cflags) before and $(python3.6-config --ldflags) after the file that was to be compiled. The first one gives g++ the compile options and the latter gives the flags for linking.
Found the solution from python docs, part 1.6.

Compile c++ to python using swig

I'm trying to compile very simple file to python on windows and I'm having a bad time.
The .i file is testfile.i:
%module testfile
%include "stl.i"
%{
int get_num() {
return 3;
}
%}
int get_num() {
return 3;
}
The swig function:
{swig path}\swig.exe -c++ -python testfile.i
This works perfectly, I now got the testfile.py file and testfile_wrap.cxx file.
Now I understood that I need to compile this to library (.pyd on windows). I tried:
{gcc path}\gcc.exe -fPIC -shared testfile_wrap.cxx -o testfile_wrap.pyd -L. -LC:\Python27\libs\ -lpython27 -IC:\python27\include.
Here is the problem, I get alot of errors like this ones:
C:\Users\itay\AppData\Local\Temp\ccANsNeU.o:testfile_wrap.cxx:(.text+0xc00): undefined reference to `__imp_PyExc_MemoryError'
C:\Users\itay\AppData\Local\Temp\ccANsNeU.o:testfile_wrap.cxx:(.text+0xc13): undefined reference to `__imp_PyExc_IOError'
C:\Users\itay\AppData\Local\Temp\ccANsNeU.o:testfile_wrap.cxx:(.text+0xc26): undefined reference to `__imp_PyExc_RuntimeError'
C:\Users\itay\AppData\Local\Temp\ccANsNeU.o:testfile_wrap.cxx:(.text+0xc39): undefined reference to `__imp_PyExc_IndexError'
And it continues on and on.
What am I doing wrong?
Thank you for your help
Update:
I managed to call swig and compile/link using visual studio 2013 but I get the same error. I followed tutorials and it still does not work.
The solution: my python was 64 bit and it didn't work. Changed to python 32 bit and now it is working (python 2.7.10)

SWIG Syntax Error

I'm trying to compile some SWIG bindings from a wireless communications library (http://www.yonch.com/wireless) that also uses the IT++ library. I am using SWIG version 2.0.11 on Ubuntu 14.04.
This is the error I am getting when trying to build:
/usr/include/itpp/base/binary.h:162: Error: Syntax error in input(1)
Here is line 162 from binary.h:
ITPP_EXPORT std::ostream &operator<<(std::ostream &output, const bin &inbin);
If the rest of that file is needed it can be found here: http://montecristo.co.it.pt/itpp/binary_8h_source.html
This is the SWIG command line call that is being used:
/usr/bin/swig -c++ -python -I/home/user/anaconda/include/python2.7 -I../../../include -I/usr/include -I../../../bindings/itpp -I../../../bindings/itpp/.. -DHAVE_CONFIG_H -o base_sparse.cpp ../../../bindings/itpp/base_sparse.i
I have almost no experience with SWIG and can't seem to see what about the code would be causing that syntax error. Any insights would be greatly appreciated!
Exports are not understood by SWIG
I usually add a
#define ITPP_EXPORT
in your .i file after the inclusion of the C/C++ headers and before you include them using
%include "Someheader.h"

Call python code from c via cython

So I'd like to call some python code from c via cython. I've managed to call cython code from c. And I can also call python code from cython. But when I add it all together, some things are missing.
Here is my python code (quacker.pyx):
def quack():
print "Quack!"
Here is my cython "bridge" (caller.pyx):
from quacker import quack
cdef public void call_quack():
quack()
And here is the c code (main.c):
#include <Python.h>
#include "caller.h"
int main() {
Py_Initialize();
initcaller();
call_quack();
Py_Finalize();
return 0;
}
When I run this I get this exception:
Exception NameError: "name 'quack' is not defined" in 'caller.call_quack' ignored
The missing pieces I'm suspecting:
I haven't called initquacker()
I haven't included quacker.h
Cython didn't produce any quacker.h - only quacker.c
caller.c doesn't import quacker.h or call initquacker()
I'm not really sure that it's even possible to do what I'm trying to do, but it seems to me that it ought to be. I'd love to hear any input you might have.
Edit:
This is how I cythonize / compile / link / run:
$ cython *.pyx
$ cc -c *.c -I/System/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7
$ cc -L/System/Library/Frameworks/Python.framework/Versions/2.7/lib -L/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/config -lpython2.7 -ldl *.o -o main
$ ./main
If you rename the quacker.pyx to quacker.py, everything is actually correct. The only problem is that your program won't search for python modules in the current directory, resulting in the output:
Exception NameError: "name 'quack' is not defined" in 'caller.call_quack' ignored
If you add the current directory to the PYTHONPATH environment variable however, the output becomes the one you'd expect:
$ PYTHONPATH=".:$PYTHONPATH" ./main
Quack!
When running the python shell, according to the documentation the current directory (or the directory containing the script) is added to the sys.path variable automatically, but when creating a simple program using Py_Initialize and Py_Finalize this does not seem to happen. Since the PYTHONPATH variable is also used to populate the sys.path python variable, the workaround above produces the correct result.
Alternatively, below the Py_Intialize line, you could add an empty string to sys.path as follows by just executing some python code, specified as a string:
PyRun_SimpleString("import sys\nsys.path.insert(0,'')");
After recompiling, just running ./main should then work.
Edit
It's actually interesting to see what's going on if you run the code as specified in the question, so without renaming the quacker.pyx file. In that case, the initcaller() function tries to import the quacker module, but since no quacker.py or quacker.pyc exists, the module cannot be found, and the initcaller() function produces an error.
Now, this error is reported the python way, by raising an exception. But the code in the main.c file doesn't check for this. I'm no expert in this, but in my tests adding the following code below initcaller() seemed to work:
if (PyErr_Occurred())
{
PyErr_Print();
return -1;
}
The output of the program then becomes the following:
Traceback (most recent call last):
File "caller.pyx", line 1, in init caller (caller.c:836)
from quacker import quack
ImportError: No module named quacker
By calling the initquacker() function before initcaller(), the module name quacker already gets registered so the import call that's done inside initcaller() will detect that it's already loaded and the call will succeed.
In case there's anyone wondering how would it work in Python 3, here's my solution after struggling a bit as a Cython newbie.
main.c
#include <Python.h>
#include "caller.h"
int
main()
{
PyImport_AppendInittab("caller", PyInit_caller);
Py_Initialize();
PyImport_ImportModule("caller");
call_quack();
Py_Finalize();
return 0;
}
caller.pyx
# cython: language_level=3
import sys
sys.path.insert(0, '')
from quacker import quack
cdef public void call_quack():
quack()
quacker.py
def quack():
print("Quack!")
Finally, here's the Makefile that compiles everything:
target=main
cybridge=caller
CC=gcc
CFLAGS= `python3-config --cflags`
LDFLAGS=`python3-config --ldflags`
all:
cython $(cybridge).pyx
$(CC) $(CFLAGS) -c *.c
$(CC) $(LDFLAGS) *.o -o $(target)
clean:
rm -f $(cybridge).{c,h,o} $(target).o $(target)
rm -rf __pycache__
Maybe this is not what you want but I got it working by the following changes:
in quacker.pyx I added
cdef public int i
To force Cython to generate the .h file.
An then in the main:
#include <Python.h>
#include "caller.h"
#include "quacker.h"
int main() {
Py_Initialize();
initquacker();
initcaller();
call_quack();
Py_Finalize();
return 0;
}
I needed to do this using CMake and ended up recreating this sample. You can find the repository with complete working example here.
You can build and run the example using either Docker on the CLI or a Visual Studio devcontainer.

SWIG error: Using libnfc.c on python

I'm trying to use the C library libnfc for NFC Devices on python (http://nfc-tools.org/). With C I can run the example program and it works fine. I downloaded the package (https://code.google.com/p/pynfc/), which should allow to use the library on python and run the command "sudo python setup.py build_ext", like it is told in the README, but I get the following error:
running build_ext
building '_nfc' extension
swigging nfc.i to nfc_wrap.c
swig -python -I/usr/include -module nfc -interface _nfc -O -o nfc_wrap.c nfc.i
nfc/nfc.h:1489: Error: Syntax error in input(3).
error: command 'swig' failed with exit status 1
This is the content of nfc.h:
typedef struct {
PyObject_HEAD
void *ptr; // <- line 1489
swig_type_info *ty;
int own;
PyObject *next;
#ifdef SWIGPYTHON_BUILTIN
PyObject *dict;
#endif
} SwigPyObject;
I'm using Linux Mint 15.
Thanks to everyone who takes the time to read this!
SWIG is a software development tool that connects programs written in C and C++ with a variety of high-level programming languages.
So, just try:
apt-get install swig

Categories

Resources