All of these files should be placed in one directory.
mkdir build && cd build
cmake ..
make
cd ..
python3 ./load_libs.py
#include <boost/python.hpp> | |
#include <boost/python/raw_function.hpp> | |
#include "CppClasses.hpp" | |
namespace python = boost::python; | |
// Converter needed for handling vectors (or lists) returned by C++ methods | |
template <class T> struct VecToList | |
{ | |
static PyObject *convert(const std::vector<T> &vec) | |
{ | |
boost::python::list *l = new boost::python::list(); | |
for (auto &&i : vec) | |
{ | |
l->append(i); | |
} | |
return l->ptr(); | |
} | |
}; | |
//Raw cpp function | |
char const* greeter(){ | |
return "hello World! from outside class"; | |
}; | |
std::vector<int> get_list() | |
{ | |
std::vector<int> v; | |
v.push_back(1); | |
v.push_back(2); | |
return v; | |
} | |
//Boost.Python wrapper defining the module name, classes and methods | |
BOOST_PYTHON_MODULE(bindings){ | |
python::class_<Hello>("Hello") | |
//.def(init<double, double>()) //another constructor if needed | |
.def("greet",&Hello::greet) //simple methods | |
.def("set",&Hello::set) | |
//.def_readonly("len", &Hello::len) //access to class fields | |
.def_readwrite("len", &Hello::len) | |
; | |
python::class_<Class2>("Class2",python::no_init) | |
.def(python::init<int>()); | |
python::def("print_hello", greeter); | |
python::def("get_list", get_list); | |
//using lists returned by C++ needs defining converter handling this type of variable | |
python::to_python_converter<std::vector<int, std::allocator<int>>, VecToList<int>>(); | |
} |
cmake_minimum_required(VERSION 3.5) | |
project(cpp_to_pyt_bindings) | |
# Find python and Boost - both are required dependencies | |
find_package(PythonLibs 3.5 REQUIRED) | |
find_package(Boost COMPONENTS python REQUIRED) | |
# Without this, any build libraries automatically have names "lib{x}.so" | |
set(CMAKE_SHARED_MODULE_PREFIX "") | |
file(GLOB_RECURSE HEADERS ${CMAKE_SOURCE_DIR} "*.hpp") | |
file(GLOB_RECURSE SOURCES ${CMAKE_SOURCE_DIR} "*.cpp") | |
include_directories( | |
${CMAKE_HOME_DIRECTORY}/include | |
) | |
# Add a shared module - modules are intended to be imported at runtime. | |
# - This is where you add the source files | |
add_library(bindings MODULE ${HEADERS} ${SOURCES} ) | |
# Set up the libraries and header search paths for this target | |
target_link_libraries(bindings ${Boost_LIBRARIES} ${PYTHON_LIBRARIES}) | |
target_include_directories(bindings PRIVATE ${PYTHON_INCLUDE_DIRS}) |
#include <string> | |
#include <iostream> | |
//example of class without default constructor | |
class Class2{ | |
public: | |
Class2(int number){}; | |
}; | |
class Hello{ | |
private: | |
std::string msg; | |
public: | |
std::string greet(){ | |
std::cout << "Hello World!\n"; | |
return msg; | |
} | |
//Set the message string | |
void set(std::string text){ | |
this->msg = text; | |
} | |
int len; //public data member | |
}; |
#!/usr/bin/python3 | |
import os | |
import sys | |
module_path = os.path.dirname(os.path.realpath(__file__)) + "/build/" | |
sys.path.append(module_path) | |
try: | |
from bindings import * | |
print("Library imported") | |
except: | |
print("Something went wrong during import") | |
print("__file__ : " + __file__) | |
print("sys.path: " + str(sys.path)) | |
print_hello() | |
get_list() | |
h = Hello() | |
h.set("Hi") | |
h.greet() | |
h.len = 50 | |
print("h.len: ", h.len) | |
c2 = Class2(88) |
Expected result:
Library imported
Hello World!
h.len: 50