python code to c++ lib or dll - c++

I have some python code that I want to use from C++, I want to build it in lib or dll? how can I do it?
code have dependencies:
import socket
import string
import struct
import sys
and maybe PIL

You can use cython and write thin wrapper to export it to C
Cython lib helloWorld.pyx:
import sys
sys.path.append(".") #yourlib is in current folder
import yourlib #you can import any python module
cdef public void helloWorld():
print "Hello World Cython!"
yourlib.helloWorld("Python")
cdef public int my_sum(int x, int y):
return x*x+y
from libcpp.string cimport string
cdef public string testString( string sx, string sy ):
x = int(sx.c_str())
y = int(sy.c_str())
ret= "%d*%d+%d=%d"%(x,x,y,my_sum(x,y))
cdef char* ret2= ret
return string( ret2 )
Compile with cython (create helloWorld.cpp, helloWorld.h):
cython --cplus helloWorld.pyx
Your code program.cpp:
#include <string>
#include <iostream>
#include "Python.h"
#include "helloWorld.h" // it's cpp header so remove __PYX_EXTERN_C (bug)
int main(int argc, char *argv[]) {
Py_Initialize(); //start python interpreter
inithelloWorld(); //run module helloWorld
helloWorld();
std::cout << testString("6","6") << std::endl; #it's fast!
Py_Finalize();
return 0;
}
Compile and run:
g++ program.cpp helloWorld.cpp -I/usr/include/python2.7/ -lpython2.7
./a.out
Hello World Cython!
Hello World Python!
6*6+6=42
Another way is to use boost::python
Your code program.cpp:
#include <string>
#include <iostream>
#include <boost/python.hpp>
int main(int argc, char *argv[]) {
Py_Initialize();
boost::python::object sys = boost::python::import("sys");
sys.attr("path").attr("append")(".");
boost::python::object main_module = boost::python::import("yourlib");
main_module.attr("helloWorld")("boost_python");
boost::python::object ret= main_module.attr( "my_sum" )( 10, 10 );
std::cout << boost::python::extract<char const*>(ret) << std::endl;
Py_Finalize();
return 0;
}
Compile and run:
g++ program.cpp -I/usr/include/python2.7/ -lpython2.7 -lpython_boost
./a.out
Hello World boost_python!
10*10+10=110

