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

07.06.2020

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

There is an easier way to build Palm OS applications - with an updated shortcut (Version 2).

And a more efficient way to do this - with an (again) updated shortcut (Version 3).

It is understandable, that not everyone wants to redo very step I did. So I put everything, what is needed for buliding a Palm OS application in a big zip-file together. 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;
}
	
Download the complete dev-package for Ubuntu 20.04 LTS (64 Bit) (Version 1)

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. Luckly Dmitry Grinberg was able to make some adjustments on gcc 9.1 in order to be abe 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-Applictions on Linux you will need the following packages:

Notes:

PilRC

PilRC (PILot Resource Compiler) is a compiler, which 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 really straight forward. Just install it in 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 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 - so far - perfectly fine. If you do not want to do the changes by yourself, you can use this pre-editited 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 the installation of these libraries, run this command inside of 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 finished, 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

ggc is the compiler and translates sourcefiles 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 in in our "/opt" directory it is already ready for use.

The Makefile

A makefile is a manual for every step, which is need to get a executable Palm application from sourcefiles. The basis of this makefile was written by Dmitry Grinberg, who thankfully gave permission to use and modify it for the 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 maybe 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 tool chain. 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, that the function UInt32 __attribute__((section(".vectors"))) __Startup__(void) is needed in very 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 Dmitrys work, this way to build 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 is 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, what is 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 Dmitrys gcc 9.1 and PilRC is needed to create a fully working tool chain 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 sill 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 in order 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 maybe 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 of the already mentioned git depended build pipline, 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, in order 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 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, what 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 sourc files. They are available here. We also need to download Dmitrys changes and unpacking 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 the inside of 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, which 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, how it was in order not to cause 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 doing some other tasks) with
./unix/configure
In the Makefile we need to tell gcc, that it has to use the 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 not 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 make 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 is 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 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 on the tool chain 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 tool chain 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 need to update/read the data. Otherwise the compiler will not work properly. - Thanks for this important notice.


Misc