Building a hello world application/de

From Openmoko

Revision as of 13:07, 31 July 2008 by Proton (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Contents

Preparation

This guide assumes that you have performed the steps in Building_Openmoko_from_scratch

The commandline program

Store the following more or less standard hello world code in hello.c

#include <stdio.h>

int main()
{
  printf ("Hello World\n");
  return 0;
}

Compiling it the wrong / easy way

Assuming your current working directory is /home/moko, and that you stored the code in /home/moko/hello.c it should now be possible to compile the application using

./build/tmp/cross/arm-linux/bin/gcc -o hello hello.c

Testing it

Assuming you have followed Setting up USB connection and you have a working network connection to either a qemu Neo or a real Neo.

scp hello root@192.168.0.202:/tmp/
ssh root@192.168.0.202 /tmp/hello

This sequence of commands ought to give you a nice Hello World, btw. the default root password is blank, just press return.

GDK the Wrong / Easy Way

Building a GDK application the wrong way is slightly more complex, but is still fun to try. It requires using pkg-config to specify including and linking with the ARM header files and libraries.

Given the following program as main.c:

#include <gtk/gtk.h>

gchar *hello = "Howdy";
gchar *world = "World";
GtkWidget *label;
gchar *labeltext;

void buttoncb(GtkWidget *widget, gpointer data)
{
if (labeltext == hello)
   {
   labeltext = world;
   gtk_label_set_text(GTK_LABEL(label), labeltext);
   }
else if (labeltext == world)
   gtk_main_quit();
}

int main(int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *button;

gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
button = gtk_button_new();
labeltext = hello;
label = gtk_label_new(labeltext);
gtk_container_add(GTK_CONTAINER(button), label);
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(buttoncb), NULL);
gtk_container_add(GTK_CONTAINER(window), button);
gtk_widget_show_all(window);
gtk_main();

return 0;
}

You must first point pkg-config to the proper directory:

export PKG_CONFIG_PATH=/home/username/moko/build/tmp/staging/arm-linux/lib/pkgconfig

And set up an environment variable to make things easier:

export OMDIR=/home/username/moko

The compile/link line is rather long - you will only want to do this once before you decide to create a shell script or make file:

$OMDIR/build/tmp/cross/arm-angstrom-linux-gnueabi/bin/gcc -L $OMDIR/build/tmp/staging/arm-angstrom-linux-gnueabi/lib/ \
                   -Wl, rpath-link, $OMDIR/build/tmp/staging/arm-angstrom-linux-gnueabi/lib/ -Wl, -O1 -g -o hw main.c \
                   '$OMDIR/build/tmp/staging/i686-linux/bin/pkg-config --cflags --libs openmoko-libs gtk+-2.0'


Then copy and run as in the original hello world command line program above.

Why was it the wrong way?

Openmoko provides a precompiled Toolchain package for that. It also comes with some scripts that make your life much easier. Besides, you don't need OpenEmbedded to build applications. If you do want to customize your complete distribution, then read on how to use bitbake when building stuff. In any way, at least you now know that you can easily cross compile for Openmoko.

The Right Way: Using the gnome build system

Even if I am no expert in this - somebody had to make a start so I'll write down everything I still believe to remember from my 1st 'real' gnome application that used the autotools and all: I have never been able to find a good tutorial for making a "canonical" gnome application - and such a tutorial is urgently needed.

Since I know that many of these things will be missing or even inaccurate in the 1st step - if You find out to make it work better or at all - please document how to do this.

Creating the necessary documentation files and directory structure

First of all go into the directory you want to be the topmost application of yout new application, and create the following files:

AUTHORS A list of all authors that took part in developing this project
COPYING The copyright notice. Favourably the GPL
INSTALL This file should contain the information how to build and install this program
README This file should contain all important information about the program including what the program was written for.
NEWS The name of this file should be self-describing
TODO The wishlist of your project
Changelog A list of the major changes to your project

