Search by Tags

Hello World application on Embedded Linux (C/C++)

 

Article updated at 13 Jul 2021
Compare with Revision




This article provides step-by-step instructions on how to cross-compile a simple Hello World application on the development host using the Linaro toolchain, either through a command-line shell or Eclipse. It also gives instructions on how to run the application on the target device.
In addition to a simple Hello World application, we are using the gtk-scribble example for the Eclipse introduction.
Linux (Colibri T20) - Sample Code

Follow this article for information on setting up your environment for Embedded Linux application development.

An alternative to the Eclipse configuration presented in this article (which uses the Linaro toolchain), you can check the Quickstart Guide and the Linux SDKs article (which use OpenEmbedded generated SDKs).

Procedure

Hello World Application using Text Editor and Linux Terminal

At the development host terminal:

cd
mkdir hello_world
cd hello_world
  • Create a new "hello_world.c" file.
    This source file is used to print "Hello World" to the standard output device.

At the development host terminal:
Note: the '&' at the end of a command line forks the started process and runs it in the background. You immediately get back the prompt in the terminal window to enter further commands and the background process will not be terminated when the terminal gets terminated.

gedit hello_world.c &

Type the following code in the editor:

#include <stdio.h>                  // standard I/O header file
 
int main(int argc, char **argv)
{
     printf("\nHello World !!!\n");        // print "Hello World" message on screen
     return(0);
}
 

Use Ctrl+S to save the editor content.

  • Compile the "hello_world.c" file.
export CROSS_COMPILE=~/oe-core/build/out-glibc/sysroots/x86_64-linux/usr/bin/arm-angstrom-linux-gnueabi/arm-angstrom-linux-gnueabi-
${CROSS_COMPILE}gcc --sysroot=${HOME}/oe-core/build/out-glibc/sysroots/apalis-t30 -mfloat-abi=hard -o hello_world hello_world.c

Note the "-mfloat-abi=hard" needed for the Openembedded toolchain which starting with V2.4 of our images defaults to "-mfloat-abi=soft" and the "--sysroot=..." needed for the gcc 5.2 cross compiler which is used starting with V2.6 of our BSPs.

  • Copy the "hello_world" application file to the target device.
    Two options are described here: 1.Copy the file to the target device using a USB memory stick.
    2.Copy the file using a Secure Shell (SSH) via the network between the development host and the target device.

1. Copy the file to the target system using a USB memory stick.

  • Copy the "hello_world" application file to the USB memory stick.

At the development host terminal:

Example:
cp –f hello_world /media/USBDrive
  • Connect the USB memory stick to the target device.

  • Copy the "hello_world" to the target device.

At the target device terminal:

cd /home/root
cp –f /media/sda1/hello_world /home/root/


2. Copy the file using SSH via the network between the development host and the target device.

  • Check the IP address of the Ethernet interface on the target device.

At the target device terminal:

ifconfig

Expected output:

Example:

...
eth0      Link encap:Ethernet  HWaddr 00:50:B6:06:C4:57
          inet addr:192.168.10.2  Bcast:192.168.10.255  Mask:255.255.255.0
          inet6 addr: fe80::250:b6ff:fe06:c457/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:15354 errors:0 dropped:0 overruns:0 frame:0
          TX packets:17551 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:1701782 (1.6 MiB)  TX bytes:13514892 (12.8 MiB)
...

The following assumes the IP address of the target to be: 192.168.10.2
Note that in our images a SSH server is already installed and active by default.

At the development host terminal:
scp /localfile/path root@192.168.10.2:/remote/path

Example:
cd
scp hello_world/hello_world root@192.168.10.2:/home/root/

Enter the root password for the target device (none set by default) and press Enter.

  • Run hello_world on target device.

At the target device terminal:

./hello_world

Expected Output:

Hello World !!!


Note 1: The hello_world binary must have the executable (x) bit set. If it has not you will get,
-sh: ./hello_world: Permission denied
Check it with ls -l, set it with chmod if needed.

ls -l hello_world
-rwxr-xr-x    1 root     root          5352 Jul 15  2013 hello_world
chmod ugo+x hello_world


