Cross Compiling For Raspberry Pi – Part I

Angry-Face-I

The Raspberry Pi is not the best environment to natively develop code on. I don’t mind using console-based editors like vi but I’d much rather use the more powerful GUI based tools that I already use on the Mac.

Add to this the Pi’s lack of serious horsepower and development can become painfully slow. For example, compiling the complete OpenCV libraries from scratch can take well over 16 hours.

So I’m going to bite the bullet and try to get cross compiling set up for the Pi, specifically for the OpenCV object detection project I’m currently developing and later for when I start using the ROS framework in anger.

What Is Cross Compiling?

In very general terms, cross compiling just means developing software on one system, the host system, that runs on a different system, the target system. To do this you need a compiler that is runs on the host system but generates output that runs on the target system.

If you’ve ever programmed an Arduino (or any microcontroller for that matter) you already have experience using a cross compiler, although in the Arduino IDE’s case the mechanics are mostly hidden from you. Still, even with the Arduino IDE you need to choose the specific Board you are developing for in the Tools menu so that the cross compiler knows the correct output to generate and what libraries to use for that particular system.

Screen Shot 2014-11-02 at 9.12.27 PM

Typically you need a cross compiler because developing code on the target system is either cumbersome or not possible – as in the case of microcontrollers. [My first professional programing job was using a cross assembler – called SNASM – on a PC to write a game for the Amiga 500.]

Let’s Be More Specific

In my case I’m developing C/C++ code for Raspbian and one of the simplest ways to do this is to avail of the pre-built compiler toolchain here: https://github.com/raspberrypi/tools.

There is also an option to build the toolchain from source using crosstool-NG if you wanted to customize it or build it for a particular host – however I think it is limited to Linux hosts, though Cygwin and OS X seem to be supported.

The pre-built toolchain itself is built using crosstool-NG and it requires a Debian based OS like Ubuntu (recommended) to run on. Even if you don’t already have Ubuntu it is easy enough to get it up and running on your OS using a virtualization system such as VirtualBox, VMware or Parallels.

In my case I am using Parallels 10 on OS X.

Setting Up Ubuntu on the Mac

I’m going to detail how I configured the Ubuntu instance for my purposes. However, there are many different ways one could do this and I’ll mention some of the options along the way. Keep in mind that my goal is to be able to use the Mac to develop code for the Pi, have Ubuntu cross compile the code, and the Pi run the code (obviously).

For starters you can decide between using the desktop or server version of Ubuntu. I’ve chosen to build a server instance as I don’t particular need or want a GUI interface for Ubuntu. I much prefer to ssh into the Ubuntu instance from a Mac terminal, that way it feels more integrated into the Mac environment and I can avail of the copy, paste and scroll back functionality of the terminal. The server instance also has a much smaller footprint of around 2 GB compared to about 11 GB for the desktop version.

Another aspect to the setup is sharing files between the Ubuntu instance and the Mac OS. There are two ways to do this.

The first is to create a special case-sensitive disk partition on the Mac. Parallels has options to automatically mount Mac volumes to the Ubuntu instance on startup. Initially I tried this approach but found that there were some permissions issues on the Ubuntu side when writing and creating files on the mounted volume. Also setting up a partition can be fiddlely, and if your backup drive is not configured for case-sensitive files then backing up the partition will not be possible. And don’t forget that you have to decide up front how big to make the partition which could be wasteful if you make it too big, or annoying if you make it too small.

In the end I went with the second approach which is to share folders with the Mac using a Samba server. This is actually very easy to do and avoids all the headaches associated with managing a separate partition. The only real draw back is that the Ubuntu instance must be running in order to access the files.

Creating the Ubuntu Server Instance

Go to http://www.ubuntu.com/download/server page and download the latest server image.

Fire up Parallels, select the Install Windows or another OS from a DVD or image file option:

Parallels Main Screen

Click Continue, then drag and drop the downloaded image onto the dialog:

Parallels File Screen

On the Name and Location screen make sure to select the Customize settings before installation option:

Name and Location Screen

Then in the Settings dialog go to the Network 1 entry under the Hardware tab and select the Default Adapter for the Type option:

Network Settings Screen

We need to set the default bridge adapter in order for the instance to connect to our local network.

Finish adjusting any other settings before continuing on with the install:

Install Progress Snapshot

When you finally get the login screen, login with the username and password you set earlier in the process:

Server Shell

In my case I created user solderspot.

