Cross Compiling GTK applications For the Raspberry Pi

In this blog entry I will cover how I was able to cross compile GTK+ 3.0 applications for the Raspberry Pi. I will be assuming that you are running a Debian/Ubuntu flavored Linux distribution on your PC. I was successfully able to cross compile GTK+ 3.0 applications on my PC under both CrashBang Linux 11(Debian based) & Kubuntu 12.04 (Ubuntu based) . The sample code and makefile discussed in this blog entry are available here.

Figure 1. Simple Cross compiled GTK3 application running on the RPi

Figure 1. Simple Cross compiled GTK3 application running on the RPi

I was not able to set up “pkg-config” properly for cross compilation. Instead I’m using a makefile that lists all of the necessary include and library files/directories as well as the library dependency directories. Some of the GTK+ related libraries also required that the libc.so.6 library (and a bunch of others) be placed in a specific static directory (/lib/arm-linux-gnueabihf) . I got around that by creating two soft links; one in the /lib & one in the /usr/lib directories. So this approach may be considered a bit of hack, but it works very well. I’m also using the latest Raspbian OS image on my RPi (2013-07-26 && 2013-05-25 work fine)  and suggest that you do the same.

  • Install the Raspbian OS on an SD Card
  • Plug the SD Card into the Raspberry Pi
  • Connect the Raspberry Pi to the Network and power it
  • SSH into the RPi.
  • Configure the RPi using the raspi-config utility
  • Update all packages on the RPi with the “sudo apt-get update && sudo apt-get upgrade” commands.

The first six steps listed above are covered in detail here.

  • Create a $HOME/rpi directory on your Linux PC. Download the cross-compiling toolchain for the RPi into that directory on your Linux PC and add it’s bin directory  to the PATH variable as instructed here .
  • Now log in remotely onto the RPi via an SSH connection and type: “sudo apt-get install libgtk-3-dev“. This will install the gtk3 libraries and utilities necessary onto the RPi’s SD card.
  • Turn OFF the RPi board, remove the SD card and plug it back into the Linux PC.
  • Copy the /usr and /lib directories from the SD card (root file system partition) into the $HOME/rpi/ on the Linux PC. You can use the graphical file manager or the cp command.
  • Plug the SD card back into the RPi, connect it to the network and turn it on.
  • On the Linux PC, create two soft links in the /lib && /usr/lib directories :
    • sudo ln -s  $HOME/rpi/usr/lib/arm-linux-gnueabihf/ /usr/lib/arm-linux-gnueabihf
    • sudo ln -s $HOME/rpi/lib/arm-linux-gnueabihf/ /lib/arm-linux-gnueabihf
  • Verify that the directory soft links indeed exist with the following two commands:
    • ls -ld /lib/arm-linux-gnueabihf
    • ls -ld /usr/lib/arm-linux-gnueabihf
  • Download and extract the sample code and makefile  available here.
  • The code and makefile are shown below for reference:

gtktest.c

#include <gtk/gtk.h>

gint count = 0;
char buf[5];

void increase(GtkWidget *widget, gpointer label)
{
  count++;

  sprintf(buf, "%d", count);
  gtk_label_set_text(GTK_LABEL(label), buf);
}

void decrease(GtkWidget *widget, gpointer label)
{
  count--;

  sprintf(buf, "%d", count);
  gtk_label_set_text(GTK_LABEL(label), buf);
}