Note 2: If hello_world was compiled for the soft-float ABI, e.g. because you used a toolchain which by default does generate executable binaries for the soft-float ABI then you get the following error message even though the file does exist:
-sh: ./hello_world: No such file or directory

Import and use an existing Eclipse Project with user-provided Makefiles

  • Get the gtk-scribble Eclipse project and start Eclipse.
    At the development host terminal:
cd
wget http://developer.toradex.com/files/toradex-dev/uploads/media/Colibri/Linux/Samples/gtk_scribble_V2.zip
eclipse &

In Eclipse a view is a child window showing data in a specific form, e.g. the Editor view displays a file, the Project Explorer view shows the directory/file structure of your projects. A Perspective is a collection of such views which are shown at the same time and enable you to do certain tasks, e.g. the C/C++ Perspective enables C code development.
Switch to the C/C++ Perspective by using the menu Window->Open Perspective.

Use menu File->Import, General/Existing Projects into Workspace, select Archive File and Browse for gtk_scribble_V2.zip. Click Finish.
In the Project Explorer view double click the README file and read it.

In this example we use the external toolchain flavour, so in a terminal window we create a symbolic link to the ExtToolchain Makefile and prepare the target rootfs shared objects to be ready for development:

cd
cd workspace/gtk_scribble_V2
ln -s Makefile.ExtToolchain_Rootfs Makefile
cd /srv/nfs/rootfs/usr/lib
sudo sh -c "ls -w 1 | grep '\.so\.[0-9]*\.[0-9]*\.[0-9]*$' | sed -r 's/(.*\.so)(\.[0-9]*\.[0-9]*\.[0-9]*$)/ln -s \1\2 \1/' > makesymlinks.sh"
sudo chmod +x makesymlinks.sh
sudo ./makesymlinks.sh
sudo rm makesymlinks.sh

The Make Target view provides a convenient way to call make with various targets. Right click 'all' and choose edit to inspect what parameters are passed to make for a given entry. Leave the dialogue with Cancel when done.
Double click the x86 all target to compile the code to run on your x86 host. Note that some intermediate files plus the executable 'scribble.x86' appear in the Project Explorer. Double click the all target to cross compile for your target. Note that the executable 'scribble' appears in the Project Explorer.

Lets examine the build output and run the x86 executable in a terminal window:

[trdx@trdx gtk_scribble_V2]$ file scribble.x86 scribble
scribble.x86: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, not stripped
scribble:     ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.16, not stripped
[trdx@trdx gtk_scribble_V2]$ ./scribble.x86

Copy and execute the scribble file on the target in the same way as we did with the hello_world file.

Create a Hello World Application using Eclipse IDE with Automatically Generated Makefiles

  • Create a New C Project "hello_world" in Eclipse.

Using the mouse, select:
Menu options --> File --> New --> Project


Using the mouse, select C project and Next.


Project name: hello_world
Using the mouse, select:
Project Type: Makefile project -->Empty Project
Toolchains: Cross GCC


  • Add a new "hello_world.c" file to the project.

Once we have an empty project hello_world created the next step is to add files to the project.
Project Explorer --> "hello_world" --> Right click the mouse
Using the mouse, select:
New --> File



File name: hello_world.c


Type the C program in the "hello_world.c" file and Save.


  • Configure project build properties for the target device.

Note: If we build the project without configuring the build settings, the program will get compiled and build for the development/native (x86) platform.


Using the mouse, select:
C/C++ Build --> Settings
Tab 'Tool Settings'
List entry 'Cross Settings'
Enter the cross toolchain prefix "arm-linux-gnueabihf-".
Enter the full directory path for "gcc-linaro/bin".

Example:
Prefix: arm-linux-gnueabihf-
Path: /home/toradex/gcc-linaro/bin



Enter the compiler options required for the used ARM architecture:
List entry 'Cross GCC Compiler -> Optimization'

Example:
Optimization flags: -march=armv7-a -fno-tree-vectorize -mthumb-interwork -mfloat-abi=hard -mtune=cortex-a9 -Wno-poison-system-directories
Note: Set 'march' & 'mtune' according to the target architecture.