From here you should first ensure the system has the latest updates:

solderspot@ubuntu:~$ sudo apt-get update
solderspot@ubuntu:~$ sudo apt-get upgrade

You can find the instance’s IP address using the ifconfig command:

solderspot@ubuntu:~$ ifconfig
eth0      Link encap:Ethernet  HWaddr 00:1c:42:ab:a8:25
          inet addr:192.168.1.59  Bcast:192.168.1.255  Mask:255.255.255.0
          inet6 addr: fe80::21c:42ff:feab:a825/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:31490 errors:0 dropped:0 overruns:0 frame:0
          TX packets:13720 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:38779438 (38.7 MB)  TX bytes:956126 (956.1 KB)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

The second line with inet addr: gives us the information we need. In this case the address is 192.168.1.59

However, if we try to ssh into the instance from a Mac terminal it will most likely fail:

Failed ssh Login

We need to first install an ssh deamon for the Ubuntu instance.

Go back to the Ubuntu window and type:

solderspot@ubuntu:~$ sudo apt-get install openssh-server

Now we should be able to ssh in to the instance from the Mac:

Successful ssh login

For here on out we can minimize the Ubuntu window and interact with the instance purely through Mac’s terminals – or Windows command prompts if you were doing this on Windows.

Sharing Folders with the Mac

We now have a Ubuntu instance that can be used to cross compile code for the Pi. However, before getting into setting up the compiler I first want to be able to access the Ubuntu files from the Mac side so that I can use all the GUI based development tools I’m already familiar with. For example, Mou to edit markdown files and SlickEdit to edit code.

To do this I’m going to setup a Samba server on the Ubuntu instance and share the solderspot home folder.

Ssh into the instance and install Samba:

solderspot@ubuntu:~$ sudo apt-get install samba

Create a Samba password for your user account:

solderspot@ubuntu:~$ sudo smbpasswd -a solderspot

Backup the default Samba config file:

solderspot@ubuntu:~$ sudo cp /etc/samba/smb.conf /etc/samba/smb.conf.defaults

Then edit /etc/samba/smb.conf and add the following section to the end of the file:

[<folder_name>]
path = <path to folder>
available = yes
valid users = <user_name>
read only = no
browseable = yes
public = yes
writable = yes

In my case I simply shared my user’s home folder:

[solderspot]
path = /home/solderspot
available = yes
valid users = solderspot
read only = no
browseable = yes
public = yes
writable = yes

Restart the samba server:

solderspot@ubuntu:~$ sudo restart smbd

Now from the Mac, open Finder, press command-k and type in the path to the shared folder, which is something like:

smb://<HOST_IP_OR_NAME>/<folder_name>/

In my case it was smb://ubuntu/solderspot :

Screen Shot 2014-11-04 at 4.24.04 PM

You’ll have to supply your username and password to connect to the server, but once that is done it should show up in Finder:

Screen Shot 2014-11-04 at 4.25.40 PM

Installing and Using the Cross Compiler

Now that we have our Ubuntu instance setup we can install the Raspbian toolchain.

To help keep things manageable I recommend creating a folder where all Pi related files can be placed and organized. This is generally good practice when doing cross development as it is too easy to confuse host and target files.

I created a folder called pidev in the home directory:

solderspot@ubuntu:~$ mkdir pidev

Change into this new folder and use git to clone the pre-built toolchain:

solderspot@ubuntu:~$ cd pidev
solderspot@ubuntu:~/pidev$ git clone https://github.com/raspberrypi/tools.git --depth=1 pitools

You should now have a folder called pitools inside pidev.

If you don’t have git install you’ll need to get it first:

solderspot@ubuntu:~/pidev$ sudo apt-get install git-core

To test out the toolchain create a test folder with a hello.cpp file with the contents:

#include <stdio.h>

int main( int argc , char **argv )
{
	printf("Hello World!\n");
	return 0;
}

In pitools there are (currently) five toolchains in the arm-bcm2708 sub-folder:

solderspot@ubuntu:~/pidev/test$ ls ../pitools/arm-bcm2708/
arm-bcm2708hardfp-linux-gnueabi  gcc-linaro-arm-linux-gnueabihf-raspbian
arm-bcm2708-linux-gnueabi        gcc-linaro-arm-linux-gnueabihf-raspbian-x64
arm-rpi-4.9.3-linux-gnueabihf