I remember that some of these files were mandatory - it's better create them all

Then create a directory named 'src - and copy the source code of the program there.

The configuration of the autotools

What is to be said to this section is that I included some requirements like gnome-vfs to the requirements not because our application actually needs these packages but because it was very hard to find out how to do so - and I therefore wanted to document how to add them.

If anybody doesn't like this approach - feel free to edit this wiki.

autogen.sh

This file is a shell script that calls all autotools in the right order and with the right parameters so they will in the end generate the standard configure script that will detect how to build our program.

#! /bin/sh
#
# Most if not all of the contents of this file was taken from the openmoko
# sample application as it was shipped with the openmoko toolchain on
# January 31st, 2008
#

srcdir=`dirname $0`
test -z "$srcdir" && srcdir=.

PKG_NAME="hello"

(test -f $srcdir/configure.ac) || {
        echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
        echo " top-level $PKG_NAME directory"
        exit 1
}

which gnome-autogen.sh || {
        echo "You need to install gnome-common from the GNOME CVS"
        exit 1
}

REQUIRED_AUTOMAKE_VERSION=1.7 USE_GNOME2_MACROS=0 REQUIRED_GETTEXT_VERSION=0.10.36 . gnome-autogen.sh
configure.ac

This file tells what the configure script has to do - and which parts of the intelligence delivered with the tools that generate the configure script we need.

I documented every line of which I found out what it actually does. The first line is for to tell the emacs text editor that it has to treat this file as an autoconf file.

#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

# Tell autoconf to check what version of autoconf we need.
AC_PREREQ(2.61)

# Initialize autoconf and tell it what program we wrote, the version
# of our program, and the address bug reports have to be sent to.
AC_INIT([audiorec],[0.2],[audiorec.projects.openmoko.org])

# tell autoconf where to put the temporary files it generates 
AC_CONFIG_AUX_DIR([build-aux])

# This one is thaken from the "Migrationg to gnome Documentation Build
# utilities". No Idea, what it does.
AC_CONFIG_MACRO_DIR([m4])

# give autoconf the name of a file whose existence is a hint that
# autoconf has been started from the right directory. 
AC_CONFIG_SRCDIR([src/diskusagemeter.c])

# Tell autoconf where to put the output file that contains all
# definitions our C program will need
AC_CONFIG_HEADER([src/config.h:src/config.hin])

# Initialize automake, and tell it to tell the C compiler to output as
# many warnings as it can
AM_INIT_AUTOMAKE([-Wall foreign])

# The GNU Gettext version we used for internationalization of our
# program... 
AM_GNU_GETTEXT_VERSION([0.16.1])
# ...Or alternatively the local gnu gettext installation
AM_GNU_GETTEXT([external])

# Check for a C compiler
AC_PROG_CC

# Include all m4 macros that have to do with the language C
AC_LANG_C

# ???
AC_ISC_POSIX

# ???
AC_HEADER_STDC

# Checks for programs.
AC_PROG_CC

# We need the following type definitions from autoconf - or somebody else.
AC_TYPE_INT8_T
AC_TYPE_INT16_T
AC_TYPE_INT32_T

# AC_CHECK_LIB(libgnome-2.0, gnome_help_display_uri, [AC_DEFINE(HAVE_LIBGNOME, 1)])

# Prepare building the gnome documentation of this program
#GNOME_DOC_INIT

