Maemo软件开发工具包

m (施工)
m (施工)
 
(9 intermediate revisions not shown)
Line 21: Line 21:
在GNU/Linux桌面系统上,Maemo SDK使用[http://scratchbox.org/ Scratchbox]这个开源交叉编译工具,创建了一个沙盒环境。
在GNU/Linux桌面系统上,Maemo SDK使用[http://scratchbox.org/ Scratchbox]这个开源交叉编译工具,创建了一个沙盒环境。
-
在大多数情况下,这个环境就象普通操作一样运行,只不过添加了一些开发工具。
+
在大多数情况下,这个环境就象普通操作系统一样工作,只不过添加了一些开发工具。
这意味着Maemo软件的开发流程与普通桌面Linux程序十分相似。麻烦的嵌入式开发过程,例如交叉编译,都由Scratchbox自动进行。
这意味着Maemo软件的开发流程与普通桌面Linux程序十分相似。麻烦的嵌入式开发过程,例如交叉编译,都由Scratchbox自动进行。
Line 37: Line 37:
当程序在''ARMEL''环境中编译完成后,就可以在手持设备上直接运行了。由于SDK提供的模拟器并不完善,所以实际的测试必须在真实设备上进行。
当程序在''ARMEL''环境中编译完成后,就可以在手持设备上直接运行了。由于SDK提供的模拟器并不完善,所以实际的测试必须在真实设备上进行。
-
== 施工中 Scratchbox ==
+
== Scratchbox ==
Scratchbox是一个特定的“沙盒”环境,提供了一个与真实的Linux系统(通常被称为host machine,宿主机)隔离的开发环境。
Scratchbox是一个特定的“沙盒”环境,提供了一个与真实的Linux系统(通常被称为host machine,宿主机)隔离的开发环境。
Line 51: Line 51:
隔离技术的另一环节,就是库调用转发机制,利用LD_PRELOAD,编译器以及其他程序,都将使用沙盒环境下的函数库。
隔离技术的另一环节,就是库调用转发机制,利用LD_PRELOAD,编译器以及其他程序,都将使用沙盒环境下的函数库。
-
总而言之,Scratchbox是:
+
总而言之,Scratchbox:
-
* 一个实现了开发用沙盒(隔离了真实系统环境)的软件包。
+
* 是一个实现了开发用沙盒(隔离了真实系统环境)的软件包。
* 包含了易于使用的交叉编译工具。
* 包含了易于使用的交叉编译工具。
* 多个开发者可以使用同一个开发系统。
* 多个开发者可以使用同一个开发系统。
Line 59: Line 59:
* 通过被称作sbrsh的机制,以及[http://bellard.org/qemu Qemu]虚拟机的cpu指令翻译,可以在宿主机上运行目标硬件系统的二进制执行文件。
* 通过被称作sbrsh的机制,以及[http://bellard.org/qemu Qemu]虚拟机的cpu指令翻译,可以在宿主机上运行目标硬件系统的二进制执行文件。
-
Besides these main features, it is possible to develop your own software packages that can be installed and used inside a Scratchbox environment. Scratchbox also includes some integration of Debian package management, so that once the source files are set up correctly and a couple of configuration files have been written, binary distribution packages can be created for various architectures (similar to .msi files in Windows, or .rpm files in Fedora Core, RHEL and SUSE). These tools are also used to provide the environment with a packaging database so that other development packages can be installed over the Internet when needed (by using standard Debian package management tools).
+
除了这些主要的特性以外,你也可以自己开发能够在Scratchbox环境中安装的软件包。
-
Fremantle also uses a similar packaging system, and this means that packages built using Scratchbox and the SDK can be installed on the real device.
+
Scratchbox已经整合了Debian的包管理器,因此,只要正确地编写了配置文件,就可以为不同架构的平台编译创建二进制软件包(deb文件,与Windows下的msi文件,Fedora/RHEL的rpm文件类似)。
-
Scratchbox is licensed under the GPL and it is open for outside contributions. For in-depth coverage on Scratchbox and its capabilities, please visit the [http://scratchbox.org project website].
+
同时,你也可以使用标准的Debian包管理工具,通过互联网下载安装你所需要的软件包。
-
This material discusses only the Scratchbox capabilities that are necessary to use the Maemo SDK.
+
Maemo 5 Fremantle 也使用了相同的包管理机制,在Scratchbox下创建的软件包,可以直接安装到真实的物理设备上。
 +
Scratchbox以GPL证书发布,欢迎外界的捐助。以上内容仅涉及了Scratchbox与Maemo 5 SDK相关的部分。如果需要深入了解Scratchbox的细节,请访问[http://scratchbox.org Scratchbox项目主页]。
-
===Scratchbox In-Depth===
 
-
Scratchbox is Maemo SDK's cross-compiling environment. The default Scratchbox installation works as-is under most conditions, but some details are good to know for more specialized usage.
+
=== 深入Scratchbox ===
-
The ''target'' inside Scratchbox contains a root file system. When you create a new target inside Scratchbox, specify the ''toolchain'' you will use to build applications. Examples of a ''target'' include X86 and ARMEL, provided by Maemo SDK on top of Scratchbox.
+
Scratchbox是Maemo SDK使用的交叉编译环境。在大多数情况下,默认安装的Scratchbox就能顺利工作。但如果你有特殊的需要,那么有必要了解一些Scratchbox的细节。
-
''Host tools'' are native to the host, provided for convenience and speed. They are always transparently preferred over target tools. For example, cross-compiling applications to the target architecture. Host tools consist of devkits and ''toolchains''.
+
''目标环境''(''target''),是Scratchbox建立的一个根文件系统,当你在Scratchbox里创建了一个''目标环境''后,就指定了''工具链''(''toolchain''),用于创建你的应用程序。Maemo SDK创建了两个''目标环境''——X86(FREMANTLE_X86)和ARMEL(FREMANTLE_ARMEL)。
-
A toolchain provides the minimal set of tools for compiling binaries for the target. Each scratchbox target must have one and only one toolchain selected.
+
''宿主工具''(''Host tools'')是宿主机环境下的原生程序,提供了最佳的可用性与性能。他们始终在目标环境外透明地执行。举例来说,宿主工具包含''开发工具''(''devkit'')与''工具链''(''toolchains'')。这些工具为目标架构创建可运行的二进制程序,
-
''CPU transparency methods'' take care of running the applications on an emulator, target device or directly on the host transparently from the user's perspective. The available CPU transparency methods come from a special ''devkit'' called ''cputransp''. For each of Maemo SDK's pre-defined targets, a CPU transparency method is selected and defined.
+
''开发工具''''devkit'')是一组开发工具,他们是宿主机系统下的原生程序。每个''开发工具''都可以针对某个目标环境单独启用。举例来说,doctool是一个开发工具,用来创建文档(类似doxygen),你可以在每个目标环境下单独启用/禁用该工具。
-
A ''toolchain'' is a collection of tools used to produce binaries for the target environment. In addition to a compiler (''gcc''), the toolchain contains a linker (''ld'') and other ''binutils'', such as ''strip'', ''objdump'' and ''strings''.
+
''工具链''(''toolchains'')提供了最基本的编译工具集合,每一个Scratchbox目标环境都必须指定一个工具链。工具链为目标环境创建,处理二进制文件。除了编译器(''gcc'')外,工具链还包括了一个链接器(''ld'')以及其他''二进制工具包''(''binutils''),例如''strip''(去除文件中的调试信息),''objdump''(二进制文件分析器)和''string''(显示文件中的可打印字符)。
-
A ''devkit'' is a collection of tools native to the host. A devkit can be selected or disabled for a target. An example of a devkit is the doctools devkit, which provides tools (like doxygen) for building documentation.
+
''CPU译码器''(''CPU transparency methods'')提供了在模拟器中运行目标架构程序的能力。Maeomo SDK官方支持的宿主机系统是x86架构的Linux系统,而实际设备的cpu却可能是arm架构的。''CPU译码器''解决了在x86设备上运行arm程序的问题。用户可以在编译阶段,选择一个程序是为了宿主系统,还是目标系统(arm或是x86)编译。Maamo SDK包含的''开发工具''(''devkit'')中,一个名为''cputransp''的工具包提供了这一功能,这个工具包提供了完整的配置,并且会被默认选中安装。
-
A ''rootstrap'' is a root file system for the target device. Maemo SDK provides root file systems for both targets (X86 and ARMEL) inside Scratchbox. Note that the user's home directory is shared for all targets. The ''/tmp'' directory is shared for all targets and also with the host.
+
''根文件系统包''(''rootstrap'')包含了一个目标设备的根文件系统。Maemo SDK为每个目标环境(X86和ARMEL)各自提供了Scratchbox环境下的根文件系统包。需要提醒的是,两个目标环境的home目录是共享的。而''/tmp''目录同时在宿主机和两个目标环境间共享。
-
From Scratchbox's point of view, Maemo SDK is a set of preconfigured ''targets'' and ''root file system''s. One set is provided for both ''X86'' and ''ARMEL'' architectures on top of a working Scratchbox installation.
+
大体上,Maemo SDK这样进行目标环境的配置。
-
==Development on Maemo SDK==
+
首先,在Scratchbox环境中创建了两个''目标环境''——''X86''和''ARMEL''。
 +
 
 +
然后为目标环境选择''开发工具'',其中包括''cpu译码器''和''toolchain''等关键工具。你还可以选择''doctool''和''debian sys''等系统辅助工具。
 +
 
 +
最后将''根文件系统''解包复制到目标环境中,这样就完成了目标环境的配置。
 +
 
 +
== 施工中 使用Maemo SDK进行开发 ==
The Maemo SDK provides all of its development tools inside Scratchbox. Also the UI framework is started with a single command, ''af-sb-init'', run within Scratchbox. However, it needs a secondary X server of proper size and bit-depth to be displayed on.
The Maemo SDK provides all of its development tools inside Scratchbox. Also the UI framework is started with a single command, ''af-sb-init'', run within Scratchbox. However, it needs a secondary X server of proper size and bit-depth to be displayed on.

Latest revision as of 02:51, 13 February 2010

Contents

[edit] Maemo SDK

本文是Maemo SDK的简体中文翻译。

在本章节中,会用到下列示例源代码:

在桌面计算机上运行的Maemo开发环境被称作Maemo SDK(Maemo Software Development Kit - Maemo软件开发工具包)。你只能在Linux系统上安装Maemo SDK。目前,Maemo SDK支持以下Linux发行版:

  • Debian
  • Ubuntu

你也可以在其他Linux发行版上安装Maemo SDK。

[edit] Maemo软件开发工具包

在GNU/Linux桌面系统上,Maemo SDK使用Scratchbox这个开源交叉编译工具,创建了一个沙盒环境。

在大多数情况下,这个环境就象普通操作系统一样工作,只不过添加了一些开发工具。

这意味着Maemo软件的开发流程与普通桌面Linux程序十分相似。麻烦的嵌入式开发过程,例如交叉编译,都由Scratchbox自动进行。

[edit] 硬件架构

Maemo SDK支持两种架构,X86ARMEL,同时提供两种开发环境。在Fremantle中,X86环境是主要的开发环境,无须进行硬件模拟,从而拥有更好的支持与运行效率。

ARMEL目标环境仅用于进行交叉编译,使程序可以手持设备上运行。

另外,需要注意的是,qemu(一个Linux下常用的虚拟机,被Scratchbox用作CPU指令译码器)无法在ARMEL目标环境下运行用户界面。

当你的程序在X86环境中顺利编译运行后,你可以在ARMEL环境下重新编译程序。编译与打包过程与在X86环境中完全相同,不过会慢一些,因为一些操作需要软件模拟执行。Scratchbox会进行交叉编译,开发者无须考虑这些问题。

当程序在ARMEL环境中编译完成后,就可以在手持设备上直接运行了。由于SDK提供的模拟器并不完善,所以实际的测试必须在真实设备上进行。

[edit] Scratchbox

Scratchbox是一个特定的“沙盒”环境,提供了一个与真实的Linux系统(通常被称为host machine,宿主机)隔离的开发环境。

Scratchbox也简化了交叉编译:软件直接被编译成可以在目标设备上运行的二进制格式。

“Scratchbox”这个名字源于“Linux from scratch”和“chroot jail”。这也解释了它的实现和用法。

当你在Scratchbox环境下工作时,程序将在一个更改过的root环境(chroot)下运行。在Linux系统中,在进程中改变文件路径是可能的。Scratchbox利用了这一机制,在启动后将根目录(/)转换到了实际根目录以外的路径下。

这是隔离技术的一个重要组成部分。因此,这个环境被称为“沙盒”,一个可以任意玩耍,无须担心影响真实系统环境的区域。

隔离技术的另一环节,就是库调用转发机制,利用LD_PRELOAD,编译器以及其他程序,都将使用沙盒环境下的函数库。

总而言之,Scratchbox:

  • 是一个实现了开发用沙盒(隔离了真实系统环境)的软件包。
  • 包含了易于使用的交叉编译工具。
  • 多个开发者可以使用同一个开发系统。
  • 每个开发者可以各自独立进行配置。
  • 通过被称作sbrsh的机制,以及Qemu虚拟机的cpu指令翻译,可以在宿主机上运行目标硬件系统的二进制执行文件。

除了这些主要的特性以外,你也可以自己开发能够在Scratchbox环境中安装的软件包。

Scratchbox已经整合了Debian的包管理器,因此,只要正确地编写了配置文件,就可以为不同架构的平台编译创建二进制软件包(deb文件,与Windows下的msi文件,Fedora/RHEL的rpm文件类似)。

同时,你也可以使用标准的Debian包管理工具,通过互联网下载安装你所需要的软件包。

Maemo 5 Fremantle 也使用了相同的包管理机制,在Scratchbox下创建的软件包,可以直接安装到真实的物理设备上。

Scratchbox以GPL证书发布,欢迎外界的捐助。以上内容仅涉及了Scratchbox与Maemo 5 SDK相关的部分。如果需要深入了解Scratchbox的细节,请访问Scratchbox项目主页


[edit] 深入Scratchbox

Scratchbox是Maemo SDK使用的交叉编译环境。在大多数情况下,默认安装的Scratchbox就能顺利工作。但如果你有特殊的需要,那么有必要了解一些Scratchbox的细节。

目标环境target),是Scratchbox建立的一个根文件系统,当你在Scratchbox里创建了一个目标环境后,就指定了工具链toolchain),用于创建你的应用程序。Maemo SDK创建了两个目标环境——X86(FREMANTLE_X86)和ARMEL(FREMANTLE_ARMEL)。

宿主工具Host tools)是宿主机环境下的原生程序,提供了最佳的可用性与性能。他们始终在目标环境外透明地执行。举例来说,宿主工具包含开发工具devkit)与工具链toolchains)。这些工具为目标架构创建可运行的二进制程序,

开发工具devkit)是一组开发工具,他们是宿主机系统下的原生程序。每个开发工具都可以针对某个目标环境单独启用。举例来说,doctool是一个开发工具,用来创建文档(类似doxygen),你可以在每个目标环境下单独启用/禁用该工具。

工具链toolchains)提供了最基本的编译工具集合,每一个Scratchbox目标环境都必须指定一个工具链。工具链为目标环境创建,处理二进制文件。除了编译器(gcc)外,工具链还包括了一个链接器(ld)以及其他二进制工具包binutils),例如strip(去除文件中的调试信息),objdump(二进制文件分析器)和string(显示文件中的可打印字符)。

CPU译码器CPU transparency methods)提供了在模拟器中运行目标架构程序的能力。Maeomo SDK官方支持的宿主机系统是x86架构的Linux系统,而实际设备的cpu却可能是arm架构的。CPU译码器解决了在x86设备上运行arm程序的问题。用户可以在编译阶段,选择一个程序是为了宿主系统,还是目标系统(arm或是x86)编译。Maamo SDK包含的开发工具devkit)中,一个名为cputransp的工具包提供了这一功能,这个工具包提供了完整的配置,并且会被默认选中安装。

根文件系统包rootstrap)包含了一个目标设备的根文件系统。Maemo SDK为每个目标环境(X86和ARMEL)各自提供了Scratchbox环境下的根文件系统包。需要提醒的是,两个目标环境的home目录是共享的。而/tmp目录同时在宿主机和两个目标环境间共享。

大体上,Maemo SDK这样进行目标环境的配置。

首先,在Scratchbox环境中创建了两个目标环境——X86ARMEL

然后为目标环境选择开发工具,其中包括cpu译码器toolchain等关键工具。你还可以选择doctooldebian sys等系统辅助工具。

最后将根文件系统解包复制到目标环境中,这样就完成了目标环境的配置。

[edit] 施工中 使用Maemo SDK进行开发

The Maemo SDK provides all of its development tools inside Scratchbox. Also the UI framework is started with a single command, af-sb-init, run within Scratchbox. However, it needs a secondary X server of proper size and bit-depth to be displayed on.

As an exception to the rule, you must start the Xserver, such as Xephyr on the host Linux environment, not inside Scratchbox.


[edit] Scratchbox Development Tools

As the Scratchbox environment is practically a full GNU/Linux system, it includes the standard GNU/Linux development tools. Debugging is performed with tools like gdb, valgrind, ltrace and strace. Performance profiling can be performed with tools like htop, oprofile and time. Compiling is done with the GCC toolchain. Some of these tools offer graphical user interfaces, which can also be used. Naturally, this is not a comprehensive list of the tools, and if the tools shipped with the SDK do not suit your needs or personal preferences, most utilities can be easily run practically unchanged in Scratchbox.


[edit] Other Programming Languages

Currently C is the only official programming language for Maemo. But thanks to the community, Python scripting language also has a good support in the form of pymaemo. C++ support for Scratchbox is also available.

[edit] Installing SDK

Before continuing, review the installation instructions of the Maemo SDK.

The kernel must support binfmt_misc-feature in order for the instruction emulator in Scratchbox to work properly. Because it is usually built as a module, verify that the module is loaded in Linux (no root access needed):

user@system:~$ lsmod | grep binfmt
binfmt_misc 12936 0

If you do not see a line of output, try to execute modprobe binfmt_misc as root (or with sudo). If this still does not work, either locate the module elsewhere, or recompile the kernel. Most Debian-based systems (Debian, Ubuntu) include the module, unless you have built your own kernel, you should encounter no problems. The feature may also be directly built inside the kernel instead of being a module.

Install a pseudo X server to act as an X client to the real system in order to run application developed after installing the SDK. You have a certain amount of freedom to choose the most suitable option to achieve this, but this material assumes that you are using Xephyr, a Kdrive-based X server/client that can emulate 16-color depth for its clients even while acting as a client to an 24-bit depth real X server. Xephyr also implements modern X protocol extensions.

The concept of having a program that is both X server and a client may seem weird, but it is a tested technology and works quite well.

To install Xephyr on a Debian-based Linux:

  • Issue the command sudo apt-get install xserver-xephyr on your real Linux system.
  • Verify installation status by issuing the command 'dpkg -l | grep xephyr' (as non-root).

As mentioned before, Maemo SDK uses Scratchbox as the cross-compilation environment. Therefore, you must install Scratchbox first before attempting to install the SDK. The preferred way to install scratchbox and SDK is to use the automated installation scripts though manual installation steps are also provided. Detailed instructions are found here.

[edit] Testing SDK Installation

[edit] Testing Scratchbox

The following shows how to create a small non-graphical Hello World program to verify that the Scratchbox environment works: helloworld.c

/**
 * helloworld.c
 *
 * This maemo code example is licensed under a MIT-style license,
 * that can be found in the file called "License" in the same
 * directory as this file.
 * Copyright (c) 2007-2008 Nokia Corporation. All rights reserved.
 *
 * Simple standard I/O (printf)-based Hello World that we can use to
 * test our toolchains.
 */

#include <stdio.h> /* printf */

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

  printf("Hello world\n");

  /* In Linux, each process upon termination must set its exit code.
     Exit code 0 means success to whoever executed this program. It
     is routinely used inside scripts to test whether running some
     program succeeded or not. Other exit codes mean failure. Each
     program is free to use different non-zero codes to signify
     different kinds of failures. These are normally listed in the
     manual page for the program (since there is no standard). If you
     forget to set your exit code, it will be undefined. */
  return 0;
}

First, verify that the proper directory is chosen by using pwd (print working directory). At this point, the work directory should be your home directory:

[sbox-FREMANTLE_X86: ~] > pwd
/home/user


Then, start an editor and write a small hello world program (you may use the above code listing as a template if you wish):

[sbox-FREMANTLE_X86: ~] > nano helloworld.c

It is also possible to use vi (Visual Interactive) editor inside Scratchbox. You can install your own favourite editor inside sbox (with the debian-devkit), but the following examples will use nano, because it is the easiest to start with. If you want to learn vi, your best course of action is searching for "vi tutorial" with your favourite search engine. There are lots of them to be found. To understand why vi can be considered "strange", it is useful to know its history first. Using vi is fully optional.

[sbox-FREMANTLE_X86: ~] > gcc -Wall -g helloworld.c -o helloworld
[sbox-FREMANTLE_X86: ~] > ls -F hello*
helloworld* helloworld.c

GCC's -g option tells the compiler to add debugging symbols to the generated output file. -Wall will tell the compiler to enable most of the syntax and other warnings that the source code could trigger. -o helloworld tells gcc to output the resulting binary with the filename of helloworld.

The -F option to ls is mainly useful when working with a non-color terminal (for example paper) to indicate the type of different files. The asterisk after helloworld signifies that the file is executable.

[sbox-FREMANTLE_X86: ~] > ./helloworld
Hello world

Running the binary should not produce any surprises.


[sbox-FREMANTLE_X86: ~] > file helloworld
helloworld: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV),
for GNU/Linux 2.6.0, dynamically linked (uses shared libs), not stripped

The file tool is a generic utility that loads some bytes from the start of the given file and then uses its internal database to decode what type of file it is. In this case, it will correctly decode the file as a X86 format binary file.

[sbox-FREMANTLE_X86: ~] > ldd helloworld
   linux-gate.so.1 =>  (0xffffe000)
   libc.so.6 => /lib/libc.so.6 (0xb7e9f000)
   /lib/ld-linux.so.2 (0xb7fd2000)
[sbox-FREMANTLE_X86: ~] > ls -l /lib/libc.so.6
lrwxrwxrwx  1 user user 11 Nov 12 15:52 /lib/libc.so.6 -> libc-2.5.so
[sbox-FREMANTLE_X86: ~] > ls -l /lib/libc-2.5.so
-rwxr-xr-x  1 user user 1213256 Sep  7 13:28 /lib/libc-2.5.so


On the left are the names of dynamic libraries that the executable uses, and on the right are the files where the libraries reside on the system when executing the program. Next use ls to check the exact version of the C library that the SDK uses with the "long listing format" -l option. Running these commands using the ARMEL target yields more or less the same results. N.B. The linux-gate.so.1 is a so-called hack to support a certain way of doing system calls on the X86 architecture, and is not always present on newer systems.

When comparing the version of libc used on the real system with ls -l, it will probably show a difference (in version numbers). This means that the executables that were built inside Scratchbox use libraries that are also inside Scratchbox. This also means we have a stable development platform, which is very important, especially when working on a team where each member has their own Linux installation which they may or may not have customized. This might not seem very important at this stage, but when encountering all the different tools that are used in free software development, this feature of Scratchbox will come in handy.

Scratchbox does not contain any logic to emulate the kernel (or to use a different kernel for running programs inside Scratchbox). The only easy possibility for this is using the sbrsh CPU-transparency option.

[edit] vi

You can also use vi (Visual Interactive) editor inside sbox. You can install your own favorite editor inside Scratchbox (with the debian-devkit), but the following examples will use nano, since it is the easiest to start with. If you want to learn vi, search for "vi tutorial" with your favorite search engine. There are lots of them to be found. To understand why vi can be considered "strange", it is useful to know its history first. Using vi is fully optional. It is common for people who are new to vi to get stuck in it; if you find yourself in this situation, a way to exit (without writing the file) is to press type <escape>:qall!<enter>.

The vi that is commonly installed on Linux systems is really vim (VI iMproved), which is a more user-friendly version of vi, including syntax high-lighting and all kinds of improvements. sbox has a program called vimtutor installed to help you learn how to use vi interactively.

It is also fairly simple to use existing editors. /scratchbox/users/x/home/x/ is the home directory of user x when accessing it from the real Linux desktop. Ubuntu comes with Gedit, which is a fairly good graphical editor that also supports syntax highlighting and multiple tabs for editing multiple files at the same time.

And as a final note, emacs can also be used.

Here is how to do use it:

  • Start emacs outside of Scratchbox
  • In emacs, use M-x server-start
  • Inside Scratchbox, use the emacsclient filename to open the file for editing in your emacs

[edit] Writing GUI Hello World

The following example shows how to write the first GUI program. Note that the example only uses the GTK+ library and does not utilise the widgets and coding style provided by the platform. That will be discussed later.

gtk_helloworld-1.c

/**
 * gtk_helloworld-1.c
 *
 * This maemo code example is licensed under a MIT-style license,
 * that can be found in the file called "License" in the same
 * directory as this file.
 * Copyright (c) 2007-2008 Nokia Corporation. All rights reserved.
 *
 * A simple GTK+ Hello World. You need to use Ctrl+C to terminate
 * this program since it doesn't implement GTK+ signals (yet).
 */

#include <stdlib.h> /* EXIT_* */
/* Introduce types and prototypes of GTK+ for the compiler. */
#include <gtk/gtk.h>

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

  /* We'll have two references to two GTK+ widgets. */
  GtkWindow* window;
  GtkLabel* label;

  /* Initialize the GTK+ library. */
  gtk_init(&argc, &argv);

  /* Create a window with window border width of 12 pixels and a
     title text. */
  window = g_object_new(GTK_TYPE_WINDOW,
    "border-width", 12,
    "title", "Hello GTK+",
    NULL);

  /* Create the label widget. */
  label = g_object_new(GTK_TYPE_LABEL,
    "label", "Hello World!",
    NULL);

  /* Pack the label into the window layout. */
  gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(label));

  /* Show all widgets that are contained by the window. */
  gtk_widget_show_all(GTK_WIDGET(window));

  /* Start the main event loop. */
  g_print("main: calling gtk_main\n");
  gtk_main();

  /* Display a message to the standard output and exit. */
  g_print("main: returned from gtk_main and exiting with success\n");

  /* The C standard defines this condition as EXIT_SUCCESS, and this
     symbolic macro is defined in stdlib.h (which GTK+ will pull in
     in-directly). There is also a counter-part for failures:
     EXIT_FAILURE. */
  return EXIT_SUCCESS;
}

Build your program:

[sbox-FREMANTLE_X86: ~] > gcc -Wall -g gtk_helloworld-1.c -o gtk_helloworld-1
gtk_helloworld-1.c:15:21: gtk/gtk.h: No such file or directory
gtk_helloworld-1.c: In function `main':
gtk_helloworld-1.c:20: error: `GtkWindow' undeclared (first use in this function)
gtk_helloworld-1.c:20: error: (Each undeclared identifier is reported only once
gtk_helloworld-1.c:20: error: for each function it appears in.)
gtk_helloworld-1.c:20: error: `window' undeclared (first use in this function)
gtk_helloworld-1.c:21: error: `GtkLabel' undeclared (first use in this function)
gtk_helloworld-1.c:21: error: `label' undeclared (first use in this function)
gtk_helloworld-1.c:24: warning: implicit declaration of function `gtk_init'
gtk_helloworld-1.c:28: warning: implicit declaration of function `g_object_new'
gtk_helloworld-1.c:28: error: `GTK_TYPE_WINDOW' undeclared (first use in this function)
gtk_helloworld-1.c:34: error: `GTK_TYPE_LABEL' undeclared (first use in this function)
gtk_helloworld-1.c:39: warning: implicit declaration of function `gtk_container_add'
gtk_helloworld-1.c:39: warning: implicit declaration of function `GTK_CONTAINER'
gtk_helloworld-1.c:39: warning: implicit declaration of function `GTK_WIDGET'
gtk_helloworld-1.c:42: warning: implicit declaration of function `gtk_widget_show_all'
gtk_helloworld-1.c:45: warning: implicit declaration of function `g_print'
gtk_helloworld-1.c:46: warning: implicit declaration of function `gtk_main'


This does not look at all promising. The source code started with #include, and you need to tell the compiler where to look for that critical GTK+ header file. The compiler probably also needs some special flags to be able to use the correct compilation settings for building GTK+ software.

To help you decide which flags to use we provide a tool called pkg-config, which is a simple program that provides a unified interface to output compiler, linker flags and library version numbers. Use pkg-config manually for the time being.

[sbox-FREMANTLE_X86: ~] > pkg-config --list-all | sort
.. listing cut to include only relevant libraries ..
dbus-glib-1    dbus-glib - GLib integration for the free desktop message bus
gconf-2.0      gconf - GNOME Config System.
gdk-2.0        GDK - GIMP Drawing Kit (x11 target)
gdk-pixbuf-2.0 GdkPixbuf - Image loading and scaling
glib-2.0       GLib - C Utility Library
gnome-vfs-2.0  gnome-vfs - The GNOME virtual file-system libraries
gtk+-2.0       GTK+ - GIMP Tool Kit (x11 target)
hildon-1       hildon - Hildon widgets library
hildon-fm-2    hildon-fm - Hildon file management widgets
pango          Pango - Internationalized text handling
x11            X11 - X Library


pkg-config also has some other useful commands:

[sbox-FREMANTLE_X86: ~] > pkg-config --modversion gtk+-2.0
2.10.12


[sbox-FREMANTLE_X86: ~] > pkg-config --cflags gtk+-2.0
-I/usr/include/gtk-2.0 -I/usr/lib/gtk-2.0/include -I/usr/include/atk-1.0
-I/usr/include/cairo -I/usr/include/pango-1.0 -I/usr/include/glib-2.0
-I/usr/lib/glib-2.0/include -I/usr/include/freetype2
-I/usr/include/libpng12


In this version of GTK+, all these commands are -I options that tell the compiler which additional directories to check for system header files in addition to the default ones.

[sbox-FREMANTLE_X86: ~] > pkg-config --libs gtk+-2.0
-lgtk-x11-2.0 -lgdk-x11-2.0 -latk-1.0 -lgdk_pixbuf-2.0 -lm
-lpangocairo-1.0 -lpango-1.0 -lcairo -lgobject-2.0 -lgmodule-2
-ldl -lglib-2.0


When linking the application, the linker has to be told which libraries to link against. In fact, the whole program linking phase will fail (as shown below) without this information.

Now compile the software again, and this time use the compilation flags that pkg-config provides:


 [sbox-FREMANTLE_X86: ~] > gcc -Wall -g gtk_helloworld-1.c  \
  `pkg-config --cflags gtk+-2.0` -o gtk_helloworld-1
 /var/tmp/ccQ14x4c.o: In function `main':/home/user/gtk_helloworld-1.c:24:
  undefined reference to `gtk_init'
 :/home/user/gtk_helloworld-1.c:28: undefined reference to `gtk_window_get_type'
 :/home/user/gtk_helloworld-1.c:28: undefined reference to `g_object_new'
 :/home/user/gtk_helloworld-1.c:34: undefined reference to `gtk_label_get_type'
 :/home/user/gtk_helloworld-1.c:34: undefined reference to `g_object_new'
 :/home/user/gtk_helloworld-1.c:39: undefined reference to `gtk_widget_get_type'
 :/home/user/gtk_helloworld-1.c:39: undefined reference to `g_type_check_instance_cast'
 :/home/user/gtk_helloworld-1.c:39: undefined reference to `gtk_container_get_type'
 :/home/user/gtk_helloworld-1.c:39: undefined reference to `g_type_check_instance_cast'
 :/home/user/gtk_helloworld-1.c:39: undefined reference to `gtk_container_add'
 :/home/user/gtk_helloworld-1.c:42: undefined reference to `gtk_widget_get_type'
 :/home/user/gtk_helloworld-1.c:42: undefined reference to `g_type_check_instance_cast'
 :/home/user/gtk_helloworld-1.c:42: undefined reference to `gtk_widget_show_all'
 :/home/user/gtk_helloworld-1.c:45: undefined reference to `g_print'
 :/home/user/gtk_helloworld-1.c:46: undefined reference to `gtk_main'
 :/home/user/gtk_helloworld-1.c:49: undefined reference to `g_print'
 collect2: ld returned 1 exit status
 


The command above may be new to you, if you have not used UNIX command shells. This is a backtick expansion, an operation where the shell starts another shell only to execute the text inside the backticks. In this case, start another shell to run `pkg-config --cflags gtk+-2.0`. Normal output from the commands is then read into the main shell and the output is replaced into the location where the backticks were. N.B. Use the backtick character (`) or falling accent. Do not use a rising accent (´) or a single quote or apostrophe ('). In some keyboard layouts, you can get the backtick character to appear by pressing first the backtic and then the space bar.

An alternative operation is $(pkg-config ..), which corresponds to the backtick but is less portable across antique UNIX shells. Choosing between these is a matter of taste.

GCC prints very different errors this time. These errors come from ld, which is the binary code linker in Linux systems and complains about missing symbols (the undefined references). Obviously something is still missing.

You must tell the linker where to find the missing symbols. Because this is the linker and not the compiler that we are talking about, the missing symbols are in the library files.

To fix the problem (again using backticks), pkg-config libs can be used:


[sbox-FREMANTLE_X86: ~] > gcc -Wall -g gtk_helloworld-1.c  \
 `pkg-config --cflags gtk+-2.0` -o gtk_helloworld-1  \
 `pkg-config --libs gtk+-2.0`
[sbox-FREMANTLE_X86: ~] >


The order and placement of the pkg-config commands above is important: you must place the cflags as early as feasible and ensure that the libs must come last (this does matter in some problematic linking scenarios).

The next step is to repeat the basic commands that you used before with the non-GUI hello world:


[sbox-FREMANTLE_X86: ~] > ls -l gtk_helloworld-1
-rwxrwxr-x  1 user user 16278 Nov 20 00:22 gtk_helloworld-1
[sbox-FREMANTLE_X86: ~] > file gtk_helloworld-1
gtk_helloworld-1: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV),
for GNU/Linux 2.6.0, dynamically linked (uses shared libs), not stripped
[sbox-FREMANTLE_X86: ~] > ldd gtk_helloworld-1
  linux-gate.so.1 =>  (0xffffe000)
  libgtk-x11-2.0.so.0 => /usr/lib/libgtk-x11-2.0.so.0 (0xb7c4c000)
  libgdk-x11-2.0.so.0 => /usr/lib/libgdk-x11-2.0.so.0 (0xb7bc8000)
  libatk-1.0.so.0 => /usr/lib/libatk-1.0.so.0 (0xb7bad000)
  libgdk_pixbuf-2.0.so.0 => /usr/lib/libgdk_pixbuf-2.0.so.0 (0xb7b97000)
  libm.so.6 => /lib/libm.so.6 (0xb7b71000)
  libpangocairo-1.0.so.0 => /usr/lib/libpangocairo-1.0.so.0 (0xb7b68000)
  libpango-1.0.so.0 => /usr/lib/libpango-1.0.so.0 (0xb7b2b000)
  libcairo.so.2 => /usr/lib/libcairo.so.2 (0xb7ab5000)
  libgobject-2.0.so.0 => /usr/lib/libgobject-2.0.so.0 (0xb7a7a000)
  libgmodule-2.0.so.0 => /usr/lib/libgmodule-2.0.so.0 (0xb7a76000)
  libdl.so.2 => /lib/libdl.so.2 (0xb7a71000)
  libglib-2.0.so.0 => /usr/lib/libglib-2.0.so.0 (0xb79dd000)
  libc.so.6 => /lib/libc.so.6 (0xb78b2000)
  libX11.so.6 => /usr/lib/libX11.so.6 (0xb77bd000)
  libXfixes.so.3 => /usr/lib/libXfixes.so.3 (0xb77b8000)
  libXtst.so.6 => /usr/lib/libXtst.so.6 (0xb77b3000)
  libfontconfig.so.1 => /usr/lib/libfontconfig.so.1 (0xb7788000)
  libXext.so.6 => /usr/lib/libXext.so.6 (0xb777a000)
  libXrender.so.1 => /usr/lib/libXrender.so.1 (0xb7771000)
  libXi.so.6 => /usr/lib/libXi.so.6 (0xb7769000)
  libXrandr.so.2 => /usr/lib/libXrandr.so.2 (0xb7762000)
  libXcursor.so.1 => /usr/lib/libXcursor.so.1 (0xb7759000)
  /lib/ld-linux.so.2 (0xb7fc3000)
  libpangoft2-1.0.so.0 => /usr/lib/libpangoft2-1.0.so.0 (0xb772b000)
  libfreetype.so.6 => /usr/lib/libfreetype.so.6 (0xb76c6000)
  libz.so.1 => /usr/lib/libz.so.1 (0xb76b7000)
  libpng12.so.0 => /usr/lib/libpng12.so.0 (0xb7692000)
  libXau.so.6 => /usr/lib/libXau.so.6 (0xb768f000)
  libXdmcp.so.6 => /usr/lib/libXdmcp.so.6 (0xb7689000)
  libexpat.so.1 => /usr/lib/libexpat.so.1 (0xb7669000)


As you can see from the last ldd listing, this simple Hello World requires several other libraries to run. The program itself only requires GTK+, but GTK+ needs GDK and all the other libraries that were covered in the introduction. Those libraries in turn need other libraries and so on.

This is almost the full list of all required libraries to run. Modern UNIX systems (and Linux) can also load other libraries on demand (called runtime dynamic module loading).

Perhaps you are wondering why writing a simple Hello World is so demanding. It is actually much simpler in real life. This chapter simply introduces and solves various problems that you may encounter in actual situations.

You need all of these tools later on when starting the packaging of the software.

[edit] Running GUI Hello World

Let's try to execute Hello World inside Scratchbox:

[sbox-FREMANTLE_X86: ~] > ./gtk_helloworld-1
gtk_helloworld-1[4759]: GLIB WARNING ** Gtk - cannot open display:
[sbox-FREMANTLE_X86: ~] > echo $DISPLAY


GTK+ seems unable to open connection to the X server. To verify this, display the contents of the DISPLAY environmental variable; indeed, the variable is empty. If the DISPLAY variable contains :0.0, the value originates in the graphical session and was copied into Scratchbox. Clients try to connect to the real X server and probably fail during authentication.

[edit] Starting Virtual X Server (Xephyr)

Run Xephyr outside the scratchbox environment:

$ Xephyr :2 -host-cursor -screen 800x480x16 -dpi 96 -ac -kb &

[edit] Directing Client to Virtual Server

Now that there is an X server running, switch back to Scratchbox.

The first step is to set the environmental variable so that X server knows to use a local domain socket, and tell all X clients to connect to Display number 2, since that is where Xephyr started:

 [sbox-FREMANTLE_X86: ~] > export DISPLAY=:2
 [sbox-FREMANTLE_X86: ~] > ./gtk_helloworld-1
 main: calling gtk_main
 [[Ctrl+c]]
 


Use Ctrl+C to terminate the program because it does not implement any graphical methods for closing.

N.B. The DISPLAY needs to be set correctly on each Scratchbox login (or when switching targets).

Since you did not start a window manager for the X server, you cannot control Hello World with the mouse. Use Ctrl+C to terminate Hello World; you will start it again in a moment.

To quickly detach the foreground process from the shell and continue running the process in the background, press Ctrl+Z and then use the shell command bg. The process is "paused" between these two steps.

[edit] Starting Application Framework

The next step is to have a graphical environment that will implement a nicer graphical screen. For this, a series of clients will be started, each of which have a specific role. These were introduced before.

To start the UI Framework, you can use a handy script that comes with the SDK:

[sbox-FREMANTLE_X86: ~] > af-sb-init.sh start

The start and stop parameters are used to start and stop the graphical environment. If everything works, it should show a screen resembling this one:


[edit] Running Hello World in Application Framework

While the UI framework is running, the Hello World can be started again

[sbox-FREMANTLE_X86: ~] >./gtk_helloworld-1

Because there now is a window manager running, the client gets much larger window to draw in. GTK+ scales the widget accordingly (there is only one widget in the program).

The screen still looks a bit off. If the application is closed by pressing the X in the top-right corner, you can see that the Hello World disappears from the screen. Because no signals have been implemented yet and thus there is nothing to handle window destruction, the Hello World application is only hidden. It is still running (as can be seen in the sbox terminal emulator, since the shell does not display its prompt). Stop the Hello World program with Ctrl+C.

The next step shows how to use an SDK utility script called run-standalone.sh. Its job is to set up the correct environment variables for themes and communication for the command that is given to it as its command line parameter.

[sbox-FREMANTLE_X86: ~] >run-standalone.sh ./gtk_helloworld-1

The screen is still a bit off (there are no borders around the main GtkLabel widget), but already looks better. The text is scaled to be more in sync with the other text sizes and the color is also in sync with the platform color (it is not gray anymore).