Python FFI through Boost.Python

A simple python FFI example on OpenBSD and macOS.

The program is a minimal example for Boost.Python.

#include <iostream>
#include <boost/python.hpp>
#include <boost/python/module_init.hpp>

using namespace boost::python;

void greet() {
	// Retrieve the main module.
	object main = import("__main__");

	// Retrieve the main module's namespace
	object global(main.attr("__dict__"));

	// Define greet function in Python.
	object result = exec("def greet():                   \n"
			"\timport sys \n"
			"\tprint(sys.version_info)\n"
			"\treturn 'Hello from Python 3!' \n", global, global);

	// Create a reference to it.
	object greet = global["greet"];

	// Call it.
	std::string message = extract < std::string > (greet());
	std::cout << message << std::endl;
}

int main(int argc, char* argv[]) {
	Py_Initialize();
	greet();
	Py_Finalize();
	return 0;
}

It seems that compilation and running a program on OpenBSD and macOS differ a lot ...

OpenBSD

Install boost

pkg_add boost

Compile

c++ -I /usr/local/include/ 
    -I /usr/local/include/python3.7m/ 
    -L/usr/local/lib
    -lboost_python3
    -lpython3.7m
    ./hellopython.cpp

Run

./a.out

macOS

Install boost with brew

sudo brew install boost-python3

Compile on macOS assuming miniconda was used to get 3.8

conda activate py38

c++ -I /Users/peter/opt/miniconda3/envs/py38/include/python3.8/ 
    -I /usr/local/Cellar/boost/1.73.0/include/
    -L /usr/local/Cellar/boost-python3/1.73.0/lib/
    -L /Users/peter/opt/miniconda3/envs/py38/lib/
    -lboost_python38
    -lpython3.8
    ./hellopython.cpp

Resulting binary has relative library paths. Fix that

Check library references. rpath is relative path

otool -L a.out

Correct paths with install_name_tool

install_name_tool -change @rpath/libc++.1.dylib /usr/lib/libc++.1.dylib a.out
install_name_tool -change @rpath/libpython3.8.dylib
    Users/peter/opt/miniconda3/envs/py38/lib/libpython3.8.dylib a.out

Check that references match your system

To run the binary with miniconda paths you need to set PYTHONPATH

export PYTHONPATH=/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/

Finally run the binary

./a.out