跳到主要内容

Cross Compiling in C++

Cross compilation happens when we are compiling the program on a system different to what the program will be running on.

It is used widely in embedded development, because many embedded devices lack the capacity for some serious compiling work. Hence, we would compile these programs on a powerful host machine and then ship them to the target machine (i.e. the embedded system).

Compile for ARMv7 under x64 Linux

Using CMake + GCC Toolchain

A more conventional way to do so is to use the GCC toolchain, i.e. the gcc/g++ compilers, the ld linker, and the libstdc++ libraries.

The toolchain should be included in most of the GNU/Linux systems. However, for cross compiling, we need to separately install the compilers and libraries for that specific architecture.

Here is a list of packages that worked for me under Ubuntu 18.04:

  • gcc-7-arm-linux-gnueabihf
  • gcc-7-multilib-arm-linux-gnueabihf
  • g++-7-arm-linux-gnueabihf
  • g++-7-multilib-arm-linux-gnueabihf
  • binutils-arm-linux-gnueabihf
  • libgcc1-armhf-cross
  • libstdc++-7-dev-armhf-cross

To do the actual compiling, you should include the following lines in the CMake file, which specifically tells it to use the gcc cross compiler for armhf and to compile for that architecture. Tweak the -march and -mcpu flag according to your platform and then you should be able to compile it as usual.

set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)

set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc-7)
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++-7)

# Some websites also adds "-mfloat-abi=hard" which produces error in my environment (gcc v7.5)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=armv7-a -mcpu=cortex-a9")
备注

If there are still errors produced at the linking stage, check if the linked libraries are also compiled in the wanted architecture (i.e. armhf). You may also need to cross-compile them from source.

References

Using CMake + LLVM Toolchain

Clang in the LLVM Toolchain is inherently a cross compiler, so it should theoretically be easier to work (while in reality...I gave up while compiling on a Ubuntu 18.04)

In LLVM, we use clang as compiler, lld as linker, and libc++ as libraries.

TODO: figure out how to get this to work.

You should set the target triplet based on the architecture you wan to compile to. Then, you should be able to compile as usual.

set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)

set(triple arm-linux-gnueabihf)

set(CMAKE_C_COMPILER clang)
set(CMAKE_C_COMPILER_TARGET ${triple})
set(CMAKE_CXX_COMPILER clang++)
set(CMAKE_CXX_COMPILER_TARGET ${triple})

Reference