Cross Compiling for Raspberry Pi in Windows 10

While the ideal build environment for Raspberry Pi is considered to be Linux and specifically Ubuntu, it may not be suitable for many of us developers who are forced, due to professional and personal reasons, or just by preference to work in a Windows world. Myself being first and foremost a SharePoint consultant, Windows is a key part of my day to day working life. Maintaining a dual partitioned system – with Windows and Linux – is impractical in many ways and with the added inconvenience of having to switch between 2 different environments, or having to run a VM (no matter how free the likes of VirtualBox are) on a home computer with about 4 GB of RAM – just enough to run your favourite Word Processor and play movies at the same time without either of them stuttering.

With the release of Windows 10 anniversary edition and Linux sub-system for Windows by Microsoft, we no longer will need to jump through all those hoops to be able to develop for Raspberry Pi.

What is cross compiling?

To understand cross compiling, first we need to understand what is meant by compiling.

Compiling, in the world of software, is the process of converting high level language – such as C/C++, Java and C# – code into machine code which a microprocessor can understand and execute. Since the architecture of various microprocessors differ in the set of instructions they support as well as how they process those instructions, programs written for one may not necessarily work in another. Hence, the compiler targeting one microprocessor architecture may not be suitable for another – although the underlying line of high level code maybe the same.

Traditionally, compilers installed on a machine targeted the architecture of that machine. For e.g. a compiler installed on a Windows 10 PC running on an x86_64 microprocessor cannot produce executable code for an ARM machine. Not only that, a compiler installed on a Windows PC will not be able to produce executable code for a Linux server running on that same machine. There maybe several reasons as to why this is the case, but I like to believe that this is due to the nature of optimisations that go into a compiler’s code which allows it to run faster and use less resources when compiling large volumes of code.

The above meant that to write and execute a program for Raspberry Pi (based on ARM), we will need to compile the code on a Raspberry Pi itself. Considering how the Raspberry Pi has been built for low power consumption, compiling large codebase would take a lot of time and that would directly decrease productivity of a developer, since they will need to compile it, run it, test it, make changes and compile it again. Then there is the comfort level argument. My professional work keeps me tied to Windows machines, plus I am quite comfortable and even prefer using Visual Studio (or one of it’s flavours) to write code since that is what I use for my SharePoint development needs. For a developer like me to have to learn an entirely new operating system, get comfortable with it, run code editors such as VIM and EMACS would be impractical and would mean having to move away drastically from my day to day working environments. I would rather stick to what I am comfortable and hence would be discouraged from actively participating in the brilliant IoT world and it’s fun.

These days we resolve the problem with a process called cross compiling.

Cross compiling is a technique with which a compiler for a specific architecture is executed within the environment of a different architecture. In the scenario above, the developer would write code and compile it on a Windows PC and transfer only the executable files to Raspberry PI. Thus, the roundtrip compile-run-test-change-compile becomes much shorter and the developer is able to turn around fixes and code much faster.

When talking about cross compiling we say: Cross-compiling for xyz on abc. So, if I am building a Raspberry Pi program within my Windows 10 machine, I would say I am cross-compiling for Raspberry Pi on Windows 10. To be more specific, I would say I am cross-compiling for ARM-v7 on x86_64 (or AMD64).

Cross compilers are not generally installed by default when installing operating systems or development IDEs. While, some of the IDE’s do come with some type of cross compiling options (For e.g. Some versions of Visual Studio come with the option of installing mobile development platforms that target varied systems like iOS and Android), it is not a norm. So, if you would like to do cross compiling you will need to deploy the relevant cross compilers for your main machine that you will use to do your development activities.

The cross-compiling toolchains

In the world of cross-compiling, the cross-compilers are called “toolchains”. Toolchains represent more than just the compiler. It is an ecosystem containing various binaries for compiling, assembling, extracting, and verifying the compiled code that your high level language is going to produce. Hence, it is essential that you download and deploy the cross compiling package rather than just the compiler. Please bear in mind that such packages are not just targeted at a specific microprocessor, but also the operating systems that run on them, or none in case you are building your own operating system for the microprocessor.

Due to the enormous amount of architecture / operating system combinations, the good people in the open source *nix community have come up with a great way of referencing these packages so they can be easily located and deployed. They call it the architecture tuple. The architecture tuple is a way of referencing the combination of microprocessor architecture, the vendor for the package, the operating system and the system interface for binary files produced (usually EABI in the case of Raspberry Pi) that is being targeted. The tuple is represented in the following format

In the case of applications targeting Raspberry Pi running the base Raspbian Linux OS, you will need the toolchain with the following tuple:

Notice that I have used “none” as the vendor?

To deploy and use the toolchain, we will need to first decide on the host that you would like to use to do the build. You can keep to pure Windows install without needing to use any sort of *nix shell, , or if you are running a 32 bit version of Windows 10, or not running the Windows 10 anniversary edition or if you are not running Windows 10 at all then you can head over to this site and download the win32 version of the toolchain and skip the next section. If not, please read on

The Linux Subsystem for Windows