# Checks for libraries.
dnl Checking for the required libraries.
GTK_REQUIRED_VERSION=2.0.0
LIBGNOMEUI_REQUIRED_VERSION=2.0.0
GCONF_REQUIRED_VERSION=2.0.0
GNOMEVFS_REQUIRED_VERSION=2.0.0
ALSA_REQUIRED_VERSION=1.0.0
OGG_REQUIRED_VERSION=1.0.0
VORBIS_REQUIRED_VERSION=1.0.0
VORBISENC_REQUIRED_VERSION=1.0.0
PKG_CHECK_MODULES(DEPEND, gtk+-2.0 >= $GTK_REQUIRED_VERSION gconf-2.0 >= $GCONF_REQUIRED_VERSION gnome-vfs-2.0 >= $GNOMEVFS_REQUIRED_VERSION libgnomeui-2.0 >= $LIBGNOMEUI_REQUIRED_VERSION alsa >= $ALSA_REQUIRED_VERSION ogg >= $OGG_REQUIRED_VERSION vorbis >= $VORBIS_REQUIRED_VERSION vorbisenc >= $VORBISENC_REQUIRED_VERSION)

AC_SUBST(DEPEND_CFLAGS)
AC_SUBST(DEPEND_LIBS)

# Gettext wants to know the path to the top directory and such things...
top_builddir=`pwd`
AC_SUBST(top_builddir)
AC_SUBST(PACKAGE)
AC_SUBST(LOCALEDIR)

# Checks for the header files we include.
AC_HEADER_STDC
AC_CHECK_HEADERS([fcntl.h stdlib.h string.h sys/vfs.h])

# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST

# Checks for library functions that we really need.
AC_FUNC_MALLOC

# A list of all configuration files we have to generate
AC_CONFIG_FILES([Makefile src/Makefile src/images/Makefile po/Makefile.in]) #help/Makefile 

# Tell autoconf to start outputting whatever it has to.
AC_OUTPUT
Makefile.am

This file is a template top-level-Makefile that will be filled with life by the configure script.

One thing that is added to the standard Makefile is code for automatically generate the _control-file mentioned above on a make dist

# A list of all subdirectories.
SUBDIRS = src po # help

# Allow automake to interpret m4 macros (needed for interpreting
# gettext's makefile.in
ACLOCAL_AMFLAGS = -I m4
# Files that aren't source files and still have to be in the tarball
EXTRA_DIST = @PACKAGE_NAME@_control

# An (currently unused) extension to the "install" target
install-data-local:

@PACKAGE_NAME@_control: Makefile.am configure.ac
	echo "Package: @PACKAGE_NAME@">$@
	echo "Version: @PACKAGE_VERSION@">>$@
	echo "Description: An voice recorder that can stop recording during silence">>$@
	echo "Section: openmoko/applications">>$@
	echo "Priority: optional">>$@
	echo "Maintainer: your_name">>$@
	echo "Architecture: armv4t">>$@
	echo "Homepage: (The homepage of this project)">>$@
	echo "Depends: gtk+ alsa-lib libogg libvorbis gnome-vfs libgnomeui">>$@
	echo "Source: \$${SRC}">>$@
src/Makefile.am

This file is a template Makefile that when filled with life by the configure script will compile our code.

The most important step here is to tell which files our program consists of.

AM_CFLAGS = $(DEPEND_CFLAGS) -Wall

AM_LDFLAGS = $(DEPEND_LIBS)

LDADD = $(LIBINTL)

bin_PROGRAMS = hello
hello_SOURCES = hello.c
Internationalization

Now the instructions on how to generate a gnome build system for our application should be nearly working. In order to generate a .tar.gz- archieve of the complete project that contains the full build system just type the following two lines:

./autogen.sh
make dist

What still has to be done is internationalization: A very fine feature of open-source software is that it is possible to translate them to nearlly all languages - and normally sooner or later somebody will have done this.

The only thing that has to be done so our program can easily be internationalized is the following:

  • get a gettext.h file and copy it to your src directory
  • add an #include gettext,h to all source files that contain text that can be translated.
  • add an _( in front of all strings that might be translated and an ) after the string.

Our source file looks now like this:

#include <stdio.h>
#include "gettext.h"

int main()
{
  printf (_("Hello World\n"));
  return 0;
}

Building our new package

I never used the offical openmoko toolchain, so no documentation for this for now - even if I don't think there is any magic there. Since the documentation of the MokoMakefile is rather good, I will document this approach - that I actually used - neither.

