Skip to content

Instantly share code, notes, and snippets.

@pktiuk
Last active February 8, 2021 22:17
Show Gist options
  • Save pktiuk/2136eeefaf4271510d82e59f90c904ce to your computer and use it in GitHub Desktop.
Save pktiuk/2136eeefaf4271510d82e59f90c904ce to your computer and use it in GitHub Desktop.
C++ used in python using Boost and CMake

Simple Cmake project showing python bindings for code written in C++

All of these files should be placed in one directory.

Compilation

mkdir build && cd build
cmake ..
make

Running

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment