Category: Projects Related to Palm OS PDAs

Compiling and building Palm-OS-Applications on Ubuntu 20.04 LTS (64 Bit)

Published on: 2020-06-08

Since the last article about this topic is nearly one year old and already obsolete, because it is only working on Ubuntu 18.04.2 and not working on Ubuntu 18.04.4 LTS or newer, I decided to write one about compiling and building Palm-OS-Applications on Ubuntu 20.04 LTS (64 Bit).

Shortcut

It is understandable, that not everyone wants to redo every step I did. So I put everything needed for building a Palm OS application into a big zip-file. Just unzip it and run make in a terminal. Then you get a runnable .prc file for your Palm OS device. Of course, you can then edit the example as you want or replace it with your own code. Just make sure it includes this function:

UInt32 __attribute__((section(".vectors"))) __Startup__(void)
{
	SysAppInfoPtr appInfoP;
	void *prevGlobalsP;
	void *globalsP;
	UInt32 ret;
	
	SysAppStartup(&appInfoP, &prevGlobalsP, &globalsP);
	ret = PilotMain(appInfoP->cmd, appInfoP->cmdPBP, appInfoP->launchFlags);
	SysAppExit(appInfoP, prevGlobalsP, globalsP);
	
	return ret;
}

Current Version: 3

If you are interested in how everything is set up, you can read the complete article.

Needed Packages

There was one major change, which makes one part of the last article unnecessary: building gcc 2.x. Luckily, Dmitry Grinberg was able to make some adjustments to gcc 9.1 to be able to compile source code for Palm OS applications with it. Gcc 9.1 is precompiled and ready for use after a few tweaks in the Palm OS SDK.

In order to be able to compile and build Palm OS applications on Linux, you will need the following packages:

Notes:

 

PilRC

PilRC (PILot Resource Compiler) is a compiler that turns a textual description of Palm OS forms, bitmaps, fonts, and other resources into a binary form that can be included in an application or library.

Installation

The installation of the PilRC-package is straightforward. Just install it via the command line with

dpkg -i pilrc_3.2-3build1_amd64.deb

or with a package manager of your choice.

 

Palm OS SDK

The Palm OS SDK provides all the needed libraries and header files to write Palm OS applications. It is needed for every Palm OS application.

Installation

Since there is no installation file available, just download it and unzip it in a folder of your choice. One place could be in /opt, so the full path can look like this:

/opt/palmdev/palm-os-sdk-master/sdk-5r3/include

 

In order to get everything to work, there are some changes in the SDK needed. I used the SDK "5r3" for my projects, which worked the best for me. Dmitry mentioned the following changes in "sdk-5r3/include/PalmTypes.h", but I was only able to find the first three parts, so I skipped the last one, which worked perfectly fine so far. If you do not want to do the changes yourself, you can use this pre-edited SDK 5r3.

Find in sdk-5r3/include/PalmTypes.h, line 210-223:

#define _OS_CALL(table, vector)											\
	__attribute__ ((__callseq__ (											\
		"trap #" _Str(table) "; dc.w " _Str(vector))))

#define _OS_CALL_WITH_SELECTOR(table, vector, selector)			\
	__attribute__ ((__callseq__ (											\
		"moveq #" _Str(selector) ",%%d2; "								\
		"trap #" _Str(table) "; dc.w " _Str(vector))))

#define _OS_CALL_WITH_16BIT_SELECTOR(table, vector, selector)	\
	__attribute__ ((__callseq__ (											\
		"move.w #" _Str(selector) ",-(%%sp); "							\
		"trap #" _Str(table) "; dc.w " _Str(vector) "; "			\
		"addq.w #2,%%sp")))
	

Replace with:

#define _OS_CALL(table, vector)												__attribute__((__raw_inline__(0x4E40 + table, vector)));
#define _OS_CALL_WITH_SELECTOR(table, vector, selector)						__attribute__((__raw_inline__(0x7400 + selector, 0x4E40 + table, vector)));
#define _OS_CALL_WITH_16BIT_SELECTOR(table, vector, selector)				__attribute__((__raw_inline__(0x3F3C, selector, 0x4E40 + table, vector, 0x544F)));
	

 

prc-tools-remix

"prc-tools-remix" is a tool-set, which is needed to create a runnable .prc-application. The most important tool in this case is "prc-builder". It transforms .bin-files from the compiler into an executable for Palm OS.

Installation

Clone or download and unzip the prc-tools-remix from GitHub. Next, we just need to build the prc-tools, without gcc, since we are going to use the newer version of gcc from Dmitry. Like mentioned in the readme.md, create a "build" directory next to the "prc-tools-2.3" directory. Then a few libraries are needed:

sudo apt-get install \
    texinfo \
    flex \
    bison \
    gperf \
    libncurses5-dev

After installing these libraries, run this command inside the created "build" directory:

../prc-tools-2.3/configure \
	--enable-targets=m68k-palmos,arm-palmos \
	--enable-languages=c,c++ \
	--disable-nls \
	--with-palmdev-prefix=/opt/palmdev \
	--host=i686-linux-gnu

With

make tools

only the needed prc-tools will be compiled.
If the make process is not working for some reasons, you can also use these pre-compiled prc-tools. After the make process finishes, the tools directory (inside the build directory) is needed. It can also be copied to "/opt/":

cp -r tools /opt/palmdev/prc-tools2_3

 

gcc 9.1

gcc is the compiler that translates source files into binary files. Thankfully, Dmitry Grinberg made modern gcc 9.1 ready for compiling Palm OS applications.

Installation

Like Dmitry mentioned in his Reddit post, we need this package: m68k-none-elf_for_palmos.tar.bz2. After unpacking and copying it into our "/opt" directory, it is already ready for use.

The Makefile

A makefile is a manual for every step needed to get an executable Palm application from source files. The basis of this makefile was written by Dmitry Grinberg, who thankfully gave permission to use and modify it for individual use.

TOOLCHAIN		?=	/opt/palmdev/toolchain/bin/
SDK				?=	/opt/palmdev/palm-os-sdk-master/sdk-5r3/include
MKPRC			?=	/opt/palmdev/prc-tools2_3/build-prc
CC				=	$(TOOLCHAIN)/m68k-none-elf-gcc
LD				=	$(TOOLCHAIN)/m68k-none-elf-gcc
OBJCOPY			=	$(TOOLCHAIN)/m68k-none-elf-objcopy
COMMON			=	-Wno-multichar -funsafe-math-optimizations -Os -m68000 -mno-align-int -mpcrel -fpic -fshort-enums -mshort
WARN			=	-Wsign-compare -Wextra -Wall -Werror -Wno-unused-parameter -Wno-old-style-declaration -Wno-unused-function -Wno-unused-variable -Wno-error=cpp
LKR				=	linker.lkr
CCFLAGS			=	$(LTO) $(WARN) $(COMMON) -I. -ffunction-sections -fdata-sections
LDFLAGS			=	$(LTO) $(WARN) $(COMMON) -Wl,--gc-sections -Wl,-T $(LKR)
SRCS			=   HelloWorld.c
OBJS			=	$(patsubst %.S,%.o,$(patsubst %.c,%.o,$(SRCS)))
TARGET			=	test
CREATOR			=	test

#add PalmOS SDK
INCS			+=	-isystem$(SDK)
INCS			+=	-isystem$(SDK)/Core
INCS			+=	-isystem$(SDK)/Core/Hardware
INCS			+=	-isystem$(SDK)/Core/System
INCS			+=	-isystem$(SDK)/Core/UI
INCS			+=	-isystem$(SDK)/Dynamic
INCS			+=	-isystem$(SDK)/Libraries



$(TARGET).prc: code0001.bin
	 $(MKPRC) -c $(CREATOR) -n $(TARGET) -o $(TARGET).prc $< && rm code0001.bin

%.bin: %.elf
	$(OBJCOPY) -O binary $< $@ -j.vec -j.text -j.rodata

%.elf: $(OBJS)
	$(LD) -o $@ $(LDFLAGS) $^

%.o : %.c Makefile
	$(CC) $(CCFLAGS)  $(INCS) -c $< -o $@

clean:
	rm -rf $(OBJS) $(NAME).elf  
 
.PHONY: clean

Please keep in mind, that you may need to modify the following paths/parameters:

Also, the "linker.lkr" is needed. This file can be downloaded here. This is the content of this file:
MEMORY
{
	rom : ORIGIN = 0x10000000, LENGTH = 256K
	
	ram : ORIGIN = 0x20000000, LENGTH = 64K
	
	trash  : ORIGIN = 0x40000000, LENGTH = 64K
}

SECTIONS
{
	.vec : {
		KEEP( *(.vectors) ) ;
		*(.vectors);
	}  > rom
	 
	/* must be before .text to properly discard function names */
	.trash2 : { *(.init) *(.init.*) ; *(.fini) *(.fini.*) ; *(*.macsbug)   }  > trash
	
	.text : { *(.text)  *(.text.*)}  > rom
	
	.rodata : { *(.rodata) *(.rodata.*) ; . = ALIGN(4); __data_data = ABSOLUTE(.) ; }  > rom

	.data : AT ( ADDR ( .rodata ) + SIZEOF ( .rodata ) ) { . = ALIGN(4); __data_start = ADDR ( .data ) + . ; *(.data) ; *(.data.*) ; . = ALIGN(4); __data_end = ADDR ( .data ) + . ; } > ram
	
	.bss  :  {  *(.bss) *(.bss.*) *(COMMON) ; } > ram
	
}

ENTRY(__Startup__)
It was also written and provided by Dmitry - thanks!

 

A Small Example

This small example allows us to test our toolchain. It just outputs "Hello World". It can be saved as "HelloWorld.c".

#include <PalmOS.h>

UInt32 PilotMain(UInt16 cmd, void *cmdPBP, UInt16 launchFlags) {
	EventType event;
	char *message = "Hello World";

	if (sysAppLaunchCmdNormalLaunch == cmd) {
		WinDrawChars(message, StrLen(message), 54, 74);

		do {
			EvtGetEvent(&event, evtWaitForever);

			SysHandleEvent(&event);

		} while (event.eType != appStopEvent);
	}

	return 0;
}

UInt32 __attribute__((section(".vectors"))) __Startup__(void)
{
	SysAppInfoPtr appInfoP;
	void *prevGlobalsP;
	void *globalsP;
	UInt32 ret;
	
	SysAppStartup(&appInfoP, &prevGlobalsP, &globalsP);
	ret = PilotMain(appInfoP->cmd, appInfoP->cmdPBP, appInfoP->launchFlags);
	SysAppExit(appInfoP, prevGlobalsP, globalsP);
	
	return ret;
}
It looks like the function UInt32 __attribute__((section(".vectors"))) __Startup__(void) is needed in every application.

Building the Application

You should have the following files in one workspace folder:

If the paths in the makefile are correct, you can build the application just with
make
and you should get a small "test.prc" at the end, which shows only "Hello World":

 

Thanks to Dmitry's work, this way of building applications is even more efficient than building an application with CodeWarrior. Of course, it has to be said that CodeWarrior has other advantages, such as a decent debugger. So the next step would probably be to build a pipeline that ensures that code managed with git is built and the application is made available with gcc 9.1. Also, it would be interesting to build a bigger project with resources like UI elements.

For this project, I want to thank the PalmDB community and Dmitry Grinberg, who helped me a lot with many problems during setting everything up.

Building a complete Palm OS application with only two tools

After publishing this article, Dmitry contacted me and told me, it would be possible to build a Palm OS application with only two tools:

Of course, also the Palm OS SDK: 5r3 and the linker.lkr are needed. After a conversation with him, reading the PilRC documentation and a bit of trying out, I was able to set everything up.

 

Second shortcut

Again, I packed everything needed in a zip-package, ready for usage:

Download the complete dev-package for Ubuntu 20.04 LTS (64 Bit) (Version 2)

Usage is easy as the last time:
Just unpack the zip-file and run make
Of course, you can edit the make and source file as you need it. But do not forget to include the mentioned function from the first shortcut if you begin a blank project.

If you are interested in how version 2 is set up, you can read the rest of this article.

No need for prc-tools

Only Dmitry's gcc 9.1 and PilRC are needed to create a fully working toolchain for building Palm OS applications on Ubuntu 20.04. The installation for gcc 9.1 is still the same and also the installation for PilRC has not changed. Only compiling the prc-tools isn't necessary anymore. You still need the Palm OS SDK and the linker.lkr. The alternative to the installation of "pilrc_3.2-3build1_amd64.deb" is to download and unpack the "pilrc-3.2-1.i386.rpm" from https://sourceforge.net/projects/pilrc/files/pilrc/3.2/. (Just rename the ".rpm" file to ".zip" for unpacking it). This is what I did for the dev-package to get an independent bundle, which can be executed without installing anything.

The makefile

Since the prc-tools dropped out of the build chain, we need to adjust the makefile a bit. It now looks like this:

TOOLCHAIN		?=	buildtools/toolchain/bin/
SDK			?=	buildtools/palm-os-sdk-master/sdk-5r3/include
PILRC			=	pilrc
CC			=	$(TOOLCHAIN)/m68k-none-elf-gcc
LD			=	$(TOOLCHAIN)/m68k-none-elf-gcc
OBJCOPY			=	$(TOOLCHAIN)/m68k-none-elf-objcopy
COMMON			=	-Wno-multichar -funsafe-math-optimizations -Os -m68000 -mno-align-int -mpcrel -fpic -fshort-enums -mshort
WARN			=	-Wsign-compare -Wextra -Wall -Werror -Wno-unused-parameter -Wno-old-style-declaration -Wno-unused-function -Wno-unused-variable -Wno-error=cpp -Wno-error=switch
LKR			=	linker.lkr
CCFLAGS			=	$(LTO) $(WARN) $(COMMON) -I. -ffunction-sections -fdata-sections
LDFLAGS			=	$(LTO) $(WARN) $(COMMON) -Wl,--gc-sections -Wl,-T $(LKR)
SRCS			=   	Src/helloWorld.c
RCP			=	Src/helloWorld.rcp
RSC			=	Src/
OBJS			=	$(patsubst %.S,%.o,$(patsubst %.c,%.o,$(SRCS)))
TARGET			=	test
CREATOR			=	test
TYPE			=	appl

#add PalmOS SDK
INCS			+=	-isystem$(SDK)
INCS			+=	-isystem$(SDK)/Core
INCS			+=	-isystem$(SDK)/Core/Hardware
INCS			+=	-isystem$(SDK)/Core/System
INCS			+=	-isystem$(SDK)/Core/UI
INCS			+=	-isystem$(SDK)/Dynamic
INCS			+=	-isystem$(SDK)/Libraries
INCS			+=	-isystem$(SDK)/Libraries/PalmOSGlue



$(TARGET).prc: code0001.bin
	$(PILRC) -ro -o $(TARGET).prc -creator $(CREATOR) -type $(TYPE) -name $(TARGET) -I $(RSC) $(RCP) && rm code0001.bin

%.bin: %.elf
	$(OBJCOPY) -O binary $< $@ -j.vec -j.text -j.rodata

%.elf: $(OBJS)
	$(LD) -o $@ $(LDFLAGS) $^

%.o : %.c Makefile
	$(CC) $(CCFLAGS)  $(INCS) -c $< -o $@

clean:
	rm -rf $(OBJS) $(NAME).elf
	
.PHONY: clean

Please keep in mind, that you may need to modify the following paths/parameters:

 

A small example with more possibilities

The actual example hasn't changed and can be used again. But in addition, a resource file with the extension ".rpc" is needed, with at least this content:

DATA "code" ID 1 "code0001.bin"
You can also add in this rpc-file UI elements. Since we are going to build it with PilRC, it will also take care of these resources. PilRC will also look into the "Src" folder for e.g. bitmap files.

 

After executing the makefile with make, you will get a runnable .prc file, which can be executed on a Palm or POSE. Luckily, this POSE installation guide is still valid for Ubuntu 20.04.

Besides the already mentioned git dependent build pipeline, it would be also nice to have an unofficial PilRC 3.3 build and also POSE included in a standalone dev-package. Therefore, a dev-package version 3 will most likely follow.

PilRC 3.3 unofficial and POSE

Right after publishing the last update of this article, I tried to add the changes from Dmitry to the PilRC source code and compiled it: with success. Also, POSE (Palm OS Emulator) was added to have a possibility to test the built application right on Linux. But before I explain how everything is set up, I created (again) a (nearly full) stand-alone dev-package (version 3):

Download the complete dev-package for Ubuntu 20.04 LTS (64 Bit) (Version 3)

This package includes the same as Version 2 but with POSE and replaces PilRC with version 3.3 unofficial. Using it is also the same, just run it with make. POSE can be executed with ./startPose.sh, which just executes the runnable in the "addons" directory.
Sadly, POSE cannot run as a stand-alone application. "libxext6:i386" is required, which can be installed with

sudo apt-get install libxext6:i386
	
But the other build tools are still stand-alone tools.

 

Patching and compiling PilRC 3.3 unofficial

First, we need the PilRC 3.2 source files. They are available here. We also need to download Dmitry's changes and unpack the .patch files in the same directory as the PilRC source files. In the next step, we need to apply these patch files with these commands from inside the PilRC directory:

patch < 0001*.patch
patch < 0002*.patch
patch < 0003*.patch
patch < 0004*.patch
patch < 0005*.patch
patch < 0006*.patch
patch < 0007*.patch
patch < 0008*.patch
patch < 0009*.patch
patch < 0010*.patch
patch < 0011*.patch
patch < 0012*.patch
patch < 0013*.patch
patch < 0014*.patch
patch < 0015*.patch
In order to see that we are using a new, unofficial version of PilRC, I have created a patch file that simply changes the version string in the version.h:
--- version.h	2004-01-29 09:34:43.000000000 -0800
+++ version.h	2020-06-11 04:19:39.527995655 -0700
@@ -34,6 +34,6 @@
  */
 
 #define PILRC_VERSION      3, 2, 0, 0
-#define PILRC_VERSION_STR  "3.2"
+#define PILRC_VERSION_STR  "3.3 unofficial"
 
 #endif
Since I didn't check where and how the constant PILRC_VERSION is used, I left it as it was to avoid unwanted problems. This patch file needs to be executed too, like the others:
patch < 0016*.patch
After applying the patches, we need to compile PilRC in 32bit mode - thanks to Dmitry for this hint. Otherwise, you will get a corrupt pilrc executable, which is not able to generate runnable .prc files. First, we need to install gcc with 32bit support, since the standard version of gcc on Ubuntu 20.04 does not support compiling in 32bit mode:
sudo apt-get install gcc-multilib
Next, we need to generate a Makefile (and do some other tasks) with
./unix/configure
In the Makefile, we need to tell gcc to use 32bit mode. The easiest way to do this is changing in the generated Makefile line 108 from:
CC = gcc
to:
CC = gcc -m32
The last step is to run these two commands:
sudo make
sudo make install
The sudo make install command also copies the compiled pilrc executable to /usr/local/bin/, which makes it system-wide available. Of course, this does not apply to the stand-alone version. At this point, the compiled pilrc executable is ready for usage. When you execute it, you can see that it was built correctly with the improvements from Dmitry and the new version string:
user@ubuntu:~/pilrc_src$ pilrc
PilRC v3.3 unofficial
  Copyright 1997-1999 Wes Cherry   (wesc@ricochet.net)
  Copyright 2000-2004 Aaron Ardiri (aaron@ardiri.com)

This program is free software; you may redistribute it under the
terms of the GNU General Public License. This program has absolutely
no warranty, you use it AS IS at your own risk.

Usage: pilrc {} infile [outfiledir]

Options:
        -L LANGUAGE    Use the TRANSLATION section for the given language
...

 

POSE

Since this POSE installation guide is still working for Ubuntu 20.04, here is only a short version of this guide:

First, get the .rpm file from https://sourceforge.net/projects/pose/files/pose/3.5-2/pose-3.5-2.i386.rpm/download. Then install libxext6:i386 with
sudo apt-get install libxext6:i386
After this step, just rename the downloaded .rpm file into a .zip file and unpack it. The unpacked executable runs just fine:
./usr/bin/pose

 

Final Words

After the third release of this article and all the changes that have been made to the toolchain to develop Palm OS applications on Ubuntu 20.04, we have reached a point where you can (for now) leave everything as it is. The toolchain is, thanks to Dmitry Grinberg, up to date and with only two tools and some libraries very compact. Hopefully, it will run on future Ubuntu releases too.

If you plan to write applications for Palm OS 2.0, use Version 2 of the dev-package, since the improvements from Dmitry are not fully supported by Palm OS 2.0.

Addendum

The discord-user Tavisco has pointed out to me that, when using the compiler introduced here, it is essential to avoid globals and instead use a struct and FtrSet/FtrGet of the Feature Manager, when needing to update/read the data. Otherwise, the compiler will not work properly. - Thanks for this important notice.