Personal tools

Preparation

This guide assumes that you have performed the steps in Building_Openmoko_from_scratch

The commandline program

Store the following more or less standard hello world code in hello.c

#include <stdio.h>

int main()
{
  printf ("Hello World\n");
  return 0;
}

Compiling it the wrong / easy way

Assuming your current working directory is /home/moko, and that you stored the code in /home/moko/hello.c it should now be possible to compile the application using

./build/tmp/cross/arm-linux/bin/gcc -o hello hello.c

Testing it

Assuming you have followed Setting up USB connection and you have a working network connection to either a qemu Neo or a real Neo.

scp hello root@192.168.0.202:/tmp/
ssh root@192.168.0.202 /tmp/hello

This sequence of commands ought to give you a nice Hello World, btw. the default root password is blank, just press return.

GDK the Wrong / Easy Way

Building a GDK application the wrong way is slightly more complex, but is still fun to try. It requires using pkg-config to specify including and linking with the ARM header files and libraries.

Given the following program as main.c:

#include <gtk/gtk.h>

gchar *hello = "Howdy";
gchar *world = "World";
GtkWidget *label;
gchar *labeltext;

void buttoncb(GtkWidget *widget, gpointer data)
{
if (labeltext == hello)
   {
   labeltext = world;
   gtk_label_set_text(GTK_LABEL(label), labeltext);
   }
else if (labeltext == world)
   gtk_main_quit();
}

int main(int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *button;

gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
button = gtk_button_new();
labeltext = hello;
label = gtk_label_new(labeltext);
gtk_container_add(GTK_CONTAINER(button), label);
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(buttoncb), NULL);
gtk_container_add(GTK_CONTAINER(window), button);
gtk_widget_show_all(window);
gtk_main();

return 0;
}

You must first point pkg-config to the proper directory:

export PKG_CONFIG_PATH=/home/username/moko/build/tmp/staging/arm-linux/lib/pkgconfig

And set up an environment variable to make things easier:

export OMDIR=/home/username/moko

The compile/link line is rather long - you will only want to do this once before you decide to create a shell script or make file:

$OMDIR/build/tmp/cross/arm-angstrom-linux-gnueabi/bin/gcc -L $OMDIR/build/tmp/staging/arm-angstrom-linux-gnueabi/lib/ \
                   -Wl, rpath-link, $OMDIR/build/tmp/staging/arm-angstrom-linux-gnueabi/lib/ -Wl, -O1 -g -o hw main.c \
                   '$OMDIR/build/tmp/staging/i686-linux/bin/pkg-config --cflags --libs openmoko-libs gtk+-2.0'


Then copy and run as in the original hello world command line program above.

Why was it the wrong way?

Openmoko provides a precompiled Toolchain package for that. It also comes with some scripts that make your life much easier. Besides, you don't need OpenEmbedded to build applications. If you do want to customize your complete distribution, then read on how to use bitbake when building stuff. In any way, at least you now know that you can easily cross compile for Openmoko.

The Right Way: Using the gnome build system

Even if I am no expert in this - somebody had to make a start so I'll write down everything I still believe to remember from my 1st 'real' gnome application that used the autotools and all: I have never been able to find a good tutorial for making a "canonical" gnome application - and such a tutorial is urgently needed.

Since I know that many of these things will be missing or even inaccurate in the 1st step - if You find out to make it work better or at all - please document how to do this.

Creating the necessary documentation files and directory structure

First of all go into the directory you want to be the topmost application of yout new application, and create the following files:

AUTHORS A list of all authors that took part in developing this project
COPYING The copyright notice. Favourably the GPL
INSTALL This file should contain the information how to build and install this program
README This file should contain all important information about the program including what the program was written for.
NEWS The name of this file should be self-describing
TODO The wishlist of your project
Changelog A list of the major changes to your project

I remember that some of these files were mandatory - it's better create them all