You might want to check how to embed python in another application (http://docs.python.org/extending/embedding.html).

Related

Fails to load Python module with Python 3

#include <Python.h>
#include <fstream>
#include <iostream>
#include <string>
#include <filesystem>
#include <sys/types.h>
#include <dirent.h>
static const char * sPythonCode =
"class Test :\n"
" def __init__(self) : \n"
" self.Disc_ = 0. \n"
" def getset(self) : \n"
" self.Disc_ = 7. \n"
" return self.Disc_ \n";
std::string writeFile()
{
static int iFile = 0;
std::string sFileName(std::string("test") + std::to_string(iFile));
std::ofstream out("py/" + sFileName + ".py");
out << sPythonCode;
out.flush();
out.close();
iFile++;
return sFileName;
}
static bool bPythonOpen = false;
#define PYTHONPATHLEN 501
static void _PyInit()
{
if (!Py_IsInitialized())
{
Py_InitializeEx(0);
}
}
void openPython(void)
{
if (!bPythonOpen)
{
const size_t szBufferN = 1000;
char acLoadPath[szBufferN];
const char *pypath = "./py";
_PyInit();
PyRun_SimpleString("import sys");
PyRun_SimpleString("print('python (%d.%d.%d) initialized' % (sys.version_info.major, sys.version_info.minor, sys.version_info.micro))");
PyRun_SimpleString("print('--------------------------')");
snprintf(acLoadPath, szBufferN, "sys.path.append('%s')", pypath);
PyRun_SimpleString(acLoadPath);
bPythonOpen = true;
}
}
PyObject *loadPythonModule(const char *acModule)
{
PyObject *pyModule = NULL;
if (bPythonOpen && acModule && strcmp(acModule, ""))
{
printf("%s\n", acModule);
pyModule = PyImport_ImportModule(acModule);
if (!pyModule)
{
PyErr_Print();
}
}
return pyModule;
}
void loadPython()
{
std::string sFileName = writeFile();
openPython();
//sleep(1);
PyObject *pPythonModule = loadPythonModule(sFileName.c_str());
if (pPythonModule)
PyDict_DelItemString(PyImport_GetModuleDict(), PyModule_GetName((PyObject *)pPythonModule));
}
int main(int argc, char **argv)
{
for (int i = 0; i < 10; i++)
{
loadPython();
}
}
My working env:
gcc version 8.3.1 20190311 (Red Hat 8.3.1-3) (GCC)
Red Hat Enterprise Linux Server release 7.6 (Maipo)
problem with python 3.6.10 / 3.8.3
Command to compile:
g++ pythontest.cpp -I/opt/python/python3.6.10/include/python3.6m -L/opt/python/python3.6.10/lib -lpython3.6m
create py directory:
mkdir py
When I run this code I have random error on different test file that I load.
Example of output:
python (3.6.10) initialized
--------------------------
test0
test1
test2
test3
ModuleNotFoundError: No module named 'test3'
test4
test5
ModuleNotFoundError: No module named 'test5'
test6
test7
ModuleNotFoundError: No module named 'test7'
test8
test9
ModuleNotFoundError: No module named 'test9'
Good to know:
If I uncomment the line with the sleep it works well
If I remove the iFile++, it works also as it used after an already created file
If I relaunch a second without rm -rf py directory it works also
If I erase file after each run in the loadPython function and remove iFile++ it works also
If I use strace to launch the executable I don't see the problem
For the moment it seems that the Python loader does not see the file on disk, however in case of failure if I print what I have in the directory thanks to dirent I see the testx.py
Please note that we reproduce the error on different Linux servers (not a hardware problem and even on Windows), with Python 2.7.x it works perfectly well.
You should call __import__('importlib').invalidate_caches() each time you modify modules folders to let C Python knows it must read directories again.

Linking against libuv

I wanted to try using libuv in dlang. I downloaded the dlang bindings like this:
git clone git#github.com:tamediadigital/libuv.git
Now what I do next to get my "hello world" running?
I tried this:
ldc2 hello.d -luv
But it said:
ldc2: Unknown command line argument '-luv'. Try: 'ldc2 -help'
ldc2: Did you mean '-v'?
I think I need to tell the compiler where the library bindings are located.
And then import something in the source code, probably with import libuv;?
Here is the 'hello world' code I want to "port" to D:
#include <stdio.h>
#include <stdlib.h>
#include <uv.h>
int main() {
uv_loop_t *loop = malloc(sizeof(uv_loop_t));
uv_loop_init(loop);
printf("Now quitting.\n");
uv_run(loop, UV_RUN_DEFAULT);
uv_loop_close(loop);
free(loop);
return 0;
}
Here is the bindings github page: https://github.com/tamediadigital/libuv
Library home page: http://www.libuv.org
First that was a wrong bindings, here are the good ones: https://github.com/changloong/libuv
Assuming you did git clonegit#github.com:changloong/libuv.git in current dir.
Compile:
ldc2 hello.d -I=libuv/deimos/libuv/ -I=libuv/ -L=-luv
The source:
import uv;
import core.memory;
import std.stdio;
int main(){
uv_loop_t *loop = new uv_loop_t;
uv_loop_init(loop);
printf("Now quitting.\n");
uv_run(loop, uv_run_mode.UV_RUN_DEFAULT);
uv_loop_close(loop);
return 0;
}
Hope it helps someone to get started with using C libs in D.

How to print to Python terminal with Boost::Python

I would like to do the equivalent of a print in python from a library I wrote in C++. I am using Boost 1.60.0 and Python 2.7.
I found the following sites :Mantid and WikiBooks. From what I understood this code should work, but nothing is printed.
cpp file
void greet()
{
std::cout<<"test_01\n";
std::cout<<"test_02"<<std::endl;
printf("test_03");
}
BOOST_PYTHON_MODULE(PythonIntegration)
{
def("greet", greet);
}
py file
import PythonIntegration
PythonIntegration.greet()
I checked if the function was called by making it return something and it works, but still nothing is printed.
Thank you for your help
This hello world example seems to do exactly what you want : https://en.wikibooks.org/wiki/Python_Programming/Extending_with_C%2B%2B
Basically...
C++
#include <iostream>
using namespace std;
void say_hello(const char* name) {
cout << "Hello " << name << "!\n";
}
#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
using namespace boost::python;
BOOST_PYTHON_MODULE(hello)
{
def("say_hello", say_hello);
}
Now, in setup.py
#!/usr/bin/env python
from distutils.core import setup
from distutils.extension import Extension
setup(name="PackageName",
ext_modules=[
Extension("hello", ["hellomodule.cpp"],
libraries = ["boost_python"])
])
Now you can do this :
python setup.py build
Then at the python command prompt :
>>> import hello
>>> hello.say_hello("World")
Hello World!

Using numpy on an embedded python interpreter using VS2008 under Windows 7

Let's take a look at my project.
I'm using Visual Studio 2008, Python 2.7 and numpy 1.8.1 (but I have tried several versions and none worked). My project is being compiled on debug mode.
It's a very simple code:
/* = Main.cpp file = */
#include "stdafx.h"
#include "Python.h"
int _tmain(int argc, _TCHAR* argv[])
{
PyObject *pName, *main;
Py_Initialize();
pName = PyUnicode_FromString("main");
main = PyImport_Import(pName);
Py_XDECREF(pName);
if (main != NULL)
{
printf("Python Module Loaded!!\n");
}
else
{
printf("Unable to load Python Module!!\n");
}
return 0;
}
And
""" = Main.py file = """
print 'Hello World!'
If I execute this code, I get:
As it is expected.
My problem arises as soon as I change main.py into:
""" = Main.py file = """
import numpy
print 'Hello World!'
Then I get the:
I have tried to run main.py separately on a python interpreter (not embedding it into C++) and then everything works just fine:
I have also tried a modification on the main.cpp as follows:
#include "stdafx.h"
#include "Python.h"
int _tmain(int argc, _TCHAR* argv[])
{
PyObject *pName, *main;
Py_Initialize();
PyRun_SimpleString("import numpy");
return 0;
}
From this code the output is:
Finally I also tried compiling original version of main.cpp code in release mode and then the output is:
So, my question here is: What can I do to get numpy working under debug compilations using an embedded interpreter on Visual Studio 2008?
You know you have to have use a python debug version built don't you? That is probably your problem. (I would leave a comment but no rep ): )

Attribute error while using methods from linked libraries in python

I'm trying to use some C++ method in my python code and I'm using ctypes library. I have wrote a simple C++ code using a simple main with no arguments and another simple method named printArgs which takes an argument of type char *. I also have wrote a simple python code to import these two methods. I made two linked libraries(one .so and one .a because I'm using Debian) with this command:
g++ -o hello.so -shared -fPIC hello.cpp
And then used export LD_LIBRARY_PATH=/the/path/to/the/linked/libraries/directory.
There is no problem in getting the main method, bu when I'm trying to get printArgs I get AttributeError. Here's the C++ code:
#include <iostream>
using namespace std;
int printArgs(char * args_array){
for (int i = 0; i < 5; i++){
cout<<i<<"- "<<args_array[i]<<"\n";
}
return 0;
}
int main(){
cout<<"Hello\n";
return 0;
}
Here's the Python code:
from ctypes import *
helloInCPP_lib = cdll.LoadLibrary("hello.a")
print helloInCPP_lib
helloInCPPMain = helloInCPP_lib.main
print helloInCPPMain
helloInCPPPrint = helloInCPP_lib.printArgs
print helloInCPPPrint
I get this output:
<CDLL 'hello.a', handle 9c45488 at b73d1e6c>
<_FuncPtr object at 0xb73e67e4>
Traceback (most recent call last):
File "testHelloInCPP.py", line 9, in <module>
helloInCPPPrint = helloInCPP_lib.printArgs(None)
File "/usr/lib/python2.6/ctypes/__init__.py", line 366, in __getattr__
func = self.__getitem__(name)
File "/usr/lib/python2.6/ctypes/__init__.py", line 371, in __getitem__
func = self._FuncPtr((name_or_ordinal, self))
AttributeError: /etc/linked_libraries/hello.a: undefined symbol: printArgs
I also tried cdll.LoadLibrary("hello.so") and/or helloInCPPPrint = helloInCPP_lib.printArgs(None); got the same error in both conditions. Any idea?
I'm using Debian 32 bit on a VMWare Workstation and Python 2.6.
Declare the printArgs using extern "C":
#include <iostream>
using namespace std;
extern "C" {
int printArgs(char * args_array);
}
int printArgs(char * args_array){
for (int i = 0; i < 5; i++){
cout<<i<<"- "<<args_array[i]<<"\n";
}
}
int main(){
cout<<"Hello\n";
}
BTW, you should pass a string (c_char_p), not None:
...
helloInCPPPrint = helloInCPP_lib.printArgs
helloInCPPPrint.argtypes = [c_char_p]
print helloInCPPPrint("ABCDE")
About argtypes, see Specifying the required argument types (function prototypes).
I tired compiling the solution by #falsetru using
g++ -O3 -shared -std=c++11 -fPIC code.cpp -o lib.so
but could not without this small modification to code.c, according to the link provided in their answer extern "C":
#include <iostream>
using namespace std;
extern "C" int printArgs(char * args_array){
for (int i = 0; i < 5; i++){
cout<<i<<"- "<<args_array[i]<<"\n";
}
}