This document describes how to use gcc to create and use GLib shared libraries on the Pilot. It is divided into seven sections:
Comments are welcome; see the Conclusions section.
Shared libraries enable many applications to share common code, without having to have a copy of the code in each application's code resource. For example, there can be one copy of encryption routines, or a version of the standard C library, and many applications can be using it.
Shared libraries can also help you get around the 32K code size limit; you can break up your code into a main portion (of at most 32K), and a number of libraries (each of at most 32K).
GLib (pronounced ``gee-lib'') shared libraries are a way to implement shared libraries on the Pilot that differs from the ``standard'' (SysLib) mechanism for the Palm Pilot.
Some features of GLib:
GLib libraries are implemented as resource databases, with a database type of GLib, and a library-specific creator ID. The GLib library will usually contain three resources: GLib 0 (the code), data 0 (the library globals), and rloc 0 (the data relocation table). By contrast, an application if a resource database with (usually) five resources: code 0, code 1, data 0, rloc 0, and pref 0. The GLib 0 resource in a shared library corresponds exactly to the code 1 resource in an application.
Before going any further, you need to make sure that you have a recent version of gcc. m68k-palmos-coff-gcc -v should report its version number to be (at time of writing) 220.127.116.11-kgpd-071097. This is the version also known as 0.5.0. If you are using an earlier version, you should certainly upgrade; this version fixes quite a few problems, including handling of certain kinds of global variables.
The first step in creating a GLib shared library is to create a ``static'' library (also called an ar archive). This is quite simple. First, compile (but don't link) each of your .c files, with command lines like the following:
m68k-palmos-coff-gcc -g -O2 -c file.c -o file.o
Actually, the ``-o file.o'' is optional. Also, the ``-O2'' can be left out if you want to compile without optimization (the program is usually smaller and faster with -O2, but sometimes it's harder to debug).
Once you have all of the .o files that will be part of your library, group them together into a static library. For example, if your .o files are file1.o, file2.o, and file3.o, and you want to call your library ``foo'', you would use the command:
m68k-palmos-coff-ar rcs libfoo.a file1.o file2.o file3.o
The prefix ``lib'' and the suffix ``.a'' are mandatory in the name of the library.
If you want to create a program that uses this static library, just write your program normally, including calls to functions that you defined in your library. When you link this program, just put -lfoo at the end of the command. For example:
m68k-palmos-coff-gcc mainprog.o -o mainprog -lfoo
If you use a static library in this way, each program that uses the library will have its own copy of the library embedded into it. If you want to share the code for the library between all the programs that use it, you need to turn your static library into a shared library.
Turning a static library into a GLib shared library is quite simple. First, make sure your static library was compiled with the upgraded version of gcc (above). Let's call this static library libfoo.a. We are going to create FooLib.prc (the GLib shared library), as well as libfoo.sa, a ``stub'' library (much smaller than the static library) that will be linked to each application that uses the GLib shared library.
You need to generate a list of the functions exported by your library; save this list in a file called foo.exp. One way to do this is the following:
m68k-palmos-coff-exportlist libfoo.a > foo.exp
This is equivalent (on most systems) to the following command:
m68k-palmos-coff-nm libfoo.a | grep ' T ' | cut -c12- | sort -u > foo.exp
This will make foo.exp contain the list of functions exported by your library, one per line. Note: the order of the functions listed in foo.exp is important if you create a new version of the GLib library. Existing functions should not change their positions in the list, and new functions should be added to the end.
Next, you need to create two ``stub'' files. The command to do this for you is:
m68k-palmos-coff-stubgen "Foo Library" FooL foostub.c FooLib.S < foo.exp
Here, "Foo Library" is the (human-readable) name for your library. FooL is the four-character creator ID (you pick this yourself, but it's supposed to be globally unique). foostub.c and FooLib.S are files that will be generated by stubgen.
Now create FooLib.prc as follows:
Finally, create the stub library libfoo.sa from foostub.c:
m68k-palmos-coff-gcc -c foostub.c m68k-palmos-coff-ar rcs libfoo.sa foostub.o
That's it. FooLib.prc is the library users must install in order to use programs that are linked to libfoo.sa. Distribute FooLib.prc to end users and distribute libfoo.sa and the header files for libfoo.a to developers of applications that could use the library.
Now that you have a GLib shared library and a stub library, how do you change your application (that was previously linked to libfoo.a) to use the shared library instead of the static one?
It's surprisingly simple; the application need not change at all. Just make sure that libfoo.sa is visible to gcc when you link your program with -lfoo. If gcc finds libfoo.sa instead of (or in addition to) libfoo.a, it will cause the program to use the GLib shared library instead of the static one. (Note: if you have both libfoo.sa and libfoo.a, gcc will prefer the shared version. If you want to force it to use the static library, you can use the -static flag to gcc.)
Note the current restriction on GLib libraries: library global variables are not exported to the application. If your application needs to read or write variables in the library's global space, you should consider modifying the library to have access functions for them.
Another restriction: be careful if you pass function pointers around (say, for callbacks). If a function is called via a function pointer, it will have the globals of the caller, which would not be its own in the case that the called function was in a shared lib, for example. In general, the rule is: don't pass a function pointer to a GLib shared library function from a GLib shared library to the main program, and have the main program call it.
To use an application that requires a GLib shared library, just make sure both the application and the library are installed on your Pilot before running the application. GLib shared libraries are just prc files; they are installed in exactly the same way as applications (HotSync or pilot-xfer, for example).
If a GLib shared library is not installed, an application that uses it will still run properly, until it tries to call a function provided by the library (at which point you will get a Fatal Error informing you which library you're missing).
Success and failure reports, comments, and questions are welcome. Depending on the content, appropriate fora are the pilot.programmer and pilot.programmer.gcc newsgroups hosted on news.massena.com, and the pilot-unix mailing list at <firstname.lastname@example.org>. If necessary, I can be reached directly at the address below (be warned that my email queue sometimes gets quite backlogged).
Back to the ISAAC Group's Pilot page
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.Ian Goldberg, email@example.com