The Linux subsystem for Windows, or Bash for Windows as it is called, is a subsystem that allows users to run some of the Linux applications, shell scripts within a shell within your Windows. The shell is not an emulator such as Cygwin but a true blue subsystem that allows unmodified Linux binaries to execute within Windows. The implementation is at a kernel layer rather than the user layer – giving it the added benefit of speed and stability.

The reason for choosing the subsystem instead of the Windows specific toolchain, at least for me, is that I can use the wide array of well documented Linux tools when doing my compile and transfer. The flip side is that, the sub-system still doesn’t support some of the service software such as SSH and TFTP (used for network booting) and we still need to use some Windows port for them.

As of writing this post, the subsystem is still in beta and can only be activated by switching on “Developer Mode” in Windows.

The first step is to turn on the developer mode in Windows 10. To do that, login into your Windows machine and access the settings app. In the settings app, access the “Update and Security” tile and select the “For developers” tab on the left to reveal the developer settings. In the screen that pops up, select the “Developer mode” radio button. The changes may take a few seconds to apply. If prompted to reboot, please do so proceeding with the next step

image

Next we need to turn on the necessary feature within Windows. To do this, use the Cortana search box and search for Windows features and select the “Turn Windows features on or off” option. In the “Windows Features” dialog that pops up, locate the “Windows subsystem for Linux (Beta)” option and select it. Click on “OK” to save changes and you should see the feature being activated. The system may prompt you to restart, in which case please do restart the computer. Once back, open an elevated command prompt and type in “bash” which will start the installation of the full subsystem in your Windows PC.

image

If you would like a more step by step guide, reference the guide from this link.

Install the cross compile tools

The next step is to deploy the relevant cross compile toolchains on our environment. To do that, start the “Bash on Ubuntu on Windows” link from the start menu. This will start the bash shell ready for our commands.

We will need to ensure that all the package sources and the shell itself is up to date. When you start the bash shell, you will see that Bash will check for updates and report the updates that are available for your system. The updates must still be initiated by the user using some Linux commands. If you are used to Ubuntu / Linux shells, then you will be able to use APT package installer to do it, otherwise follow the below command listings to update the packages and sources.

First let us update the package sources with the following command:

For those of you new to *nix, you maybe wondering what “sudo” and “apt-get” means. Well, sudo is the *nix version of “Run as Administrator” that you typically use within Windows and apt-get is the command line version of the aptitude package manager which allows administrators to download and deploy packages on the system. What we are essentially asking the package manager is to update it’s package sources cache. When running sudo, the shell will ask you to confirm your identity by prompting you for the root password. You would have set it up when deploying the subsystem.

Ensure the current version of the shell and the packages are up to date, so once the above command has completed successfully, type and execute the following command

The above command will download and update all the packages that require upgrades. Once completed, it will be time to deploy the base build tools. These are not the cross compiler versions, but the tools required to build applications for the host system. While this is not necessary, it is recommended. Run the following command to install it.

The above command will deploy the necessary utilities and binaries to compile sources targeting the host system. To ensure the packages have been deployed correctly, type in the following command once the above command has been completed

Now, let us deploy the cross compiler toolchain that we need. Type in and execute the following command in the shell

This should deploy all essential packages and binaries required to cross compile for Raspberry Pi running Linux from a Windows 10 host. To ensure that the packages are deployed correctly, type and execute the below command.

The above command should print the currently installed version of the toolchain, if the deployment was successful. Let us now build our first program for Raspberry Pi in Windows.

Our first cross-compiled “Hello World”

The application we are going to write is going to be in GNU C. You may like to use a different language or toolset such as Python which may not need a cross compiler, but for the purpose of this article, we are going to build one in C. For writing code, I recommend the lightweight Visual Studio Code. Although, we are doing this on a Windows host machine, Visual Studio Code is available for Linux and Mac OS X. If you are planning to use Code, I recommend deploying the C/C++ extension that provides syntax highlighting and intellisense for C and C++ programs. For this little experiment, we are going to use the tiny text editor called nano for Linux.

Switching back to the bash shell, type in the following command to switch to the home directory for your user profile

Type in the following command to write your C program

This should open the nano editor in your Linux shell. Once opened, type in the following code into the editor and press Ctrl+O to save the file. The editor will prompt you for the file name. Just press enter to save it to “hello.c”. Press Ctrl+X to exit the editor

Once back in the command prompt for the shell, type in the below command to compile our code for Raspberry Pi

The above command will compile hello.c to be compatible with Raspberry Pi / Pi 2.

Now you will not be able to run the code on your host Windows system since it is not compatible with your x86_64 Windows system. Trying to execute the binary will print an Exec Format Error on the screen. You will need to copy the hello.out file to your Pi before you can execute it. I prefer to use tools like Putty or WinSCP to do that. Login into your Pi and change your current directory to where you copied the hello.out to and execute the following command which should print “Hello Pi from Windows!” on the screen if everything goes well.

That is it! You have your cross compiler setup and you can use all the tools you are comfortable with in Windows to build applications for your Raspberry Pi!