Cross building

Cross building is compiling a library or executable in one platform to be used in a different one.

Cross-compilation is used to build software for embedded devices where you don’t have an operating system nor a compiler available. Also for building software for not too fast devices, like an Android machine, a Raspberry PI etc.

To cross build code you need the right toolchain. A toolchain is basically a compiler with a set of libraries matching the host platform.

GNU triplet convention

According to the GNU convention, there are three platforms involved in the software building:

  • Build platform: The platform on which the compilation tools are executed
  • Host platform: The platform on which the code will run
  • Target platform: Only when building a compiler, this is the platform that the compiler will generate code for

When you are building code for your own machine it’s called native building, where the build and the host platforms are the same. The target platform is not defined in this situation.

When you are building code for a different platform, it’s called cross building, where the build platform is different from the host platform. The target platform is not defined in this situation.

The use of the target platform is rarely needed, only makes sense when you are building a compiler. For instance, when you are building in your Linux machine a GCC compiler that will run on Windows, to generate code for Android. Here, the build is your Linux computer, the host is the Windows computer and the target is Android.

Conan settings

From version 1.0, Conan introduces new settings to model the GNU convention triplet:

build platform settings:

  • os_build: Operating system of the build system.
  • arch_build: Architecture system of the build system.

These settings are detected the first time you run Conan with the same values than the host settings, so by default, we are doing native building. Probably you will never need to change the value of this settings because they describe where are you running Conan.

host platform settings:

  • os: Operating system of the host system.
  • arch: Architecture of the host system.
  • compiler: Compiler of the host system (to declare compatibility of libs in the host platform)
  • … (all the regular settings)

These settings are the regular Conan settings, already present before supporting the GNU triplet convention. If you are cross building you have to change them according to the host platform.

target platform:

  • os_target: Operating system of the target system.
  • arch_target: Architecture of the target system.

If you are building a compiler, specify with these settings where the compiled code will run.

Cross building with Conan

If you want to cross-build a Conan package, for example, in your Linux machine, build the zlib Conan package for Windows, you need to indicate to Conan where to find your cross-compiler/toolchain.

There are two approaches:

  • Install the toolchain in your computer and use a profile to declare the settings and point to the needed tools/libraries in the toolchain using the [env] section to declare, at least, the CC and CXX environment variables.
  • Package the toolchain as a Conan package and include it as a build_require.

Using profiles

Create a profile with:

  • A [settings] section containing the needed settings: os_build, arch_build and the regular settings os, arch, compiler, build_type and so on.
  • An [env] section with a PATH variable pointing to your installed toolchain. Also any other variable that the toolchain expects (read the docs of your compiler). Some build systems need a variable SYSROOT to locate where the host system libraries and tools are.

Linux to Windows

  • Install the needed toolchain, in ubuntu:

    sudo apt-get install g++-mingw-w64 gcc-mingw-w64

  • Create a file named linux_to_win64 with the contents:

[env]
# Where is our C compiler
CC=/usr/bin/x86_64-w64-mingw32-gcc
# Where is our CPP compiler
CXX=/usr/bin/x86_64-w64-mingw32-g++

[settings]
# We are building in Ubuntu Linux
os_build=Linux
arch_build=x86_64

# We are cross building to Windows
os=Windows
arch=x86_64
compiler=gcc
# Adjust to the gcc version of your MinGW package
compiler.version=6.3
compiler.libcxx=libstdc++11
build_type=Release
  • Clone an example recipe or use your own recipe:
git clone https://github.com/memsharded/conan-hello.git
  • Call conan create using the created profile.win
$ cd conan-hello && conan create . conan/testing --profile ../linux_to_win64
...
[ 50%] Building CXX object CMakeFiles/example.dir/example.cpp.obj
[100%] Linking CXX executable bin/example.exe
[100%] Built target example

A bin/example.exe for Win64 platform has been built.

Windows to Raspberry PI

  • Install the toolchain: http://gnutoolchains.com/raspberry/ You can choose different versions of the GCC cross compiler, choose one and adjust the following settings in the profile accordingly.
  • Create a file named win_to_rpi with the contents:
[settings]
os_build=Windows
arch_build=x86_64
os=Linux
arch=armv7hf
compiler=gcc
compiler.version=6.3  # We have chosen gcc 6.3 installer
compiler.libcxx=libstdc++11
build_type=Release

[env]
CC=arm-linux-gnueabihf-gcc
CXX=arm-linux-gnueabihf-g++

The downloaded toolchain is an installer that puts the compilers in the path, so we can just specify the executable name in the CC and CXX variables.

  • Clone an example recipe or use your own recipe:
git clone https://github.com/memsharded/conan-hello.git
  • Call conan create using the created profile.
$ cd conan-hello && conan create . conan/testing --profile=../win_to_rpi
...
[ 50%] Building CXX object CMakeFiles/example.dir/example.cpp.obj
[100%] Linking CXX executable bin/example
[100%] Built target example

A bin/example for Raspberry PI (Linux/armv7hf) platform has been built.

Linux/Windows/Macos to Android

Cross bulding a library for Android is very similar to the previous examples, except the complexity of managing different architectures (armeabi, armeabi-v7a, x86, arm64-v8a) and the Android API levels.

Download the Android NDK here and unzip it.

Note

