So here’s a confession: I hate make files. And I’m really not all that keen on the whole compilation thing, with all those flags and whatnot. Why? Because I’m lazy.
But of late I’ve felt myself drawn back to C++. There is something about the language that both appeals to me and repulses me. Mostly those make files.
So this is about how I got a working cross-compilation setup working – with a lot of help from a guy in Ireland.
Most of the code I write is in Python. As a (mostly, sorta) interpreted language it reminds me of the simplicity of writing in BBC Basic on the BBC Micro. There’s something immediate and satisfying about what I call the code-run-crash loop. It’s easy to try things out. With no compilation time you’re encouraged to try small changes and see what happens.
Of course I use C/C++ elsewhere. (And yes, I’m aware that lumping those two together like that infuriates some people. Get over it.) I code in C++ for AVR microcontrollers in Atmel Studio and also in Wiring’s odd C/C++ hybrid in the Arduino IDE.
But I wanted to do it on the Raspberry Pi, especially given that Python can run like a dog on such low-power platforms. I haven’t done that to date because it either meant coding in some text editor and manually cobbling together stuff like make files or attempting to get an IDE running on the Pi, which felt like it would be an exercise in frustration, given the power limitations.
Then I found this video.
Not just for Beagles
The first thing you’ll notice is that it’s about the BeagleBone. Well, I have some of those too and I did follow along and get this working on that platform. But it’s equally applicable to the Raspberry Pi.
Basically, it walks you through creating a cross-development environment for ARM platforms using the Eclipse IDE on a Linux machine. Not only can you compile the ARM code, you configure Eclipse in such a way that the compiled executable automatically gets copied over the network to the ARM device each time you build. Just Ctrl-B to build and like magic the program is on the ARM device ready to run. No messing about with sftp or the like.
Even better, you can debug the code running on the ARM device from the Linux machine.
The video is by Dr Derek Molloy, an Irish academic who has a particularly clear way of putting over complex information.
Actually, I didn’t start with this video. There was an earlier version but the information in that quickly went out of date. I was five minutes into it before I noticed the mention in the description saying a more up-to-date version is available.
Alas, even the newer version is now slightly dated. It was made in 2015, which is about two aeons ago in computer terms. In particular, I quickly hit problems with the use of Emdebian as a package repository. From what I can see, that project has been moribund for at least a couple of years.
I nearly gave up, but something told me to persist. And it turns out that about 95% of the video is still valid and invaluable. So what I’m going to discuss here is what I did differently to the way Molloy does it in the video. I won’t claim that my approach is the best one to sorting out the problems, but so far it’s worked for me.
For the most part I won’t describe what’s in the video – you can watch it for yourself. Don’t do any of the stuff below without watching the video, and slot my bits in where appropriate.
Like Molloy, I set up my coding environment in a virtual machine. My daily driver computer is an iMac, and although I’ve heard of people setting up cross-compilation environments for ARM under macOS I’ve also heard a lot of horror stories. (I’ve done it to a degree, and may post about that another day.) So I went with my current Ubuntu 16.04 VM which I run under VMWare Fusion.
My first mistake was installing Eclipse from the Ubuntu repos using apt-get. I should have followed the video more precisely, downloading Eclipse C/C++ from the website and installing it that way. It’s remarkably easy, ensures you get the latest version and that you can put it wherever you like.
After having added armhf to Ubuntu’s list of architectures (sudo dpkg –add-architecture armhf), you fairly quickly run into that Emdebian issue. My solution was to ignore Emdebian entirely. I was having all kinds of issues when attempting to ‘apt-get update’. So here’s what I did instead.
I edited /etc/apt/sources.list and put [arch=i386,amd64] near the start of every existing entry. [Update 16/01/2018: I have since learned that adding architecture qualifiers for deb-src lines doesn’t make sense, so they’re needed only for the deb lines.] So, for example, the file starts with the entries:
deb [arch=i386,amd64] http://us.archive.ubuntu.com/ubuntu/ xenial-updates main restricted deb-src http://us.archive.ubuntu.com/ubuntu/ xenial-updates main restricted
When doing an update, that stops apt from requesting the armhf versions of packages from those repos. Then I added two lines at the end:
deb [arch=armhf] http://ports.ubuntu.com/ xenial main universe deb-src http://ports.ubuntu.com/ xenial main universe
From what I understand, ports.ubuntu.com is now the proper place to look for other architectures. You’ll notice that these entries all mention xenial because that’s the version of Ubuntu I’m running. If your version is different (Jessie, for instance) you’ll need to change that.
Installing Qemu, as described by Molloy, to get the armhf executables to run on Linux didn’t work for me. And, to be honest, while I know that’s probably fixable, it simply wasn’t sufficiently important to me to explore. Maybe some other time.
At various points, Molloy has you install stuff on the Linux machine, but why not go ahead and get it all done in one hit? I think this is the full list.
sudo apt-get install gcc make binutils-arm-linux-gnueabi sudo apt-get install gcc-arm-linux-gnueabi sudo apt-get install g++-arm-linux-gnueabi sudo apt-get install gcc-arm-linux-gnueabihf sudo apt-get install g++-arm-linux-gnueabihf sudo apt-get install libc6-armel-cross libc6-dev-armel-cross sudo apt-get install libncurses5-dev sudo apt-get install crossbuild-essential-armhf sudo apt-get install curl sudo apt-get install build-essential
For the most part, that’s it! (Obviously, Molloy makes you do a lot more.) However, there are a couple of other things worth noting.
On my Linux VM, I already had keys in the ~/.ssh/ directory, so didn’t bother generating new ones. That worked fine when using ssh-copy-id to the remote device. But for various reasons, the name of my private key isn’t the usual id_dsa or id_rsa. So I had to go into Window -> Preferences -> Network Connections -> SSH2 and add my private key to the list.
Also, when it came to setting up the debugger, I had to do an extra step compared to what’s shown in the video. This has to do with the remote connection and it may be because I’m using a more recent version of Eclipse (Oxygen).
At around the 33:29 mark, Molloy is setting up a debug configuration. In his case, this seems to have picked up the remote connection to the BeagleBone that he configured for building. This wasn’t the case for me, so under Run->Debug Configurations… I created a new setting under C/C++ Remote Application (as my project is called test2 this automatically got the name ‘test2 Debug’ and the, on the Main tab I had to select ‘New…’ to create a new connection. This meant setting up the name and IP address of the remote host (above).
One other thing to note, not mentioned in the video, is that if you hit the debug icon (white arrow in a green circle), you’ll likely get an error. That’s because Eclipse will default to the local machine. There’s an arrow next to the debug icon that provides a dropdown menu for debugging configurations – select the one you just set up for the remote machine.
And here I am happily debugging a (somewhat trivial) program running on my Raspberry Pi from the comfort of my Ubuntu VM running on my iMac. How’s that for layers of abstraction…