I am just getting started with gcc on Linux. I am following the tutorial here, except that I am using the g++ compiler.
hello_fn.cpp
#include <stdio.h>
#include "hello.h"
void
hello (const char * name)
{
printf ("Hello, %s!\n", name);
}
bye_fn.cpp
#include <stdio.h>
#include "hello.h"
void
bye (void)
{
printf ("Goodbye!\n");
}
hello.h
void hello (const char * name);
void bye (void);
I then run the following in the shell:
$ g++ -Wall -c hello_fn.cpp
$ g++ -Wall -c bye_fn.cpp
$ ar cr libhello.a hello_fn.o bye_fn.o
Then I try the following from python:
Python 2.7.1+ (r271:86832, Apr 11 2011, 18:05:24)
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import ctypes
>>> test = ctypes.cdll.LoadLibrary(r'/home/oob/development/libtest/libhello.a')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.7/ctypes/__init__.py", line 431, in LoadLibrary
return self._dlltype(name)
File "/usr/lib/python2.7/ctypes/__init__.py", line 353, in __init__
self._handle = _dlopen(self._name, mode)
OSError: /home/jeff/development/libtest/libhello.a: invalid ELF header
My idea was to write some functions in c++ and call them from Python. Any ideas?
UPDATE: I was able to get things "working". Based on what Cat Plus Plus said, I may not go this direction for new code, but I was able to get this to work with a large legacy c++ library that I was porting from Windows to Linux. We need a frontend to call some long running functions from this library, so I thought Python might be easiest. The functions create a lot of output and only return an integer return code, so maybe I can avoid the "painful" stuff Cat Plus Plus was saying.
Here is what I did.
Modified hello_fn.cpp
#include <stdio.h>
#include "hello.h"
extern "C" int
hello (void)
{
return 16;
}
Modified by_fn.cpp
#include <stdio.h>
#include "hello.h"
extern "C" void
bye (void)
{
printf ("Goodbye!\n");
}
Modified hello.h
extern "C" int hello (void);
extern "C" void bye (void);
buildscript.sh
#!/bin/bash
rm *.o
rm *.so
g++ -fpic -g -c -Wall hello_fn.cpp
g++ -fpic -g -c -Wall bye_fn.cpp
#make a shared library, not a static library (thanks cat plus plus)
g++ -shared -o libhello.so hello_fn.o bye_fn.o
test.py
#!/usr/bin/python
import ctypes
c = ctypes.cdll.LoadLibrary(r'/home/jeff/development/libtest/libhello.so')
a = c.hello()
print 'hello was ' + str(a)
c.bye()
Try it in the terminal....
oob@ubuntu:~/development/libtest$ ./build_script.sh
oob@ubuntu:~/development/libtest$ python test.py
hello was 16
Goodbye!
Our legacy library doesn't really use any windows-specific c++ stuff (thanks to the guy who wrote that code), so it has been a pretty easy port. We had several functions that used extern "C" to expose functions. For the port, I have made the following changes:
#ifdef LINUX
#define __stdcall
#endif
#ifdef WINDOWS
#define __stdcall __stdcall
#endif
And for one of our functions, I can just leave it unchanged, for example:
extern "C" long __stdcall reform_proj {
//do a bunch of stuff
return 0;
}
ctypes is for loading shared libraries. ar creates archives of object files, also known as static libraries. You can't load that file with ctypes, it will only be understood by the linker.
Another issue is that using C++ shared libraries via ctypes is painful if not downright impossible. Just don't. Use Cython instead, and write a proper Python extension that interfaces with your C++ code (then you can link it either statically or dynamically, and it'll work).
Another option is Boost.Python, but it's somewhat less documented, but has a benefit of defining Python module directly in your C++ code, instead of using wrappers written in another language.
Third is SWIG, but I've never used it, so can't tell you how well it works in practice.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With