PyQt for SL-A300


Python の Qt(/Embedded) 用モジュールである。 PyQt 本家にバイナリがあることはあるのだが、 SL-A300 では libqte の非互換(or バグ?) のため動かない。 具体的には

QLibrary::QLibrary(QString const &, QLibrary::Policy)
が無いといって止まる。 この constructor は libqte が参照していて、実体は libqpe に入っている。 本来 libqte から qtopia への参照があるはずがなく、 実際 SL5000 系の場合は libqte からの参照はない。 A300 の libqte がヘンなんだが、 これまで libqpe を使わない生粋の qt-embedded アプリが A300 に無いので露見しなかったバグということになる。

qpe を置き換えた時と同様にして QLibrary::QLibrary() だけを qtopia-free からとってきて LD_PRELOAD するのは少し難しい。 内部的に (QUnknownInterface の) virtual function を叩いているので、 virtual function table の index がずれないことを保証するためには 本物の(つまり qtopia-free でない、Sharp の手の入った) クラスの継承関係の宣言が必要になる。 いちいち libqpe 全体をリンクするというのも重そうなんだが、 まーでも、どーせ libqpe はメモリの上にあるわけだしな。

方針としては三策。

  1. PyQt を A300 向けに rebuild し、-lqpe する。
  2. libqte 参照時に自動的に libqpe を見に行くようにする。
  3. ほぼ同じことだが、PyQt 実行時に libqpe も見に行くようにする。

どれが正しいかは何とも言えない。たとえば 1. の方法は 実直なんだが、他の qte (not qpe) アプリでは また上の constructor が無いといって実行できない訳である。 2 or 3 の方法は解決方法そのものがマトモでない。

とりあえず 3. の方法で解決してしまったもの:

qt module を import すると同時に読みこまれる libsip.so というものがあるが、 これが内部で libqte だけを呼んでいる。 この部分でひっかかっているので、libqpe も読み込むようにした libsip に交換した。

この方法に価値があるのは PyQt の make に比べ SIP の make が格段に易しいからだが、 やろうと思えば SIP の rebuild すら必要なく、libsip の中で libqte.so.2 を呼んでいる部分を libqpe.so.1 にバイナリエディットしてしまえば (libqpe は libqte を呼んでるので) libsip は両方とも読み込むようになる。

2. の方法についてはまたそのうち。本質的には 3. と変わらんし。

1. の方法はさらに二策に分かれる。

PyQt は make のまえに python build.py しなければならない。 ふつーの ./configure に相当するのだが、 これがクロス構築に対応していない。で、この python build.py をセルフで実行するため「だけ」に kernel を入れ換え、Debian woody 入れた jail 作り ... するはめになったのだが、 どーせ build.py 動かしてから Makefile ごにょごにょ書き換えるんなら、 最初から build.py もクロスでそのまんま流してもよかったんではなかろーか、 という気もする。

セルフ開発環境の用意

zgcc 入れればすむような生易しい話ではなく。 Debian woody そのものを使った。 まずカーネルを直すところから ──
カーネルの zero page バグ
これはたぶん別項を起こす。 zaurus-ja ML の #545 〜 #557 の件のことだが、結論だけ書くと Debian (つーか dpkg) を SL-A300 で動かすためには下記パッチをカーネルに当ててつくりなおす必要がある。 自前で作りなおすともれなく zaurus-ja の w3m バイナリが動くようになるという特典もつく。 ついでだが、 てのもあるにはある。上の kernel のバグを w3m 側で対処してしまったもので、 カーネルにパッチをあてなくても w3m を SL-A300 で使うことができる ... というだけでなく、 zaurus-ja の w3m_0.3-1 だと embedded-konsole で罫線がでない (lcfont に 2 バイト罫線がなく、ついでに embedded-konsole の termcap がヘンなのか GR 区の 1 バイト罫線がうまく使えん) ので、いずれにせよこちらを使うことを勧める。

なお、上の w3m は zaurus-ja の w3m と違い、ssl に対応したため ライブラリとして libssl, libcripto を要求する。たとえば:

control ファイルの Depends: には書いておいたんだが、そういう風にしといても qinstall は 「libssl, libcripto を入れろ」とは言わないらしい (つ、つかえん ...)。
けっこ戸惑ってる人をちらほら見掛けるが、すまんかった。
再追記: Depends には version も入れなならんよーだ libssl (>=0.9.6) とか。次の版でなおそ。
statd
NFS root (/var/lib/dpkg/ 等が nfs 上にある) システムで apt-get, dpkg を使うには lockd が要る (zaurus-ja ml #540)。

Debian woody から nfs-common パッケージを拾ってきて、 その中から /usr/sbin/rpc.statd を取り出して A300 に入れる。 これは幸い libc 2.2.2 でも動く (同梱されてる mountd だったかはダメ)。

# mkdir /var/lib/nfs
# /usr/sbin/rpc.statd  
作法的には /etc/init.d/nfs-common start と起動するのが正しいが、 そうやって動くほど本体システムは Debian 化されてない。
chroot jail
母艦上で作っておいた arm 用 Debian woody 上へ chroot.
# mount -t nfs atropos:/home/src/SUBSYSTEM/arm /atropos
# cd /atropos
# chroot . /bin/zsh
# mount -t proc proc /proc
# apt-get install python2.2 gcc tmake
これ以外に何が必要だったかは忘れた。 まー、こまごまといろいろ要るんで、zgcc では足りないと書いたんだけども。
Qt/Embedded, Qtopia SDK
母艦環境の /opt/Qtopia/sharp 以下をもってくる。 もってきさきを /opt/Qtopia/ にするか /opt/Qtopia/sharp にするかを ちと悩んだが、前者にした。実は後者のほうがトラブルが少ないかもしれない。
セルフ開発環境向け tmake.conf の調整
/opt/Qtopia/sharp/tmake/lib/qws/linux-sharp-g++ はクロス向けに CC が arm-linux-gcc になっている。 TMAKE_CC, TMAKE_CXX を gcc, g++ に書き換えるほか、 TMAKE_CXXFLAGS から -DQT_QWS_CUSTOM を取り除き、TMAKE_LIBS_QT-lqte -lqpe とした。

-DQT_QWS_CUSTOM は SL-5000 向けのタッチパネルデバイスのための項で、 A300 には有害 ... だと思うんだが、ま、試しに除いてみたというのがほんとのところ。 TMAKE_LIBS_QT はというと、libqte に入ってるべきいくつかのクラスが libqpe に移ってたのでしょうがなく ... というのがつまり、QLibrary::QLibrary(QString const &, QLibrary::Policy) のことだけど。

A300 で libqte だけ使うアプリというものがありえない以上、 最初から -lqpe を付けてしまったほうが間違いがない。

ソースツリーの準備

PyQt for Zaurus はバイナリはあるのにソースが置いてない。 x11 用コードにマージされてるようでもありされてないようでもあり。
SIP と PyQt ソース
ソースを 本家 から拾ってくる。 つい sip-x11-gpl-3.4.tar.gz, PyQt-x11-gpl-3.4.tar.gz の組をひろってきそうになるが これらは zaurus 用のソースが一部足りない。 snapshot version を拾ってきて展開。
# zcat sip-x11-gpl-snapshot-20021128.tar.gz | tar -x
# zcat PyQt-x11-gpl-snapshot-20021129.tar.gz | tar -x

てとこで SIP から。

SIP の build.py
python build.py して makefile を作る。これは A300 上で行う。

# cd sip-x11-gpl-snapshot-20021128
# python build.py -l qte
SIP の make
make は母艦に戻って行う。CC, CXX, LINK あたりは arm-linux-gcc 等に書き換えるのは いつもとおんなじ。
# cd sipgen
# make && make install
# cd ../siplib
# make && make install
make からインストールまでしてしまったが、母艦環境で python2.2 を使ってないからできる暴挙である :-)
make した時点で /usr/local/bin に sip が入ってしまうなど、もともとの makefile の出来がよろしくないので注意を要する。
PyQt の build.py
つづいて PyQt の build. ... のまえにいくつか修正。
--- build.py~   Sat Nov 30 01:56:46 2002
+++ build.py    Sun Dec  1 22:42:06 2002
@@ -972,7 +972,7 @@
 int main(int argc,char **argv)
 {
     FILE *fp;
-    QApplication app(argc,argv,0);
+    // QApplication app(argc,argv,0);
 
     if ((fp = fopen("%s","w")) == NULL)
     {
リモートコンソール上から動かしてるせいか、 Qt アプリにしてしまうと features が作れなくなる。 これ自体は qte でもなんでもないので、外してしまう。

/opt/Qtopia/include/qmenubar.h を 1 行修正。
void QMenuBar::goodbye(bool) が private member になっているが、protected member であることを要求するので、(コンパイルの間だけ; 意味ねー ...) protected に。

sip/qpeapplication.sip の void dateFormatChanged(int); をコメントアウト。
Qtopia に対応する関数がもうない。qtopia-free 1.6.0 にもなかった。

それと、sipqtQMenuData をつくるために qt/Makefile の CXXFLAGS に -DINCLUDE_MENUITEM_DEF をつけておく。 /opt/Qtopia/include/qmenudata.h の中で デフォルトでは #ifdef INCLUDE_MENUITEM_DEF として何故か外されている。

そしてやっぱり build.py は A300 で動かす。

# cd  PyQt-x11-gpl-snapshot-20021129
# python build.py -l qte -a QtPE_1_5_0
"-a QtPE_1_5_0" をつけないと Qtopia 対応モジュールが make されない。
PyQt の make
もちろん母艦に戻っておこなう。A300 で続行してもいいんだろうが、 ... いや、べつに止めないけど。 emacs20 をセルフビルドした体感からみて 6 時間もあれば PyQt も出来るとは思う。
ただ、ソース無修正で最後まで通るとは限らないからねえ ...
# make && make install
Dom がないので pyuic2 は出来ない。pyxml も qte に実装が足りなくて(?) 出来ない (確かに pyqt_3.4-1.0_arm.ipk にもない)。それらはほっとけばスルーされる。

スクリーンショット

なにげに Hydro style にして撮ってみたりして。 QLineEdit もちゃんと動くよーやね。よしよし。
なお、コードの元ネタは 「湯けむりウィジェットツアー」トコの このあたり から。

PyQt の QLineEdit w3m

ついでに上で作った w3m も。

パッケージ

まあ、苦労してせっかく作ったんだし、パッケージにしてみた。
ところで、これを使う python 2.2.1 が /usr/lib/python2.2/ しか見てない (/home/QtPalmtop/ 下を見てない) ので、pyqt はカードには入れられない。 qinstall でカードに入れるためには python のほうから直す必要がある。

もっとも、/usr/lib/python2.2/site-packages/ にしかファイル置いてないから、よーするに /usr/lib/python2.2/site-packages/ をカードのどこかにsymlink しておけば「本体インストール」選んでも実体はカード行きになる訳で。

追記

w3m のその後については、12/27 の項を参照のこと。

追記、その2

pyqt_3.5-1.0-sla300-1_arm.ipk を作成、zaurus-ja に上げる。
[日記へ] [目次へ]