The First Cut is the Deepest

Running LTIB for the First Time

I was recently reminded that getting LTIB running for the first time can be a bit frustrating, so I thought I’d do it on a freshly-installed instance of Xubuntu that I have running on my Asus netbook, and write up a quick tutorial.

I’ve also been touting that I can cross-compile a rootfs for the Pi “in under 10 minutes” with LTIB.  And this is absolutely true on my 6-core Xeon Linux workstation.  But I realize that despite the fact that that machine is a couple of years old, it’s still considered to be pretty fast.

So we’ll fire up my nearly 4 year-old Asus Aspire One and see how she does.   That should put an upper-bound on any time claims.  After all, who in their right mind would use a 1.6GHz Atom machine as a build platform?

[Update: 3 hours and 18 minutes wall-clock time to build the basic RPi configuration from scratch — with the vast majority of that building the kernel + modules — on a 4-year-old Netbook.]

Getting LTIB

This has been discussed before, but, briefly, to get the latest code from the repository (and you want the latest, as RPi support is not yet in any of the static releases) you’ll need perl5 installed, as well as cvs.   Issue the following commands:

perl netinstall.txt

You should now have LTIB installed in the directory that you specified to netinstall.txt.

Installing packages

Before we run LTIB, let’s make sure the host is configured more-or-less properly.  LTIB will attempt to tell you what packages it needs to have installed on the host system, but the list falls short.   The LTIB mailing list provided an informal list of packages needed for Ubuntu about v12.04.  I’ve encapsulated that knowledge into the following script that you can run:


set -e

# sudo apt-get install -y install
sudo apt-get install -y patch
sudo apt-get install -y g++
sudo apt-get install -y rpm
sudo apt-get install -y zlib1g-dev
sudo apt-get install -y m4
sudo apt-get install -y bison
sudo apt-get install -y libncurses5-dev
sudo apt-get install -y libglib2.0-dev
sudo apt-get install -y gettext
sudo apt-get install -y build-essential
sudo apt-get install -y tcl
sudo apt-get install -y intltool
sudo apt-get install -y libxml2-dev
sudo apt-get install -y liborbit2-dev
sudo apt-get install -y libx11-dev
sudo apt-get install -y ccache
sudo apt-get install -y flex
sudo apt-get install -y uuid-dev
sudo apt-get install -y liblzo2-dev
sudo apt-get install -y libglib2.0-dev

if [ `uname -m` == "x86_64" ] ; then
  sudo apt-get install -y ia32-libs gcc-multilib lib32g++

  if [ ! -e /usr/lib32/ ] ; then
    sudo ln -s /usr/lib32/ /usr/lib32/

  echo "Not 64-bit; skipping unneeded packages"

Of course, package names can change, and other distros may have other dependencies, but this is the script that worked for my netbook.

Configuring a proxy server

Chances are you don’t need to configure a proxy server to use LTIB.   But if you get a timeout message when attempting to download packages from the gpp (Global Package Pool), you might need one.  Here’s how to set it up.

Unfortunately, LTIB doesn’t use the usual proxy server environment variables (http_proxy, HTTP_PROXY, etc.) but instead relies on the .ltibrc file in the directory where you checked out the ltib source.

# The HTTP proxy for internet access
# example:

And then further down, change %gpp_proxy from 0 to 1


Running ltib

Change into the directory where you checked out the ltib tree, and type ./ltib.   You’ll see

Installing host support packages

and a warning about how this may take a long time the first time you run it.   What’s happening here is that LTIB is building and installing more packages needed for its own operation in /opt/ltib.   It’s installing them in a separate and distinct RPM database, so there’s no worry about it clobbering the versions of packages you already have installed.   If you ever need to change the packages in /opt/ltib, do the following:

./ltib --hostcf

And that will let you configure the packages installed on the build system.

Pre-Positioning the RPi Toolchains

While we’re waiting for LTIB to complete setup, we might as well look ahead a little bit.

Once we run ltib and choose RPi as our platform, it will complain about not being able to find the RPM that contains the toolchains.   The maintainers of the Global Package Pool are unable to host the RPi toolchains, so we must fetch it and place it in the Private Package Pool or in a local directory (one specified in .ltibrc:%ldirs) so that LTIB can find it.

The easiest thing to do is to download the official RPi toolchains as an RPM file from and place the file in /opt/freescale/pkgs or /opt/ltib/pkgs.   LTIB will then install the RPM when it needs one of the toolchains contained therein.


./ltib -c

Choose the Raspberry Pi as the platform, then exit, Save = yes.

The first time compiling for a new platform takes a bit longer than subsequent builds.   This is because LTIB actually caches the source tarballs in /opt/ltib/pkgs, so once the 100M kernel source tarball has been downloaded, you don’t have to do it again.

In fact, LTIB caches binary RPMs in rpm/RPMS/arm so if it needs to install a package that was previously built and hasn’t changed, it won’t waste time recompiling it.

Don’t go too crazy at first, choosing packages willy-nilly.  Not all packages work on the pi yet.  Start with the default configuration.   It will build a kernel from source, and use busybox for most of the utilities in the rootfs.  If all goes well, at the end of the build, you will be prompted with a banner like:

 _   _            _ 
| | | | ___ _   _| |
| |_| |/ _ \ | | | |
|  _  |  __/ |_| |_|
|_| |_|\___|\__, (_)

That instructs you to issue 1-2 sudo commands in order to build the RPi SD card image. Unfortunately, the post-build script is executed with regular user privileges, and the LTIB maintainers decided that it would be better to prompt the user to issue the sudo commands than to potentially block an automated build by prompting for a sudo password.

In any case, you can edit config/platform/rpi/; so that it executes the commands rather than echoes them to the screen.    If you do, it makes life easier if you modify /etc/sudoers so that the commands can be executed with no password prompt.

My /etc/sudoers has the following line, and my build user is a member of the admin group, so this works for me:


Writing the SD card image

The rpi_sdcard.img file that results from all of this is a bootable image that needs to be written to the SD card with dd.

Be.  Extremely. Careful. to ensure that you are writing to the correct device.   Failure to Be.  Extremely. Careful.  will result in you overwriting another disk drive in your system with this RPi image.   This would be most unfortunate if it were the disk you’ve booted from, or one containing your vacation pictures from the Tesla Museum.  Or the birth of your first child.

If you’re not 100% sure of what you’re doing, stop now.

Okay, that said, I determined that my SD card reader shows up as /dev/sdb on my machine.  There are several ways to do this, including watching the log for attach messages when you insert the card reader.  You might also try cat’ing /proc/partitions to see what’s new when you insert the SD card.

So, noting that we’re writing to the disk device (/dev/sdb) and not a partition (/dev/sdb1), for me, on my system (Be. Extremely. Careful. of what you’re doing before you cut & paste this command), the following command writes the sd card image to my SD card.

sudo dd if=rpi_sdcard.img of=/dev/sdb bs=1M ; sync

That’s it.

Next up: useful ./ltib tricks, and troubleshooting.


One thought on “The First Cut is the Deepest

  1. Pingback: A good compromise: Cross-compiling with distcc | Midnight Yell

Leave a Reply

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

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

Google+ photo

You are commenting using your Google+ 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 )


Connecting to %s