int main(int argc, char** argv) {

  GtkWidget *label;
  GtkWidget *window;
  GtkWidget *frame;
  GtkWidget *plus;
  GtkWidget *minus;

  gtk_init(&argc, &argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  gtk_window_set_default_size(GTK_WINDOW(window), 250, 180);
  gtk_window_set_title(GTK_WINDOW(window), "+-");

  frame = gtk_fixed_new();
  gtk_container_add(GTK_CONTAINER(window), frame);

  plus = gtk_button_new_with_label("+");
  gtk_widget_set_size_request(plus, 80, 35);
  gtk_fixed_put(GTK_FIXED(frame), plus, 50, 20);

  minus = gtk_button_new_with_label("-");
  gtk_widget_set_size_request(minus, 80, 35);
  gtk_fixed_put(GTK_FIXED(frame), minus, 50, 80);

  label = gtk_label_new("0");
  gtk_fixed_put(GTK_FIXED(frame), label, 190, 58); 

  gtk_widget_show_all(window);

  g_signal_connect(window, "destroy",
      G_CALLBACK (gtk_main_quit), NULL);

  g_signal_connect(plus, "clicked", 
      G_CALLBACK(increase), label);

  g_signal_connect(minus, "clicked", 
      G_CALLBACK(decrease), label);

  gtk_main();

  return 0;
}

Makefile

ARM_PREFIX= arm-linux-gnueabihf-
CC   = $(ARM_PREFIX)gcc
SRC += gtktest.c
TARGET = gtktest

LIBRARY += gtk-3 
LIBRARY += gdk-3 
LIBRARY += atk-1.0 
LIBRARY += gio-2.0 
LIBRARY += pangocairo-1.0 
LIBRARY += gdk_pixbuf-2.0 
LIBRARY += cairo-gobject 
LIBRARY += pango-1.0 
LIBRARY += cairo 
LIBRARY += gobject-2.0 
LIBRARY += glib-2.0 

LIBRARYDIR += $(HOME)/rpi/lib/arm-linux-gnueabihf 
LIBRARYDIR += $(HOME)/rpi/usr/lib/arm-linux-gnueabihf 
LIBRARYDIR += $(HOME)/rpi/lib
LIBRARYDIR += $(HOME)/rpi/usr/lib

XLINK_LIBDIR += $(HOME)/rpi/lib/arm-linux-gnueabihf 
XLINK_LIBDIR += $(HOME)/rpi/usr/lib/arm-linux-gnueabihf

INCLUDEDIR += $(HOME)/rpi/usr/include/gtk-3.0 
INCLUDEDIR += $(HOME)/rpi/usr/include/pango-1.0 
INCLUDEDIR += $(HOME)/rpi/usr/include/gio-unix-2.0/ 
INCLUDEDIR += $(HOME)/rpi/usr/include/atk-1.0 
INCLUDEDIR += $(HOME)/rpi/usr/include/cairo 
INCLUDEDIR += $(HOME)/rpi/usr/include/gdk-pixbuf-2.0 
INCLUDEDIR += $(HOME)/rpi/usr/include/freetype2 
INCLUDEDIR += $(HOME)/rpi/usr/include/glib-2.0 
INCLUDEDIR += $(HOME)/rpi/usr/lib/arm-linux-gnueabihf/glib-2.0/include 
INCLUDEDIR += $(HOME)/rpi/usr/include/pixman-1 
INCLUDEDIR += $(HOME)/rpi/usr/include/libpng12

OPT = -O0
DEBUG = -g
WARN= -Wall 
PTHREAD= -pthread

INCDIR  = $(patsubst %,-I%,$(INCLUDEDIR))
LIBDIR  = $(patsubst %,-L%,$(LIBRARYDIR))
LIB    = $(patsubst %,-l%,$(LIBRARY))
XLINKDIR = $(patsubst %,-Xlinker -rpath-link=%,$(XLINK_LIBDIR))

all:
	$(CC) $(OPT) $(DEBUG) $(WARN) $(LIBDIR) $(PTHREAD) $(INCDIR) $(XLINKDIR) $(LIB) $(SRC) -o $(TARGET)

clean:
	rm -rf $(TARGET)
  • In a terminal window on your Linux PC navigate into the “gtktest” directory, “cd ~/gtktest” and run “make“.
  • If everything went well you should end up with a binary compiled for arm called “gtktest”. Type the following command in the terminal “file gtktest“. The output should be: gtktest: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.26, BuildID[sha1]=0x72cb5773b65f1dce50358edfebd8be2d44aef967, not stripped.”
  • Copy the arm binary from the Linux PC to the  “home/pi/” directory on the RPi using scp. i.e. Run the following command in a terminal window on your Linux PC “scp $HOME/gtktest/gtktest  pi@10.42.0.73:/home/pi” (replace 10.42.0.73 with the IP address of your RPi). You will be prompted for the a password to connect to the RPi (user pi). It should be “raspberry” unless it was changed.
  • To test the binary on the RPi we will need to start a VNC server on the RPi and connect to it with a VNC client on your Linux PC. Detailed instructions are provided here.
  • Once the VNC session is started, and you can access the RPi’s desktop, open an LXTerminal window and type: “chmod +x gtktest” to make the gtktest binary executable and run it with “./gtktest“.
  • I got the example code from Zetcode’s GTK+ tutorial. I was able to build a few other GTK+ 3.0 examples as well.
  • You can use Eclipse as an IDE if you really want to. Simply move the gtktest directory into your eclipse workspace directory, start eclipse and when creating a new project, choose the “Makefile project with Existing Code” option.
  • Instead of using a VNC server to execute the GUI application remotely on the RPi, you can try X11 forwarding in SSH. I haven’t covered this topic yet but intend to do so in the near future.

 

This entry was posted in Raspberry Pi, Raspberry Pi Cross Development. Bookmark the permalink.