This topic describes how to port some C applications to Symbian OS. It
uses three examples: Hello
, ConsoleApp
and
GUIApp
. The first two are simple console-based examples. The third
is a command-line driven program which has been converted into a standard
Symbian application. It also describes typical problems which may be
encountered when porting C code to Symbian OS, including the restriction on
writeable data in DLLs. These example code projects can be found in directory
examples\stdlib\
.
Note that these examples may not be present on all Symbian OS SDKs.
Some of the code for the second two examples was taken from the FreeBSD source code. For information on FreeBSD, see http://www.freebsd.org.
The code in this section has been taken from the Hello
example.
This example demonstrates the most basic use of STDLIB. It consists
of the single source code file, slhello.c
whose sole function,
main()
calls printf()
.
The Hello
example's project definition file
(Hello.mmp
) contains the following:
TTARGET hello.exe
TARGETTYPE exe
UID 0
SOURCEPATH .
SOURCE slhello.c
SYSTEMINCLUDE \epoc32\include\libc \epoc32\include
LIBRARY estlib.lib euser.lib
STATICLIBRARY ecrt0.lib
Notes
The import library estlib.lib
is the C standard
library.
The project also links to ecrt0.lib
. This file
provides the E32Main()
entrypoint for a .exe
. It also
provides other services including command-line parsing, and it calls
main()
.
The SYSTEMINCLUDE
path specifies
\epoc32\include\libc\
, which is the location for STDLIB's header
files.
For more information on the project specification for a
.exe
see How to build for an EXE target.
To build Hello
for
the Emulator, run bldmake
from the directory where the
bld.inf
file is located:
bldmake bldfiles
This creates the abld.bat
batch file. Use
abld
to build the project, for instance:
abld build wins udeb
For information on building see
How to use the Symbian build process. To run it, invoke hello.exe
.
To build Hello
for the target machine, invoke
bldmake
and abld
, specifying the appropriate target
platform.
To install software on the target device you need to create a
.sis
file using the Symbian Installation system; see the
Software Installation Toolkit - guide.
This program converts a quantity from one unit of measurement into
another, prompting the user for input. Conversion information is provided in a
data file, slunits.dat
.
The user is prompted for input, but it is important to note that STDLIB does not provide all of the functionality of a traditional console driver. STDLIB is intended to be a "behind-the-scenes" enabling technology, rather than an alternative user interface.
The code for the ConsoleApp program was taken from the FreeBSD source code (See http://www.freebsd.org ).
Build the program using bldmake
and abld
as
the Hello example. For the Emulator, slunits.dat
is copied
automatically by abld into the right directory. For a target phone ensure that
slunits.dat
is located in the directory specified in
pathname.h
, this is the root of the drive on which the program is
installed.
To install ConsoleApp.exe
on the target phone you will
need to create a .sis
file using the Symbian Installation system;
see Software Installation Toolkit - guide and Installation reference.
To run it on the target phone, invoke ConsoleApp.exe
.
The application uses the FreeBSD cksum
utility as its
engine.
The checksum example is an application with a user interface and an engine written in C.
The first stage in porting this program was to split the project into the engine (GUIAppEng) and the application (GUIApp).
The engine is written in C. At its core is the crc()
function. This function takes a file descriptor and returns the checksum and
the file size.
The engine's project specification file (GUIAppEng.mmp
)
is as follows:
TARGET GUIAppEng.dll
TARGETTYPE dll
UID 0x1000008d 0x01000a02
VENDORID 0x70000001
SOURCEPATH .
SOURCE crc.c
SYSTEMINCLUDE \epoc32\include\libc \epoc32\include
LIBRARY estlib.lib euser.lib
#if defined(WINS)
deffile GuiAppEngWINS.def
#else if defined(ARM)
deffile GuiAppEngARM.def
#endif
nostrictdef
The output file is GUIAppEng.dll
, whose import library
will be included by the UI.
The first UID specified (0x1000008d) is the standard UID for an
interface DLL. The second UID (0x01100a02) is unique to the GUIApp
project.
Splitting the project into engine and UI means that the definition of
crc()
in crc.c
must be marked EXPORT_C
because this function will be exported from the engine's DLL.
For more information on DLLs, see DLLs.
The implementation of checksum (GUIApp.app
) limits the
user to the selection of a single file at a time and uses the default algorithm
crc()
, defined in crc.c
, to produce a 32-bit value.
The user interface provides two main menu commands; Calculate
checksum
(invokes a file selection dialog) and View
checksums
. When a file has been selected, and OK
pressed,
the selected filename is retrieved and opened:
const TUint16* fn=iFileName->PtrZ();
int fd = wopen((const wchar_t*)fn, O_RDONLY, 0);
This code fragment is taken from
examples\stdlib\GUIApp.cpp.
open()
returns a file descriptor which the engine's
crc()
function uses to identify the file. The checksum is
calculated (unless an error occurred in attempting to open or read the file),
and is displayed. The file is closed.
The filename and checksum are appended to an array, the contents of
which may be viewed by selecting View checksums
.
The application program includes several STDLIB header files, located
in \epoc32\include\libc\
. At link time, the program includes
estlib.lib
and the engine DLL's .lib
(GUIAppEng.lib
). Unlike the previous examples, this application
does not link to ecrt0.lib
. In this application there is no
main()
and Symbian OS provides its own E32Main()
.
For information on Symbian applications, their project specification, and resource files, see How to build GUI applications.
This section describes some issues which may arise during the porting of code written in C to Symbian OS.
The PETRAN stage of building may report a message similar to the following:
WARNING: Dll 'SLSUMENG[0x01000a02].DLL' has initialised data.
This warning, which is not reported when building for the Emulator,
indicates that the DLL contains non-const static data. This is not allowed in
ARM builds. If it is not obvious where the problem occurs, the associated
.map
file
(epoc32\release\<target>\urel\<dllname>.map
) contains
information which can help to track down the source file involved. A search for
from *(.bss)
(to find uninitialised data) or from
*(.data)
(to find initialised data) in GUIAPPEng.map
will
reveal the file in which the problem occurs, and the names of the offending
variables, although static variables will not be named.
For more information about the restriction on writeable static data, see Writeable static data in DLLs.
In C++ source files which use STDLIB routines, the Symbian OS C++ include files should be included before any of the STDLIB files. Failure to do this will result in the following warning:
'NULL' : macro redefinition"
C and C++ have different views about the names of functions. If you
refer to a C function from C++, ensure that its prototype is declared as
extern "C"
. If there are several such function declarations, it
may be more convenient to enclose them within the following:
#ifdef __cplusplus
extern "C" {
#endif
...
#ifdef __cplusplus
}
#endif
See for example examples\stdlib\GUIApp\extern.h
. For
more information about issues which arise when mixing C and C++, refer to any
good book on C++.
Some projects will produce the following error:
unresolved external symbol __chkstk
unless the amount of stack they use is reduced. Symbian threads have only 8k stack by default.
Symbian OS has a requirement that all resources which were
allocated by an application must be cleaned up by the time the program
terminates. On the Emulator, in debug builds, failure to do this will cause a
panic from the __UHEAP_MARKEND
macro.
Because the data allocated in the thread-local storage for STDLIB's
DLL (the _reent
structure) is not automatically cleaned up when
the environment is destroyed, it must be cleaned up by the user of STDLIB.
The function to achieve this is CloseSTDLIB()
. To use
this function, file epoc32\include\libc\sys\reent.h
should be
included in the project. Call CloseSTDLIB()
after the point at
which it is known that code in STDLIB's DLL will no longer be called and its
thread-local storage no longer needed.
For example, see the destructor for CExampleDocument
in examples\stdlib\GUIApp\GUIApp.cpp
.