But you are going use either gcc-linaro-arm-linux-gnueabihf-raspbian if you have a 32 bit system, or gcc-linaro-arm-linux-gnueabihf-raspbian-x64 if you have a 64 bit system.

I have a 64 bit system so I’ll be using gcc-linaro-arm-linux-gnueabihf-raspbian-x64 in all examples.

To compile our test Hello World code we can manually invoke the compiler from the test folder:

solderspot@ubuntu:~/pidev/test$ ../pitools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/arm-linux-gnueabihf-gcc hello.cpp -o hello

You should now have a hello executable that we can run on the Pi.

Ssh into the Raspberry Pi:

solderspot@ubuntu:~/pidev/test$ ssh pi@<ip of raspberry pi>
pi@192.168.1.17's password:
Linux mite 3.12.28+ #709 PREEMPT Mon Sep 8 15:28:00 BST 2014 armv6l

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sun Nov  2 04:26:15 2014 from 192.168.1.7
pi@mite ~ $

Copy the hello program over:

pi@mite ~ $ scp solderspot@192.168.1.59:pidev/test/hello .
[solderspot@192.168.1.26's password:
hello                                         100% 6427     6.3KB/s   00:00

And run it:

pi@mite ~ $ ./hello
Hello World!

It should print out “Hello World!”.

Wrapping Up

So I’ve got the basics set up and am able to compile a trivial Hello World example. The next step is to compile much more complex programs that use other libraries, such as OpenCV and MMAL. I will detail my success or failure with that endeavor in “Part II”.

Advertisements

5 comments

  1. Roger Shepherd · · Reply

    Thanks for this – very useful. I’ve set things up using Virtual Box on a Mac. I’ve got a couple of case sensitive file systems on the Mac and I mount them using folder sharing on the virtual machine. All seems to work OK.

    However, when I get as far as trying to compile the test program with

    ../pitools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/arm-linux-gnueabihf-gcc hello.cpp -o hello

    I get a message that

    arm-linux-gnueabihf-gcc-4.8.3: command not found

    I’ve looked at arm-linux-gnueabihf-gcc and it just invokes arm-linux-gnueabihf-gcc-4.8.3. I guess the problem is that PATH needs to be set up – in which case the test compile wouldn’t need the ../pitools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/arm-linux-gnueabihf-gcc
    command to have to full path.

    Have a missed something? Or did you omit to mention some magic that makes this all work?

    Thanks

  2. Roger Shepherd · · Reply

    Actually, it seems that doing via folder sharing is the source of lots of problems. The one I mention is just the start. I’m going to revert to the method you suggest. I’ve tried compiling with the files on the VM disk and that works wonderfully.

    1. Yes, I had the same problem as you did. Making the VM disk accessible to the Mac using a Samba server worked like a charm and avoided incompatibilities between the two operating systems.

  3. Hello there 🙂 . I came see the first part because i wanted to be sure to be able to do the second one.

    I used your toolchain finally, because i was using a custom toolchain for arm, so i wanted to start over with you (Had a LOT of problems with OpenCV)

    You should actually use

    “pitools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/arm-linux-gnueabihf-g++”

    instead of gcc.

    Gcc doesnt compile C++, only C 😉

  4. Brian Topping · · Reply

    Great series, thanks! I haven’t gotten to part 2 yet.

    What I’ve done previously is set up Internet Sharing off a dedicated ethernet port on the Mac. This generally provides a subnet of 192.168.2.0/24 that can reach the net if the Mac is alternately connected (such as through wifi or a second wired ethernet). By wiring the Pi to the Mac with a hard connection, the file sharing is a lot smoother.

    Secondly, I share my personal home folder on the Mac using NFS (not SMB), but only to machines coming from 192.168.2.0/24. NFS has kernel components that should make it faster and more resilient to a funky net, and with the mount restrictions, if I carry the rig to a coffee shop, everything is secure.

    With that in hand, I mount the NFS on the Pi and have been doing compiles for the Pi on the mounted Mac home folder, allowing me to use IDEs on the Mac for development as you are doing here. But I also ran into the same issues with compile times, so that’s why I’m setting up a similar rig. Instead of Parallels, I had an extra machine that I ran XenServer on.

    Since this gear isn’t really portable any more, if I want to work out of a coffee shop, I access it all through Back To My Mac. While the other tricks above are pretty easy to find, http://onethingwell.org/post/27835796928/remote-ssh-bact-to-my-mac really covers BTTM well.

    On to part 2!! 🙂

Comments welcome

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s