If you are in Windows the process will be almost the same, but unzip the file in the root folder of your hard disk (C:) to avoid issues with path lengths.

Now you have to build a standalone toolchain, we are going to target “arm” architecture and the Android API level 21, change the --install-dir to any other place that works for you:

$ cd build/tools
$ python make_standalone_toolchain.py --arch=arm --api=21 --stl=libc++ --install-dir=/tmp/arm_21_toolchain

Note

You can generate the standalone toolchain with several different options to target different architectures, api levels etc.

Check the Android docs: standalone toolchain

To use the clang compiler, create a profile android_21_arm_clang with the following contents:

standalone_toolchain=/tmp/arm_21_toolchain # Adjust this path
target_host=arm-linux-androideabi

[settings]
compiler=clang
compiler.version=5.0
compiler.libcxx=libc++
os=Android
os.api_level=21
arch=armv7
build_type=Release

[env]
CONAN_CMAKE_FIND_ROOT_PATH=$standalone_toolchain/sysroot
PATH=[$standalone_toolchain/bin]
CHOST=$target_host
AR=$target_host-ar
AS=$target_host-as
RANLIB=$target_host-ranlib
CC=$target_host-clang
CXX=$target_host-clang++
LD=$target_host-ld
STRIP=$target_host-strip
CFLAGS= -fPIE -fPIC
CXXFLAGS= -fPIE -fPIC
LDFLAGS= -pie

You could also use gcc using this profile arm_21_toolchain_gcc:

standalone_toolchain=/tmp/arm_21_toolchain # Adjust this path
target_host=arm-linux-androideabi

[settings]
compiler=gcc
compiler.version=4.9
compiler.libcxx=libstdc++
os=Android
os.api_level=21
arch=armv7
build_type=Release

[env]
CONAN_CMAKE_FIND_ROOT_PATH=$standalone_toolchain/sysroot
PATH=[$standalone_toolchain/bin]
CHOST=$target_host
AR=$target_host-ar
AS=$target_host-as
CC=$target_host-gcc
CXX=$target_host-g++
RANLIB=$target_host-ranlib
LD=$target_host-ld
STRIP=$target_host-strip
CFLAGS=-fPIC
CXXFLAGS=-fPIC
LDFLAGS=
  • Clone, for example, the zlib library to try to build it to Android
git clone https://github.com/lasote/conan-zlib.git
  • Call conan create using the created profile.
$ cd conan-zlib && conan create . conan/testing --profile=../android_21_arm_clang

...
-- Build files have been written to: /tmp/conan-zlib/test_package/build/ba0b9dbae0576b9a23ce7005180b00e4fdef1198
Scanning dependencies of target enough
[ 50%] Building C object CMakeFiles/enough.dir/enough.c.o
[100%] Linking C executable bin/enough
[100%] Built target enough
zlib/1.2.11@conan/testing (test package): Running test()

A bin/enough for Android ARM platform has been built.

Using build requires

Instead of downloading manually the toolchain and creating a profile, you can create a Conan package with it. The toolchain Conan package needs to fill the env_info object in the package_info() method with the same variables we’ve specified in the examples above in the [env] section of profiles.

A layout of a Conan package for a toolchain could looks like this:

from conans import ConanFile
import os


class MyToolchainXXXConan(ConanFile):
    name = "my_toolchain"
    version = "0.1"
    settings = "os_build", "arch_build"

    def build(self):
        # Typically download the toolchain for the 'build' host
        url = "http://fake_url.com/installers/%s/%s/toolchain.tgz" % (os_build, os_arch)
        tools.download(url, "toolchain.tgz")
        tools.unzip("toolchain.tgz")

    def package(self):
        # Copy all the
        self.copy("*", dst="", src="toolchain")

    def package_info(self):
        bin_folder = os.path.join(self.package_folder, "bin")
        self.env_info.path.append(bin_folder)
        self.env_info.CC = os.path.join(bin_folder, "mycompiler-cc")
        self.env_info.CXX = os.path.join(bin_folder, "mycompiler-cxx")
        self.env_info.SYSROOT = self.package_folder

Finally, when you want to cross-build a library, the profile to be used, will include a [build_requires] section with the reference to our new packaged toolchain. Also will contain a [settings] section with the same settings of the examples above.

You can

See also

Preparing recipes to be cross-compiled

If you use the build helpers AutoToolsBuildEnvironment or CMake, Conan will adjust the configuration accordingly to the specified settings.

If don’t, you can always check the self.settings.os, self.settings.build_os, self.settings.arch and self.settings.build_arch settings values and inject the needed flags to your build system script.

You can use this tool to check if you are cross building:

ARM architecture reference

Remember that the conan settings are intended to unify the different names for operating systems, compilers, architectures etc.

Conan has different architecture settings for ARM: armv6, armv7, armv7hf, armv8. The “problem” with ARM architecture is that frequently are named in different ways, so maybe you are wondering what setting do you need to specify in your case.

Here is a table with some typical ARM platorms:

Platform Conan setting
Raspberry PI 1 and 2 armv7 or armv7hf if we want to use the float point hard support
Raspberry PI 3 armv8 also known as armv64-v8a
Visual Studio armv7 currently Visual Studio builds armv7 binaries when you select ARM.
Android armbeabi-v7a armv7
Android armv64-v8a armv8
Android armeabi armv6 (as a minimal compatible, will be compatible with v7 too)

See also