Scratchbox2 based cross compiling
From PlugWiki
Contents |
Introduction on using a scratchbox2 based cross compiling toolchain for the SheevaPlug
WORK IN PROGRESS!!!!
This how to focuses on a cross compile development environment for a Debian or Ubuntu based target on a ubuntu host. The choice of an ubuntu host pc is because I use that distribution on my desktop pc, but with some modifications should this also work on a different distribution. The only difference will be probably the package manager or/and the name of the package. I have chosen Ubuntu or Debian for the target because the nice integration of the debian package management into the scratchbox2 environment.
Cross compiling is mostly used when it is specifically cumbersome or even impossible to compile on the native target. With the SheevaPlug is cross compiling not so needed: the amount of memory 512Mb and processor speed 1.2GHz is such that we get on the system itself a reasonable performance. I choose to cross compile because I use only a 2Gb SD memory card as root file system. This becomes rather small when you want to install all necessary development tools. My desktop has just more power and space under the hood. But again this is a rather personal choice.
This tutorial consist of three steps:
- Collecting and installing the necessary files.
- Setting up our "development" enviroment.
- Usages examples of the development enviroment.
Installation of the necessary packages
For the cross-compiling process we need three elements:
- The cross-compiler with is basic libraries.
- A way to manage the libraries we want to install
- This can be done with using a suitable root file system of the target (native scratchbox2 way).
- Using apt-cross as cross package manager to keep track on the libraries for the target installed on the host.
- A jail to trick the compilation process to make it think it is natively compiling while it is doing a cross compile.
This is also very well explained on the page of BiffEngineering. This page adds some details how it should/could work for specifically the SheevaPlug but basically it can be used for different targets as well.
The compiler / tool chain
For this step we should get a toolchain that can work for an armv5TE little embian architecture without floating point unit i.e. with softfloat. We have a number of options:
- Pre-built toolchains:
- CodeSourcery: This cross-compiler is used by almost all developers/companies using ARM devices. However, they only provide cross-compilers that work on x86/i386.
- Emdebian: This cross-compiler is used by Debian. Available for amd64/x86_64 and i386/x86.
- Tools for creating cross-compilers:
- Crosstool-ng: Builds a cross-compiler from source. Non-distribution specific.
- Crossdev: Gentoo's cross-compiler builder. Needs Gentoo.
- Emdebian: Emdebian also provides ways to build your own toolchain.
This is the same as we can use for the kernel as described here
We can install this tool chain at any convenient directory. For instance I used the CodeSourcery toolchain.
~$ mkdir SheevaPlug ~$ cd SheevaPlug ~$ bunzip2 arm-2009q3-67-arm-none-linux-gnueabi-i686-pc-linux-gnu.tar.bz2 ~$ tar xvf arm-2009q3-67-arm-none-linux-gnueabi-i686-pc-linux-gnu.tar ~$ ls arm-2009q3 ~$
Scratchbox2
First we have to download the correct packages. We can find more information about the basic scratchbox install here at the MeamoSDK+ web site.
To do this we have to the right distribution archive to your /etc/apt/source.list In my case I have to add:
deb http://maemo-sdk.garage.maemo.org/download/host ubuntu-jaunty free
But the exact line is different for each distribution of Ubuntu or debian.
By the way; the Maemo site mentions that only i386 is supported, butscratchbox2 works also on the 64bit architecture.
We can now install scratchbox2:
~$ sudo apt-get update ~$ sudo apt-get scratchbox2 sb2-qemu-arm
This will install some additional files/libraries as well.
Root file system
We can find an ubuntu Jaunty compatible root file system inside the"Sheeva installer 1.0" directory structure. We can find the archive containing this here. We can copy this rootfs.tar.gz file to an easier to remember name Ubuntu_Jaunty.rootfs.tar.gz
We can also use a debian version, Debian squeeze has my personal preference because the support for the Ubuntu version will be discontinued in say a year or two. How to make a Debian root file system from scratch is explained here on the wiki or we get a pre-build version from here. I just copied a pre build version which was already names as.
Configuration of the different parts
First we need to install a root file system of the target somewhere in our home directory. (I use $HOME/SheevaPlug but everywhere is OK) We can do this by un-tar-ing a suitable rootfs.tar.gz file. The procedure for the debian version is a bit different because there is something wrong with the locales of that pre-build version.
Note that we extract the archive as root because it contains device nodes: creating these requires root permissions. Then we use chown/chgrp to reassign all permissions to ourselves.
Ubuntu
~$ mkdir -p ubuntu_rootfs ~$ cd ubuntu_rootfs ~$ sudo tar -xvf ../Ubuntu_Jaunty.rootfs.tar.gz ~$ sudo chown -R myname * ~$ sudo chgrp -R myname * ~$ cd ..
And we can initialize our scratchbox2 environment.
~$ cd ubuntu_rootfs ~$ sb2-init -c sb2-qemu-arm Sheeva_ubuntu $HOME/SheevaPlug/arm-2009q3/bin/arm-none-linux-gnueabi-gcc ~$ cd .. ~$ mkdir source ~$ cd source ~$ sb2 -eR apt-get update ~$ sb2 -eR apt-get upgrade
The above commands can take sometime. The root file system for the target is brought up to date. We should not see major error messages, but sometimes will it happen that er are some minor warnings. They can be in general ignored. We are now ready to use our development system.
Debian
~$ mkdir debian_rootfs ~$ cd debian_rootfs ~$ sudo tar -xvf ../debian_squeeze.rootfs.tar.gz ~$ sudo chown -R myname * ~$ sudo chgrp -R myname * ~$ cd ..
We have to do a bit more configuration for the debian squeeze root filesystem. We have to add:
LANG=C LANGUAGE=en_GB:en LC_ALL=C
To the debian_rootfs/etc/default/locale file.
And we can initialize our scratchbox environment.
~$ cd debian_rootfs ~$ sb2-init -c sb2-qemu-arm Sheeva_debian $HOME/SheevaPlug/arm-2009q3/bin/arm-none-linux-gnueabi-gcc ~$ cd .. ~$ mkdir source ~$ cd source ~$ sb2 -eR apt-get install locales ~$ sb2 -eR dpkg-reconfigure locales
Select here an option you previous defined in the locale file. In this example is that "en_GB.UTF-8 UTF-8" and select OK.
~$ sb2 -eR apt-get update ~$ sb2 -eR apt-get upgrade
The above commands can take sometime. The root file system for the target is brought up to date. We should not see major error messages, but sometimes will it happen that er are some minor warnings. They can be in general ignored. We are now ready to use our development system.
Usage
At this point is it smart to read the Maemo SDK+ documentation as well. The main information can be found here.
The nice thing of using scratchbox2 is that there is no "limitation" or special demand where and how we develop our program. We can just make any directory or tool for our project and develop our code.
Actually there is one demand: we should not develop our code in the root file system of our target!
I will give a couple of examples to show the power of this development system.
Simple example
Let's make the following C program:
#include <stdio.h>
int factorial(int n)
{
if (n == 0) return 1;
return n * factorial (n - 1);
}
int main () {
int i;
int n;
for (i = 0; i < 10; ++i) {
n = factorial (i);
printf ("factorial(%d) = %d\n", i, n);
}
return 0;
}
And save this as factorial.c We can compile this program very easily:
~$ sb2 gcc factorial.c -o factorial ~$ file factorial factorial: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.14, not stripped ~$ ./factorial bash: ./factorial: cannot execute binary file ~$ sb2 ./arm_factorial factorial(0) = 1 factorial(1) = 1 factorial(2) = 2 factorial(3) = 6 factorial(4) = 24 factorial(5) = 120 factorial(6) = 720 factorial(7) = 5040 factorial(8) = 40320 factorial(9) = 362880 ~$
In the above example are happening a couple of interesting items:
- We can call the compiler within the scratchbox environment simply with gcc and we do not need to use the long "real" name. Scratchbox maps the name for us.
- The file we generate is an ARM compatible file and not an intel/amd compatible file binary.
- We compiled against a very old kernel 2.6.14. This is due to the version used to make the toolchain. We can "improve" the situation by making a custom made toolchain with the help of a tool like buildroot or buildroot-ng.
- As expected is our new program not working on our host pc. Because we compiled for the arm and not for an intel architecture.
- We can "run" the program in the simulated arm environment of scratchbox2.
More complicated example: with libraries
Let's generate the following program:
#include "ace/Log_Msg.h"
int main(){
ACE_DEBUG((LM_INFO, ACE_TEXT("Hello World\n")));
return 0;
}
We save this as test_ace.cpp and again we try to compile this:
~$ sb2 g++ -c -o test.o test_ace.cpp test_ace.cpp:1: fatal error: ace/Log_Msg.h: No such file or directory compilation terminated.
This does not work: because we do not have the ace library is the compiler not able to compile this program. We should first install all the necessary libraries and then try again.
This is with scratchbox very simple!
~$ sb2 -eR apt-get install libace-dev ~$ sb2 g++ -c -o test.o test_ace.cpp ~$ sb2 g++ -lACE test.o -o test ~$ file test test: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.16, not stripped ~$ ./testbash: ./test: cannot execute binary file ~$ sb2 ./test Hello World ~$
Again we can notice a couple of interesting items:
- We can install development libraries with the normal apt-get tool the sb2 -eR is mandatory to make the libraries install on our target root file system. With these options we allow scratchbox2 to work as "root" on our target file system.
- The compiler does not need complicated -I and -L directives scratchbox2 takes care that the compiler thinks that the libraries are in /usr/lib and /usr/include.
Working with the normal tools like "make" and "configure"
One advantage more is that with scratchbox all the normal tools think that they are working on the target. We can cross compile any package by just downloading the source archive, un-tar-ing it and follow the installation instructions as given by the maintainer of the source. But we only have to remember that we should run the commands within the sb2 environment.
Commands that modify our target file system, like make install, should be run as sb2 -eR make install. Other commands can be run with sb2 only, like sb2 make.
We will get in general some error messages about missing libraries during the process of using "configure" or "make". Make sure that you install all the neccary development libraries on the target first. It will ask for some attention to the error messages and other output to understand what is needed.
A basic example: (first we install all the essential tools on the targetlike "make".)
~$ sb2 -eR apt-get install build-essential binutils ~$ cd "source" ~$ sb2 ./configure ~$ sb2 make ~$ sb2 -eR make install
The last command installs the program on the target root file system as we have on the file system of the host pc. This does not really install any thing on the target file system. We have to copy the files manually to the SheevaPlug with scp for instance. Or we have to make a debian package, which we will discuss next.
Making a debian .deb package to install on the SheevaPlug
This is a bit more complicated. Please read the Ubuntu forum on the dh_make program for a bit better understanding. And check some of the Debian packaging tutorials for more background information. Let's start, we use the same source as we did in the previous example:
~$ apt-get install dh_make ~$ cd example-1.2.3 ~$ sb2 -eR apt-get install dpkg-dev dh-make ~$ sb2 dh_make -f ../example-1.2.3.tar.gz
In general we will need to modify the files generated in the ./debian directory to make the automatic compile process complete successfully. In general should the ./debian/rules file reflect the items that are needed to compile the program without the "debian" element to it.
After this preparation we can generate our package with:
~$ sb2 -eR dpkg-buildpackage -rfakeroot -b -d -uc -us
It can be that this fails on the change log parser.
~$ sb2 dpkg-buildpackage -rfakeroot -d -b -uc -us dpkg-buildpackage: set CFLAGS to default value: -g -O2 dpkg-buildpackage: set CPPFLAGS to default value: dpkg-buildpackage: set LDFLAGS to default value: -Wl,-Bsymbolic-functions dpkg-buildpackage: set FFLAGS to default value: -g -O2 dpkg-buildpackage: set CXXFLAGS to default value: -g -O2 Can't locate object method "new" via package "Dpkg::Changelog::Debian" at /usr/lib/dpkg/parsechangelog/debian line 132. dpkg-buildpackage: failure: changelog parser /usr/lib/dpkg/parsechangelog/debian gave error exit status 22
This happens because the target has a different version of the dpkg tools than our host. Scratchbox does a slightly complicated mix and match between target files and host files: we use the dpkg-parsechangelog of the target with the perl libraries of the host. One of the more simple solutions is to change the path mapping in the /usr/share/scratchbox2/lua_scripts/pathmaps/simple/00_default.lua by adding:
-- 99. Other rules.
{prefix = "/usr/lib/dpkg/parsechangelog", map_to = tools},
{prefix = "/usr/lib/perl", map_to = tools},
Now we will use the parsechangelog functions of the host and this matches better.
When the process went without any problem then we should have one directory higher a example-1.2.3.armel.deb file. After copying this file to the SheevaPlug we can install this with dpkg -i example-1.2.3.armel.deb