Then create a directory named 'src - and copy the source code of the program there.

The configuration of the autotools

What is to be said to this section is that I included some requirements like gnome-vfs to the requirements not because our application actually needs these packages but because it was very hard to find out how to do so - and I therefore wanted to document how to add them.

If anybody doesn't like this approach - feel free to edit this wiki.

autogen.sh

This file is a shell script that calls all autotools in the right order and with the right parameters so they will in the end generate the standard configure script that will detect how to build our program.

#! /bin/sh
#
# Most if not all of the contents of this file was taken from the openmoko
# sample application as it was shipped with the openmoko toolchain on
# January 31st, 2008
#

srcdir=`dirname $0`
test -z "$srcdir" && srcdir=.

PKG_NAME="hello"

(test -f $srcdir/configure.ac) || {
        echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
        echo " top-level $PKG_NAME directory"
        exit 1
}

which gnome-autogen.sh || {
        echo "You need to install gnome-common from the GNOME CVS"
        exit 1
}

REQUIRED_AUTOMAKE_VERSION=1.7 USE_GNOME2_MACROS=0 REQUIRED_GETTEXT_VERSION=0.10.36 . gnome-autogen.sh
configure.ac

This file tells what the configure script has to do - and which parts of the intelligence delivered with the tools that generate the configure script we need.

I documented every line of which I found out what it actually does. The first line is for to tell the emacs text editor that it has to treat this file as an autoconf file.

#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

# Tell autoconf to check what version of autoconf we need.
AC_PREREQ(2.61)

# Initialize autoconf and tell it what program we wrote, the version
# of our program, and the address bug reports have to be sent to.
AC_INIT([audiorec],[0.2],[audiorec.projects.openmoko.org])

# tell autoconf where to put the temporary files it generates 
AC_CONFIG_AUX_DIR([build-aux])

# This one is thaken from the "Migrationg to gnome Documentation Build
# utilities". No Idea, what it does.
AC_CONFIG_MACRO_DIR([m4])

# give autoconf the name of a file whose existence is a hint that
# autoconf has been started from the right directory. 
AC_CONFIG_SRCDIR([src/diskusagemeter.c])

# Tell autoconf where to put the output file that contains all
# definitions our C program will need
AC_CONFIG_HEADER([src/config.h:src/config.hin])

# Initialize automake, and tell it to tell the C compiler to output as
# many warnings as it can
AM_INIT_AUTOMAKE([-Wall foreign])

# The GNU Gettext version we used for internationalization of our
# program... 
AM_GNU_GETTEXT_VERSION([0.16.1])
# ...Or alternatively the local gnu gettext installation
AM_GNU_GETTEXT([external])

# Check for a C compiler
AC_PROG_CC

# Include all m4 macros that have to do with the language C
AC_LANG_C

# ???
AC_ISC_POSIX

# ???
AC_HEADER_STDC

# Checks for programs.
AC_PROG_CC

# We need the following type definitions from autoconf - or somebody else.
AC_TYPE_INT8_T
AC_TYPE_INT16_T
AC_TYPE_INT32_T

# AC_CHECK_LIB(libgnome-2.0, gnome_help_display_uri, [AC_DEFINE(HAVE_LIBGNOME, 1)])

# Prepare building the gnome documentation of this program
#GNOME_DOC_INIT

# Checks for libraries.
dnl Checking for the required libraries.
GTK_REQUIRED_VERSION=2.0.0
LIBGNOMEUI_REQUIRED_VERSION=2.0.0
GCONF_REQUIRED_VERSION=2.0.0
GNOMEVFS_REQUIRED_VERSION=2.0.0
ALSA_REQUIRED_VERSION=1.0.0
OGG_REQUIRED_VERSION=1.0.0
VORBIS_REQUIRED_VERSION=1.0.0
VORBISENC_REQUIRED_VERSION=1.0.0
PKG_CHECK_MODULES(DEPEND, gtk+-2.0 >= $GTK_REQUIRED_VERSION gconf-2.0 >= $GCONF_REQUIRED_VERSION gnome-vfs-2.0 >= $GNOMEVFS_REQUIRED_VERSION libgnomeui-2.0 >= $LIBGNOMEUI_REQUIRED_VERSION alsa >= $ALSA_REQUIRED_VERSION ogg >= $OGG_REQUIRED_VERSION vorbis >= $VORBIS_REQUIRED_VERSION vorbisenc >= $VORBISENC_REQUIRED_VERSION)

