如何用 Linux 開發 Palm 程式
Palm
是麼是 Palm 大家一定知道.現在越來越多的人投入到
Palm 程式開發的行列中來.今天,就讓我們自己也來體會一下如
和在 Linux 上開發 Palm 的程式吧.
為什麼是 Linux
原因很簡單,因為 Linux 是免費的.因為 Linux 下的很
多工具也都是免費的. 同時, Linux 本身就是一個最好的程式開
發平台.
在 Linux 中寫 Palm 程式,除了需要一個可以正常工作的 Linux
環境以外,我們還需要以下的東西:
- 1. 我們需要 Palm OS 的 SDK 來開發 Palm 的程式. Palm 的 SDK 可以在 Palm
的網站中免費下載: http://www.palmos.com/dev/
- 2. Palm Emulator - Palm 的模擬器,用來模擬 Palm 執行我們
寫出的 Palm 程式. Palm Emulator 也可以子愛 Palm 的網
站中免費下載: http://www.palmos.com/dev/
- 3. RPC-Tools 如果想在 Linux 中開發 Palm 的程式. 就需要用到
RPC-Tools 了. RPC-Tools 實際上是通過對 the GNU Compiler
Collection, Assembler, linker, 跟 symbolic debugger 做
一些必要的修改,好讓我們可以在 Linux 上面用 C/C++ 來開發
Palm 的程式. RPC-Tools 可以在 http://prc-tools.sourceforge.net/
中免費下載.
- 4. gcc-2.95.3 我們需要打造出一個 cross compiler, 按照 RPC-Tools
的建議,這裡我們選擇了下載 gcc-2.95.3:
http://www.gnu.org/software/gcc/gcc-2.95/
- 5. GDB - 用來建立 cross debuger (除錯), 同樣的,按照 RPC-Tools
中的建議,我們選擇 gdb-5.0 :
ftp://sources.redhat.com/pub/gdb/old-releases/gdb-5.0.tar.bz2
- 6. Binutils - 我們所需要的一些工具,包含了:
ld, as, ar, nm, objcopy, objdump, ranlib, size, strings, strip,
c++filt, addr2line 和 nlmconv 這裡我們選擇 binutils-2.9.1
ftp://ftp.gnu.org/gnu/binutils/binutils-2.9.1.tar.gz
- 7. make-3.77 - 我們選擇 make-3.77
ftp://ftp.gnu.org/pub/gnu/make/make-3.77.tar.gz
- 8. PilRC - PilRC 是 Palm 的 resource compiler. 也就是說把
m68k 的可執行程式碼編譯成 palm 的 .prc 文件. PilRC 可以
在下面的連結中免費取得:
http://www.ardiri.com/index.php?redir=palm&cat=pilrc&subcat=download
這裡用於測試的系統是 RedHat 7.3
安裝 Palm SDK
首先 tar vxfz sdk50.tar.gz 這時侯會出現一個 palmos-sdk 的 rpm 文件.
用 rpm -ivh 給安裝上去就好. SDK 會被安裝在 /opt/palmdev/sdk-5 中.
我們現在需要做一個 symbolic link, 把 sdk-5 link 到 sdk 上面去.
cd /opt/palmdev
ln -s sdk-5 sdk
現在我們已經安裝好了 Palm SDK 了. 接下來就該安裝開發所需要的環境
了.
安裝 PRC-Tools 以及 cross compile 所需要的工具
收先我們建立一個新的目錄
mkdir /tmp/prc
然後把 prc-tools-2.0.92.tar.gz binutils-2.9.1.tar.bz2 gcc-2.95.3.tar.bz2
gdb-5.0.tar.bz2 make-3.77.tar.gz 都 copy 過去.
cp prc-tools-2.0.92.tar.gz /tmp/prc
cp binutils-2.9.1.tar.bz2 /tmp/prc
cp gcc-2.95.3.tar.bz2 /tmp/prc
cp gdb-5.0.tar.bz2 /tmp/prc
cp make-3.77.tar.gz /tmp/prc
然後 cd 到 /tmp/prc 目錄下.
執行解壓縮的動作:
收先把所有 .gz 的解壓縮
for i in *.gz; do tar vxfz $i; done
接下來是一些用 bzip2 壓縮的 .bz2 文件
for i in *.bz2; do tar vxfj $i; done
prc-tools 為以上的這些程式,有做一些改動,所以我們需要
把上面的程式碼 patch 一下:
cat prc-tools-2.0.92/*.palmos.diff | patch -p0
現在我們進入 prc-tools-2.0.92 的目錄,首先我們需要做的是
把 binutils-2.91, gdb-5.0, gcc-2.95.3 跟 make-3.77 這幾
個目錄用 symbolic link 分別 link 到 prc-tools-2.0.92 這
個目錄中.
cd prc-tools-2.0.92
ln -s ../binutils-2.9.1 binutils
ln -s ../gcc-2.95.3 gcc
ln -s ../gdb-5.0 gdb
ln -s ../make-3.77 make
為了保持我們程式源碼目錄的整潔與完整性,所以我們在編譯的時侯,
單另建立一個目錄 build:
cd ..
mkdir build
現在我們只要跑 prc-tools-2.0.92 中的那個 configure 就好了
../prc-tools-2.0.92/configure --target=m68k-palmos --enable-languages=c,c++
這裡面我們分別傳給 configure 兩個參數, 一個是告訴我們的 target 為 m68k-palmos
另一個是 enable C/C++ 這兩種語言. prc-tools 中的這只 configure script 會幫我們
把 binutils, gcc, gdb, make 這四個程式所需要的 Makefile 也同時幫我們建立好.
現在在我們的 build 目錄中,就有了以下這些東西:
binutils config.log crt gcc include libm Makefile
config.cache config.status doc gdb libc make tools
現在我們只要用 make all-install 就好了.
(如果您不是用 root 帳號, 不要忘記 su 成 root)
make all-install
因為需要 compile 的時間滿長的.如果您的系統中有超過一顆的 CPU 記得在
make 後面加上 -j number 的選項,其中 number 的 value 就是您 CPU 的數量
加一. 例如您有兩顆 CPU 就可以用 make -j3 all-install, 如果有三顆就用
make -j4 all-install. 如果您的機器又很大的 RAM (好幾 GB)然後也有個
十幾顆的 CPU, 那麼也可以用 make -j all-install 來編譯.如果 -j 後面沒
有跟任何數字,那麼 make 就不會對 jobs 做任何的限制. 詳細的情況請自行
man make 看一下.
在我們編譯的過程中,還有己個小小的問題需要解決一下(至少這個問題存在
於 RedHat 版本的系統中)
首先遇到的問題是, 在 gdb 的編譯中有一個錯誤:
In file included from /usr/include/curses.h:111,
from ../../../prc-tools-2.0.92/gdb/gdb/utils.c:28:
/usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdbool.h:39: conflicting types for `false'
../bfd/bfd.h:101: previous declaration of `false'
/usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdbool.h:41: conflicting types for `true'
../bfd/bfd.h:101: previous declaration of `true'
我們這裡看到在 gdb/gdb.utils.c 中的第 28 行有 include curses.h 這個
文件.而 curses.h 中的第 111 行又 include 了 stdbool.h, stdbool.h 中
定義了 false, 而 bfd/bfd.h 中同時也定義了 false, 這樣兩個 false 就衝
突了.所以造成編譯失敗.這裡用最簡單也是最偷懶的作法,打開
/usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdbool.h
把:
typedef enum
{
false = 0,
true = 1
} _Bool;
這己行給暫時 mark 起來
/*
typedef enum
{
false = 0,
true = 1
} _Bool;
*/
然後再重新
make all-install
現在我們會遇到第二個問題:
gcc -DEXEC_PREFIX=\"/usr/local\" -I. -I../../prc-tools-2.0.92/tools/../binutils/include -I../binutils/bfd -g -O2 -o def.yy.o -c def.yy.c
../../prc-tools-2.0.92/tools/def.l:35:19: utils.h: 沒有此一檔案或目錄
../../prc-tools-2.0.92/tools/def.l:37:23: pfdheader.h: 沒有此一檔案或目錄
找不到 utils.h 跟 pfdheader.h 這個很容易解決,把 prc-tools-2.0.92/tools 下面
這兩個文件複製到 build/tools 下面就好了,這裡我們把全部的東西都給複製過去,
不然等會還會繼續說找不到 utils.h 的文件
cp ../prc-tools-2.0.92/tools/* tools/
然後繼續 make all-install
接下來又會有一個錯誤中斷編譯:
gcc -DEXEC_PREFIX=\"/usr/local\" -I. -I../../prc-tools-2.0.92/tools/../binutils/include -I../binutils/bfd -g -O2 -o def.yy.o -c def.yy.c
../../prc-tools-2.0.92/tools/def.l:39: conflicting types for `dup'
/usr/include/unistd.h:441: previous declaration of `dup'
這裡是說,在 def.l 中第 39 行定義的 dup 已經在 /usr/include/unistd.h 中的
第 441 行定義過了.所以產生了衝突.
還是用最簡單的方法來解決:
首先要做的是
vim tools/def.yy.c
把第十二行的 #include 改成 #include "unistd.h"
這樣編譯 def.yy.c 的時侯,就不會去找 /usr/include/unistd.h
這個文件,而是找 tools 下面的 unistd.h
接下來
cp /usr/include/unistd.h tools/
把 unistd.h 複製到 tools 下面,再把 unistd.h 改動一下
最後
vim tools/unistd.h
把第 441 行的 extern int dup (int __fd) __THROW;
給 mark 起來
// extern int dup (int __fd) __THROW;
存檔後重新 make all-install 就再沒有問題了.
這時侯,在您的 /usr/local/bin 下面就已經有了我們
做 cross compile 所需要的全部工具了.
PS. 不要忘記把了把 /usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdbool.h 改回原貌喔.
安裝 pilrc
現在到了最後一步,安裝 pilrc
首先把 pilrc-2.9.tar.gz 複製到 /tmp 中
cp pilrc-2.9.tar.gz /tmp
然後解壓縮:
tar vxfz pilrc-2.9.tar.gz
pilrc-2.9 這個版本,有一點小問題. 如果直接編譯,那麼
pilrcui ( resource viewr )則沒有辦法正常工作.遺憾
的是, pilrc 的官方網站並沒有放出 patch 文件.所以就需
要自己動手改一下了.這裡我們需要改兩個文件.
一個是 main.c 另外一個是 pilrc.c
收先打開 main.c 在倒數第三行會看到
ParseFile(szInputFile, szOutputPath, szResFile, szIncFile, fontType);
把這行刪除不要,改成下面的這行, 我們要用 FreeRcpfile 來叫 ParseFile
FreeRcpfile(ParseFile(szInputFile, szOutputPath, szResFile, szIncFile, fontType));
然後存檔離開.再打開 pilrc.c 把倒數第五行的
FreeRcpfile(prcpfile);
給 mark 起來
//FreeRcpfile(prcpfile);
這行我們不要.
現在就可以執行 ./configure 程式了, 然後執行
make
make install
現在我們就已經在 linux 下安裝好了一個 palm 的開發環境了.
最後的測試
現在為了測試我們的 palm 開發環境是否一切都真的工作了,
就讓我們寫一個最簡單的 hello word 來測試一下吧
我從電腦中找了個 hello 的 palm 程式出來.忘記是哪裡的
一個範例了,借來用用.
hello.rpc:
#include "hello.h"
VERSION ID 1 "1.00"
MENU ID MainMenu
BEGIN
PULLDOWN "Help"
BEGIN
MENUITEM "About..." ID HelpMenuAbout
END
END
FORM HelloForm AT (0 0 160 160)
MENUID MainMenu
USABLE
BEGIN
LABEL "Hello, world!" AUTOID AT (CENTER 50)
END
ALERT ID AboutAlert
BEGIN
TITLE "About..."
MESSAGE "Hello, world! demo app\nVersion 1.00\n\nCopyright \251 2003\nStudy-Area.\n"
BUTTONS "OK"
END
hello.h:
#define MainMenu 1000
#define HelpMenuAbout 1010
#define HelloForm 1100
#define AboutAlert 2000
hello.c:
#include <PalmOS.h>
#include <PalmUtils.h>
#include "hello.h"
static FormPtr gpForm;
static Err StartApplication()
{
FrmGotoForm(HelloForm);
return 0;
}
static void StopApplication()
{
FrmCloseAllForms();
}
Boolean HelloFormEventHandler(EventPtr event)
{
Boolean handled = false;
switch (event->eType) {
case frmOpenEvent: {
gpForm = FrmGetActiveForm();
FrmDrawForm(gpForm);
handled = true;
break;
}
case frmCloseEvent:
FrmEraseForm(gpForm);
FrmDeleteForm(gpForm);
gpForm = 0;
handled = true;
break;
default:
break;
}
return handled;
}
static Boolean ApplicationEventHandler(EventPtr event)
{
Boolean handled = false;
switch (event->eType) {
case frmLoadEvent: {
FormPtr pForm = FrmInitForm(event->data.frmLoad.formID);
FrmSetActiveForm(pForm);
FrmSetEventHandler(pForm, HelloFormEventHandler);
handled = true;
break;
}
case menuEvent:
switch (event->data.menu.itemID) {
case HelpMenuAbout:
FrmAlert(AboutAlert);
break;
}
handled = true;
break;
default:
break;
}
return handled;
}
static void EventLoop()
{
EventType event;
UInt16 error;
do {
EvtGetEvent(&event, evtWaitForever);
if (!SysHandleEvent(&event)) {
if (!MenuHandleEvent(0, &event, &error)) {
if (!ApplicationEventHandler(&event)) {
FrmDispatchEvent(&event);
}
}
}
}
while (event.eType != appStopEvent);
}
UInt32 PilotMain(UInt16 launchCode, MemPtr cmdPBP, UInt16 launchFlags)
{
Err err = 0;
if (launchCode == sysAppLaunchCmdNormalLaunch) {
if ((err = StartApplication()) == 0) {
EventLoop();
StopApplication();
}
}
return err;
}
最後寫一個 Makefile:
PROGRAM=hello
CC=m68k-palmos-gcc
PILRC=pilrc
OBJRES=m68k-palmos-obj-res
ICONTEXT='hello'
BUILDPRC=build-prc
APID=TEST
CFLAGS=-palmos -Wall -g
LFLAGS=-g
SOURCES=hello.c
OBJS=hello.o
PRC=$(PROGRAM).prc
RESOURCES=$(PROGRAM).rcp
all: $(PRC)
$(PRC): $(PROGRAM) bin.res
$(BUILDPRC) $(PRC) $(ICONTEXT) $(APID) *.bin *.grc
$(PROGRAM): $(OBJS)
$(CC) -o $(PROGRAM) $(OBJS) $(LFLAGS)
$(OBJRES) $(PROGRAM)
bin.res: $(RESOURCES) hello.h icon.bmp
$(PILRC) $(RESOURCES)
touch bin.res
ctags:
ctags $(SOURCES)
clean:
rm -f *.bak *.bin *.grc *.o bin.res tags $(PRC) $(PROGRAM)
hello.o: hello.c hello.h
然後我們打 make 最後看到成功了:
m68k-palmos-gcc -palmos -Wall -g -c -o hello.o hello.c
m68k-palmos-gcc -o hello hello.o -g
m68k-palmos-obj-res hello
pilrc hello.rcp
PilRC v2.9 patch release 2
Copyright 1997-1999 Wes Cherry (wesc@ricochet.net)
Copyright 2000-2001 Aaron Ardiri (aaron@ardiri.com)
Generating 68K resources from 'hello.rcp'.
Writing tver0001.bin
5 bytes
Writing MBAR03e8.bin
86 bytes
Writing tFRM044c.bin
102 bytes
Writing Talt07d0.bin
90 bytes
touch bin.res
build-prc hello.prc 'hello' TEST *.bin *.grc
好啦,現在一切都 ok 了.如果您也同樣的 make 成功.那麼恭喜您,您的 linux 中
已經有了一個可以寫 palm 程式的環境了.