Compiler Options


Enter the linker options required to find the target rootfs and its libraries:
List entry 'Cross GCC Linker -> Miscellaneous'

Example:
Linker flags: -L/srv/nfs/rootfs/usr/lib -Wl,-rpath-link,/srv/nfs/rootfs/usr/lib -L/srv/nfs/rootfs/lib -Wl,-rpath-link,/srv/nfs/rootfs/lib
Note: Be sure to enter the path to the target's rootfs as it resides on your host machine. The rootfs is provided in our evaluation Linux images or it may be built using OpenEmbedded.

Linker Options

click OK

  • Build the "hello_world" project.

Using the mouse, select:
Menu options --> Project --> Build All


Verify the build messages,
Console --> CTD Build Console [hello_world]


Now, the "hello_world" application is ready to be deployed to the target device. Check the Debug folder with the intermediate files and the executable file hello_world.

Using Eclipse's Remote System Explorer

The Remote System Explorer plugin allows accessing other computers over Ethernet from within Eclipse. For the connection with our target device, we will be using SSH as the transport protocol. This feature is mainly used for debugging on the target from within Eclipse.

  • Create a Remote System Explorer connection.

Using the mouse, select:
Menu options --> Windows --> Open Perspective --> Other...


Using the mouse, select:
Remote System Explorer
OK


Using the mouse, select icon:
Remote System --> Define a connection to remote system


Follow the steps as shown in the images below, make sure to use 'Next' and not 'Finish' to go on:


Host name: Enter the IP address of your target device.
Connection name: The default value is the same as the host name, but this can be changed to a more human readable value.
Description: Some suitable description for the connection.
Select, Verify host name






By default, Eclipse uses the User ID from the host to login to the target.
Change the default User ID used to connect to the SSH server on the target device to root:



  • Connect to the target with the Remote System Explorer.

Enter the password for the target device (none set by default) and press Enter.


To transfer the "hello_world" application from the development host to the target device with the help of the Remote System Explorer, copy the executable from the project directory on the development host and paste it under:
Eclipse --> Remote System --> Sftp files --> My home

To access the target device, use the SSH terminal in Eclipse.
Run the hello_world application from the SSH terminal:

cd
chmod +x hello_world
./hello_world

Debug an Application in Eclipse

To debug an application on the target device which is controlled by the development host the following components are used:

  • Eclipse is used to setup the target device and the development host.
  • An SSH connection is used to start things on the target device.
  • On the target device, the gdbserver is used to start and control the program to be debugged.
  • On the development host gdb is started and a connection to the gdbserver over Ethernet is established.
  • Eclipse is used as a graphical front-end to gdb.

Creating a Debug Configuration.

Menu options --> Run --> Debug Configurations...
Create a new 'C/C++ Remote Application' launch configuration
Give it a Name
In the Main tab
- set the C/C++ Application (Note: Depending on the Eclipse version the order of input fields might be different)
- set the Eclipse Project
- use the RSE Connection already defined, or create a new SSH connection if you are not using the Remote System Explorer
- set the C/C++ Application on the Target (Note: If you don't get the Remote Absolute File Path try first configuring a regular run configuration)
- click Apply

Debug Configuration, Main Tab

In the Debugger tab
- set the path to the cross debugger: /home/toradex/gcc-linaro/bin/arm-linux-gnueabihf-gdb
- set the GDB command file, e.g. to gdbinit
- click Apply
Debug Configuration, Debugger Tab

The debugger needs access to the shared library files used on the target device, so if a shared object file is opened by your application on the target device it can read that same file from a storage location on the development host. Create the GDB command file in the Eclipse project and set solib-absolute-prefix to point to the rootfs used on the target device:

set solib-absolute-prefix /srv/nfs/rootfs

Starting to Debug

  • Open the Debug Configuration you just created and click Debug
  • If asked, enter info for the Remote System Explorer
  • If asked, confirm the switch to the Debug perspective
  • Happy debugging

    Debug Session