AC_SUBST(DEPEND_CFLAGS)
AC_SUBST(DEPEND_LIBS)

# Gettext wants to know the path to the top directory and such things...
top_builddir=`pwd`
AC_SUBST(top_builddir)
AC_SUBST(PACKAGE)
AC_SUBST(LOCALEDIR)

# Checks for the header files we include.
AC_HEADER_STDC
AC_CHECK_HEADERS([fcntl.h stdlib.h string.h sys/vfs.h])

# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST

# Checks for library functions that we really need.
AC_FUNC_MALLOC

# A list of all configuration files we have to generate
AC_CONFIG_FILES([Makefile src/Makefile src/images/Makefile po/Makefile.in]) #help/Makefile 

# Tell autoconf to start outputting whatever it has to.
AC_OUTPUT
Makefile.am

This file is a template top-level-Makefile that will be filled with life by the configure script.

One thing that is added to the standard Makefile is code for automatically generate the _control-file mentioned above on a make dist

# A list of all subdirectories.
SUBDIRS = src po # help

# Allow automake to interpret m4 macros (needed for interpreting
# gettext's makefile.in
ACLOCAL_AMFLAGS = -I m4
# Files that aren't source files and still have to be in the tarball
EXTRA_DIST = @PACKAGE_NAME@_control

# An (currently unused) extension to the "install" target
install-data-local:

@PACKAGE_NAME@_control: Makefile.am configure.ac
	echo "Package: @PACKAGE_NAME@">$@
	echo "Version: @PACKAGE_VERSION@">>$@
	echo "Description: An voice recorder that can stop recording during silence">>$@
	echo "Section: openmoko/applications">>$@
	echo "Priority: optional">>$@
	echo "Maintainer: your_name">>$@
	echo "Architecture: armv4t">>$@
	echo "Homepage: (The homepage of this project)">>$@
	echo "Depends: gtk+ alsa-lib libogg libvorbis gnome-vfs libgnomeui">>$@
	echo "Source: \$${SRC}">>$@
src/Makefile.am

This file is a template Makefile that when filled with life by the configure script will compile our code.

The most important step here is to tell which files our program consists of.

AM_CFLAGS = $(DEPEND_CFLAGS) -Wall

AM_LDFLAGS = $(DEPEND_LIBS)

LDADD = $(LIBINTL)

bin_PROGRAMS = hello
hello_SOURCES = hello.c
Internationalization

Now the instructions on how to generate a gnome build system for our application should be nearly working. In order to generate a .tar.gz- archieve of the complete project that contains the full build system just type the following two lines:

./autogen.sh
make dist

What still has to be done is internationalization: A very fine feature of open-source software is that it is possible to translate them to nearlly all languages - and normally sooner or later somebody will have done this.

The only thing that has to be done so our program can easily be internationalized is the following:

  • get a gettext.h file and copy it to your src directory
  • add an #include gettext,h to all source files that contain text that can be translated.
  • add an _( in front of all strings that might be translated and an ) after the string.

Our source file looks now like this:

#include <stdio.h>
#include "gettext.h"

int main()
{
  printf (_("Hello World\n"));
  return 0;
}

Building our new package

I never used the offical openmoko toolchain, so no documentation for this for now - even if I don't think there is any magic there. Since the documentation of the MokoMakefile is rather good, I will document this approach - that I actually used - neither.