Pybind11: Cross compilation workflow

Created on 21 Mar 2018  路  10Comments  路  Source: pybind/pybind11

Howdy!

Say I have a cross-compiled python setup and want to build against that. Currently pybind appears to be tightly coupled to the system python in it's cmake configuration.

How could this be approached? I'm happy to work on this and submit a PR.

My use case is building native modules for aarch64-linux-gnu in a relatively controlled environment.

All 10 comments

Related to #99

I鈥檓 cross compiling with yocto, this fails because the find package executes python to get the path, but the target system ist not available aka cmake executes python on the host..

A workaround would be to forget about Pybind11's cmake and just add the header directory in your own cmake (or whatever).

Did you ever find a way to get this up and running? I'm in a similar situation: I'd like to build an extension for a 32-bit ARM target using as close to the standard CMake workflow as possible, but am running into issues because the system python is 64-bit.

No, i did not, though did not invest much time on it.. right now im just using systemd and dbus to launch python scripts on the target board

Hi, I also have the same issue, I'm cross compiling for ARM on an intel machine, and pybind11 finds the Python installation for the host, so of course the build fails:

CMake Error at deps-base/pkg-pybind11/src/tools/FindPythonLibsNew.cmake:125 (message):
  Python config failure: Python is 64-bit, chosen compiler is 32-bit
Call Stack (most recent call first):
  deps-base/pkg-pybind11/src/tools/pybind11Tools.cmake:16 (find_package)
  deps-base/pkg-pybind11/src/CMakeLists.txt:33 (include)

Any indication on how to direct pybind11 to the python installation for the target?

I ended up just commenting out the bit-width check in FindPythonLibsNew.cmake (lines 121-131) - hacky, but the only solution I could find.

The order of inclusion of pybind11 and Python in CMake also has a few gotchas that need to be noted, see https://github.com/pybind/pybind11/blob/master/docs/faq.rst#user-content-inconsistent-detection-of-python-version-in-cmake-and-pybind11.

Hi, thanks for the above hint about inclusion order!
Yes commentig out the check can work in some cases, but fails in others, as the target platform might have a different python version from the host or no python installation at all.

On build machine you can work-around this by doing

dpkg --add-architecture i386
apt install -y python2.7:i386

You maybe need to remove amd64 package of python too.

But my full solution was building a docker image with necessary dev packages and tools to keep host machine clean. Assuming, following files are in the same directory, run build-docker.sh

Dockerfile

FROM ubuntu:18.04

RUN dpkg --add-architecture i386
RUN apt update.
RUN apt install -y debootstrap python2.7:i386 cmake make build-essential binutils-arm-linux-gnueabihf \
gcc-6-arm-linux-gnueabihf g++-6-arm-linux-gnueabihf debootstrap qemu-user-static

ENV SYSROOT=/sysroot
RUN mkdir ${SYSROOT}
RUN debootstrap --foreign --variant=minbase --arch=armhf stretch "${SYSROOT}" http://deb.debian.org/debian/
RUN cp /usr/bin/qemu-arm-static "${SYSROOT}"/usr/bin/ && cp /etc/resolv.conf "${SYSROOT}"/etc/
RUN apt-get clean

RUN mkdir /build
WORKDIR /build

Build docker image build-docker.sh

#!/bin/bash
set -e
SOURCE_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $SOURCE_DIR/

docker run --privileged linuxkit/binfmt:v0.6

docker build -t image:latest .

docker run --privileged -it image:latest /bin/sh -c 'chroot /sysroot /debootstrap/debootstrap --second-stage'
docker commit `docker ps -l --format="{{.ID}}"` image:latest
docker run --privileged -it image:latest /bin/sh -c 'chroot /sysroot apt install \
--allow-unauthenticated -y libc6-dev libjsoncpp-dev libboost-filesystem-dev libboost-regex-dev \
libboost-python-dev libboost-thread-dev libboost-date-time-dev libboost-program-options-dev libssl-dev libz-dev && apt-get clean'
docker commit `docker ps -l --format="{{.ID}}"` image:latest

later-on you can use it with

docker run  -it --rm -v "$(pwd)":/build image:latest /bin/bash

and issue cmake/build from container's /build directory

At the end I've been able to generate a python wrapper with pybind11 also when cross compiling.
In cross compilation mode pybind11 needs the python include and libraries of the target installation, not the ones of the host. The point is that when cross-compiling one normally already have a root file system of the target with everything installed (at least this is my case) the point is how to direct pybind11 to this installation.

It turns out this can be done quite easily, no need to change pybind11 build system, I just added a couple of variables in my own cmake before including pybind11:

# Tell pybind11 where the target python installation is
set(PYTHON_INCLUDE_DIRS ${MY_TARGET_PYTHON_INCLUDE_DIRS} CACHE INTERNAL "Cross python include path")
set(PYTHON_MODULE_EXTENSION ".so" CACHE INTERNAL "Cross python lib extension")

# Disable pybind11 python search mechanism
set(PYTHONLIBS_FOUND TRUE CACHE INTERNAL "")

# include pybind11 cmake
add_subdirectory(pybind11)

At the end I've been able to generate a python wrapper with pybind11 also when cross compiling.

I'll interpret this as "issue resolved". Thanks for the write-up of your solution!

Was this page helpful?
0 / 5 - 0 ratings