Category: Projects Related to Palm OS PDAs
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).
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.
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 (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.
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.
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.
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" 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.
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 is the compiler that translates source files into binary files. Thankfully, Dmitry Grinberg made modern gcc 9.1 ready for compiling Palm OS applications.
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.
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:
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!
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.
You should have the following files in one workspace folder:
If the paths in the makefile are correct, you can build the application just withmakeand 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.
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.
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.
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.
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:
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.
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:i386But the other build tools are still stand-alone tools.
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*.patchIn 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" #endifSince 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*.patchAfter 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-multilibNext, we need to generate a Makefile (and do some other tasks) with
./unix/configureIn 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 = gccto:
CC = gcc -m32The last step is to run these two commands:
sudo make sudo make installThe
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 ...
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 installlibxext6:i386
with
sudo apt-get install libxext6:i386After this step, just rename the downloaded .rpm file into a .zip file and unpack it. The unpacked executable runs just fine:
./usr/bin/pose
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.