Getting to grips with Eclipse: cross compiling

In this article I will show you how to use Eclipse to cross compile a program and run it on a development board. I am running the Helios release of Eclipse on Ubuntu 10.04 but it will work as described on a wide variety of versions of Linux and Eclipse. My target board has an ARM 926JE core and I am using an Ångström toolchain and root file system (http://www.angstrom-distribution.org/) but once again the information is generic and should work with pretty much any embedded Linux target and toolchain.

Installing Eclipse

You need a version of Eclipse and the C/C++ Development Toolkit. I downloaded the “Eclipse IDE for C/C++ Developers” for 32-bit Linux from http://www.eclipse.org and installed it into my home directory as follows:

cd ~
tar xzf eclipse-cpp-helios-linux-gtk.tar.gz

You will need a Sun Java runtime to run Eclipse. You can install it from your distribution, for example on Ubuntu “sudo apt-get install sun-java6-jre”, and then run Eclipse from the command line like this:

$HOME/eclipse/eclipse

Alternatively, you can download the binary package of the Java runtime from http://java.sun.com and install it into your home directory (for example). Then, run Eclipse with the -vm option like this:

$HOME/eclipse/eclipse -vm $HOME/jre1.6.0_12/bin/java

Setting the path for the toolchain

Usually you will have installed a cross-toolchain into /usr/local, /opt or your home directory. In my case I have an Ångström armv5te eabi toolchain (created using “bitbake meta-toolchain” if you are curious – full details outside the scope of this tutorial) which is installed into /usr/local/angstrom/arm and the tools have the prefix arm-angstrom-linux-gnueabi-. Whether you are compiling from the command line or Eclipse, you will need to include the path to the toolchain binaries. I generally write a script file that sets the path and then loads Eclipse like this:


#!/bin/sh
PATH=/usr/local/angstrom/arm/bin:$PATH
$HOME/eclipse/eclipse -vm $HOME/jre1.6.0_12/bin/java

Creating a project

Start Eclipse and select File->New->C Project or File->New->C++ Project. You will have a choice of four project types: Executable, Shared Library, Static Library and Makefile project. With the first three Eclipse will look after building the program using its own internally-generated makefile: this tutorial is about how to set up Eclipse to use a cross-compiler in these cases. With a Makefile project you will provide the Makefile yourself and so you select the compiler and build options outside the Eclipse environment.

For the proposes of this tutorial, create a “Hello World ANSI C Project”. You will find that Eclipse compiles it automatically to produce an executable for your PC – which is not what you want.

Setting the cross compiler

For all project types except Makefile project, you need to tell Eclipse to use the cross compiler rather than the native gcc.

  • Select the project in the Eclipse Project Explorer windows and then go to Project->Properties
  • Expand the section C/C++ Build and select Settings
  • If it is a C++ project, there will be four items in the Tool settings tab: GCC C++ Compiler, GCC C Compiler, GCC C++ Linker and GCC Assembler. If it is a C project, there will be three items: GCC C Compiler, GCC C Linker and GCC Assembler
  • In each case you need to add the toolchain prefix (arm-angstrom-linux-gnueabi-) to the the tool, for example gcc becomes arm-angstrom-linux-gnueabi-gcc as shown below:

If you are using multiple configurations, Debug and Release for example, you need to do this for each of them.

Now, click on Project->Clean to force Eclipse to rebuild and you should find an executable in the Binaries folder of the type of your toolchain, arm/le in my case.

Setting the include parser

This next bit is optional since it only affects the way Eclipse parses #include directives but not the way the program is compiled. Select Project->Properties. Under C/C++ General, select Paths and Symbols. On the Includes tab, select GNU C and add the path as shown in the screen shot below:

Now, if you right-click a header file (stdio.h for example) and select Open Declaration, it will display the header from the cross toolchain, rather than the native one. This may not matter much for headers from libc, which are pretty much the same for every one, but it does make a difference for headers from other libraries that may be totally different or not even installed on your development PC.

Unfortunately it is not possible to remove the paths to the native headers, but normally it won't be a problem because the indexer will look in the cross toolchain includes first.

Running the application on the target

Simply copy the executable from the project Binaries folder to the target. Exactly how you do it depends on how you connect to the target board, so I am going to have to let you work this bit out yourself. One option is to use the Eclipse Remote System Explorer, which I cover in in this tutorial http://www.embedded-linux.co.uk/tutorial/eclipse-rse

Debugging on the target

For this you will need a copy of gdbserver for the target and a network connection between the target and your PC. In my example below, the PC is at address 192.168.1.1 and the target is 192.168.1.101. You also need to choose a free TCP port number in the range 1024 to 65535: I use 2001.

On the target type:

gdbserver 192.168.1.1:2001 hello-arm

Gdbserver will load the program into memory and insert a breakpoint at the first instruction.

If you are using Eclipse Helios, there is an extra step (unless anybody knows a better way – comments?)

Eclipse Helios

  • Select Run->Debug Configurations....
  • In the list, double click C/C++ Application to make your new project appear and select it
  • Click on the Debugger tab. Here is the new bit: the default process launcher does not allow you to specify gdbserver as it used to. So, look for Using GDB (DSF) Create Process Launcher and click Select other...
  • In the “Select Preferred Launcher” window, tick Use configuration specific settings and then select Standard Create Process Launcher and then click OK
  • Now on the Debugger tab there is an item named Debugger which is set to gbd/mi. Change that to gdbserver
  • Set GDB debugger to arm-angstrom-linux-gnueabi-gdb
  • On the Connection tab:
  • Set Type to TCP
  • Set Host name or IP address to 192.168.1.101
  • Set Port number to 2001
  • Click Apply
  • Click Debug to start the session

Eclipse Galileo and earlier

  • Select Run->Debug Configurations....
  • From the list, select C/C++ Local Application
  • Click on New and your project should be added to the list. Select it
  • Click on the Debugger tab
  • In the Debugger list: select gdbserver Debugger
  • Set GDB debugger to arm-angstrom-linux-gnueabi-gdb
  • On the Connection tab:
  • Set Type to TCP
  • Set Host name or IP address to 192.168.1.101
  • Set Port number to 2001
  • Click Apply
  • Click Debug to start the session

For each debug session:

  • Start gdbserver on the target
  • In Eclipse, select Run->Debug or click on the bug icon
  • Once in the debug perspective, click the Resume icon or press F8.
  • The session ends when program exits or when you click the terminate button (a red square) in Eclipse

This whole process is easier if you install the Remote System Explorer, as I describe in http://www.embedded-linux.co.uk/tutorial/eclipse-rse

Tip: creating a skeleton project as a template

One final thought: it rapidly becomes tedious to change the project properties as shown here for every project you create. So, it is worthwhile to create a template project, for example the Hello World program, for each architecture/toolchain you work with and to make a copy of that for each new project. Copying projects is easy:

Open the template project (if not open already)
Edit->Copy
Edit->Paste and give the new project a sensible name (not “Copy of template”)