Development With Ubuntu
Here is a collection of tips which can be useful for people developing root filesystems or applications with Ubuntu.
Boot Ubuntu desktop / netbook on NFS
At least if you boot your root filesystem directly (without going through a standard Ubuntu initramfs), you probably noticed:
- that you can boot a minimal or server Ubuntu rootfs through NFS
- that you cannot boot a desktop type of Ubuntu rootfs (Ubuntu Desktop, Ubuntu Desktop Edition...)
The system hangs during the boot sequence. It's because of
NetworkManager that reinitializes the network interface that you used for NFS.
A quick workaround is just to disable
NetworkManager, for example by renaming the corresponding upstart configuration file:
sudo mv /etc/init/network-manager.conf /etc/init/network-manager.conf.disabled
Of course, this is shouldn't be done in a user environment, because users will need
NetworkManager (to connect to their wired and wireless networks). However, this can make your life easier if you are involved in product test or development.
Extract the contents of a uInitrd file
This can be useful to study boot scripts and analyze the early boot process in Ubuntu:
First, remove the U-boot header:
dd if=uInitrd of=initrd skip=64 bs=1
The initrd is a compressed cpio archive. Let's extract this archive...
On Maverick and beyond, it is compressed with lzma:
lzcat initrd | cpio -id
On Lucid and earlier versions, it is compressed with gzip
zcat initrd | cpio -id
Note: the U-boot header added to the initrd file is currently 64 bytes. This could change, and this can be different in other U-boot files. Here's a tip to find the actually U-boot header size. You can find the original image size with:
> mkimage -l uInitrd Image Name: Ubuntu Initrd Created: Wed Oct 6 05:09:47 2010 Image Type: ARM Linux RAMDisk Image (gzip compressed) Data Size: 5978226 Bytes = 5838.11 kB = 5.70 MB Load Address: 0x00000000 Entry Point: 0x00000000
The header size is the uInitrd file size minus the data size listed by mkimage.
Modify an existing uInitrd file
First, extract the contents of the uInitrd file to an initrd directory by following the above instructions.
Then, run the following commands:
cd initrd <make changes: for example by adding "set -x" in some scripts to debug them> find . | cpio -H newc -o | lzma -c > ../initrdnew.lzma cd .. mkimage -A arm -O linux -T ramdisk -C none -a 0 -e 0 -n initramfs -d ./initrdnew.lzma ./uInitrdnew
Replace lzma by gzip if your initramdisk was initially compressed with gzip (in Ubuntu Lucid and earlier versions, for example).
Note that the newc format for cpio is mandatory. If you don't use it, Linux won't be able to extract this archive.
Use ccache for your builds
Using ccache during your builds on Ubuntu is simple; just install ccache on your machine:
$ sudo apt-get install ccache
...and add it first to your $PATH:
$ export PATH="/usr/lib/ccache:$PATH"
OR alternatively, if you want to use ccache for all compilations, you can softlink the desired binaries:
$ sudo cp ccache /usr/local/bin/ $ sudo ln -s /usr/local/bin/ccache /usr/local/bin/gcc $ sudo ln -s /usr/local/bin/ccache /usr/local/bin/g++ $ sudo ln -s /usr/local/bin/ccache /usr/local/bin/cc $ sudo ln -s /usr/local/bin/ccache /usr/local/bin/arm-none-linux-gnueabi-gcc $ sudo ln -s /usr/local/bin/ccache /usr/local/bin/arm-none-linux-gnueabi-g++ $ sudo ln -s /usr/local/bin/ccache /usr/local/bin/arm-none-linux-gnueabi-cc
This will work as long as /usr/local/bin comes before the path to gcc (which is usually in /usr/bin). After installing you may wish to run "which gcc" to make sure that the correct link is being used.
Create a cross chroot environment
There are many wikis/blogs about this already, but I often find it cumbersome to get the exact instructions that work... and since I am using that often I am putting my own instructions here. At least I won't need to search them anymore, and at best it will be useful for others.
So basically here the purpose is to create an ARM root FS and be able to 'start' it from a desktop/laptop (x86) using QEMU user emulation. Clearly reading the following links will provide information about what this is all about:
So here are the exact instructions that worked like a charm for me.
First install the required packages:
sudo apt-get install debootstrap schroot binfmt-support qemu qemu-user-static
then create the 'foreign' root fs with:
sudo debootstrap --arch armel --variant buildd --foreign oneiric /var/chroot/oneiric_armel
or if you prefer to go with armhf...
sudo debootstrap --arch armhf --variant buildd --foreign precise /var/chroot/precise_armhf
This will take a few minutes, it will download all the .deb files that need to be install and unpack them.
Now, we need to finalize the packages installation in the target root FS.
First, copy the QEMU binary in the chroot (this is what will make sure that you can run an ARM executable on your desktop using emulation):
sudo cp /usr/bin/qemu-arm-static /<your chroot>/usr/bin/
Now you can enter your chroot and run the 'second stage deboostrap' that will finalize the packages installation and configuration.
sudo chroot /<your chroot>/ /debootstrap/debootstrap --second-stage exit
Now you need to create a valide 'sources.list' file in your chroot
<edit> /<your chroot>/etc/apt/sources.list
and add something like this (customize it as you want, and make sure that you use the right ubuntu release name)
deb http://ports.ubuntu.com/ oneiric main restricted universe multiverse deb-src http://fr.archive.ubuntu.com/ubuntu/ oneiric main restricted universe multiverse
Now you are all set! You can chroot in your ARM root FS and install packages, or do anything you want (like doing 'native' compilation). To enter the chroot, just run:
sudo chroot /<your chroot>/ apt-get update apt-get install <anything>
As you will notice you would be identfied as 'root', that can be fine most of the time. However if you plan to use the chroot as a 'working' environment, you might prefer to create standard users. You can do it with 'adduser' command and manage users/groups in the chroot as if you were on a 'different' computer. But there is a better mechanism...based on 'schroot'. You can read http://www.debian-administration.org/articles/566 to get more information, but basically it allows to seemlessly chroot using privileges from the current computer. And as a convenience, 'schroot' will also mount your regular '$HOME' folder so that you get all your 'stuff', including things like SSH or PGP keys...
In order to use schroot, you need to create a configuration file, e.g.
sudo <edit> /etc/schroot/chroot.d/arm.conf # it can be any file with .conf extension
and add something like that
[<config name>] description=Ubuntu ARM chroot directory=/<your chroot path>/ root-users=<your login> type=directory users=<your login>
What this does is:
- allow <your login> to log as 'root' in the chroot
- allow <your login> to log as <your login> in the chroot, and it would mount your $HOME as well.
So now to log as 'root' you can run:
schroot -c <config name> -u root
And to log as standard user, you can run:
schroot -c <config name> -u <your login>
Using <your login> you should find this very convenient to build/develop from your PC as if you were on a real ARM device!