Using Clang as a cross compiler for Raspberry Pi
Posted on May 4, 2019 by Paul
In this article, I will show you how to cross compile C and C++ programs on a x86-64 machine for Raspberry Pi using Clang 8. The advantage of cross compiling on a x86-64 system for armhf is that, usually one has a beefy laptop or desktop computer that can speed up, by an order of magnitude or more, the compilation of C and C++ programs. This is more visible with large C++ programs, that can take hours to build on a Raspberry Pi 3 or days on a Raspberry Pi Zero.
We’ll start by building Clang as a cross compiler on the host x86-64 system. This will let us use the latest stable version of Clang, which at the time of this writing is 8. You will also be able to run the binaries compiled with this Clang version on all versions of Raspberry Pi.
As a side note, you can install the official Clang binary directly on your Raspberry Pi, check this article if you are interested. The problem with this approach is that the compiler will work only on Raspberry Pi 2 and up, no support for RPi 1 or Zero, and that it is really slow for large C++ projects.
I recommend that you do the build in a Debian Stretch virtual machine or a Docker container in order to not mess your system. If you decide to install Stretch in a virtual machine, make sure to use the minimal netinst system. It is really important that you start with a bare bone system, because we need to install armhf executables and libraries. By using a minimal system we avoid potential conflicts with the native x86-64 versions.
I’ll assume that you have a clean Raspbian install. I’ve used the latest available desktop image. In principle you should be able to follow the article using Raspbian Lite, but I did all my tests using the full desktop version of Rasbian.
First, make sure your x86-64 Debian Stretch virtual machine or container is updated:
Next, let’s enable the armhf architecture on the x86-64 machine:
At this point, you should be able to install armhf libraries and applications on your system and run them.
We’ll start by installing a few x86-64 prerequisites like a GCC compiler toolchain, version control systems, build systems, libraries and a few other applications:
We’ll also install the armhf counterpart of the above:
Next step, is to get the latest stable versions of Clang, LLVM, libc++ and a few other utilities:
Now, we can build what is in the llvm folder from above, depending on the speed of your computer, this could take from 40 minutes to a few hours:
Let’s add Clang to the system path:
Verify if you can use Clang by checking the compiler version, this is what I see on my machine:
If you get a command not found error, close and reopen your Terminal and try again.
At this point, you should be able to compile C and C++ programs, but you will be limited to use the system standard libraries and headers which correspond to GCC 6 which is a bit old. Fortunately, we can use libc++ which is also provided by Clang. Let’s build the remaining libraries libc++, libc++abi and openmp:
We are done, now we have a complete Clang cross toolchain. Let’s see how you can use it by compiling some small programs. I will put the next three test programs in a folder named work_examples in my home directory:
Copy or write the next three examples in the above folder:
You can build the first example, t0.c, from above with this command:
Side note, you can execute the generated binary directly on your host system because we’ve installed the qemu emulator, if your write:
you should see the Hello armhf from cross Clang message.
You can convince yourself that t0 is an armhf binary by using the file command. This is what I see on my machine:
Next, we can build the t1.cpp example in two ways:
t1a from above uses the system provided libstdc++ from GCC and t1b uses libc++. You can check what libraries needs each binary by using the next commands:
This is what I see on my machine:
For building t2.cpp use the next command:
Please note that t2.cpp needs the libc++, libc++abi and -libc++fs libraries. You simply can’t build it with the system libstdc++ library because it is too old and lacks C++17 filesystem support.
You can check what libraries are used by t2 like before. This is what I see on my machine:
Next, we are ready to deploy our executables to a Raspberry Pi device. We’ll also need to copy the libc++ and openmp libraries to the RPi, because our compiled versions are not available in Raspbian. I will make a folder named clang_libs in which I will copy all the required libraries:
Now, you’ll need to copy clang_libs and work_examples to your RPi device. Please note that clang_libs needs to be copied only once, while work_examples, or other binary that you’ve built, needs to be transferred every time you recompile the programs on your x86-64 Debian machine.
I will assume that you’ve transferred clang_libs and work_example in the home folder of your RPi device. For example, if you are using ssh, you can copy the folders with these commands:
don’t forget to replace your_rpi_device_ip from above with your RPi device IP!
For the remaining of this article I will assume that you are on an RPi device at a Terminal prompt.
On your RPi move the clang_libs folder to /usr/local:
Next, add the libraries from clang_libs to the system library path (this needs to be done only once):
At this point you should be able to run, on your RPi, any C or C++ program compiled with your cross Clang compiler. Try to run the four executables:
If you see an error about missing a shared library when you run t1b or t2 try to close and reopen your Terminal on the RPi, or logout and login again if you are using ssh.
This is what I see on my RPi:
If you want to learn more about programming on the Raspberry Pi, a very good book is Exploring Raspberry Pi by Derek Molloy: