Python 3 の移植
現代の Python を Windows CE で動かす作業。
リポジトリ
By らすぴー
動作確認環境
第1世代
x PW-A9000 (表示に不具合?(白い長方形))
第2世代 (確認済みの全機種で表示に不具合あり?(白い長方形))
x PW-G4200
x PW-G5200
x PW-G5300
x PW-A9300
第3世代
x PW-SH1
第4世代
x PW-SH4
x PW-SB6
x PW-SH7
確認されている不具合
書かれていないものがあれば随時追加してください。(限定的な環境要因を除く)
_ RasPython3.icon working ウィンドウサイズを変更しないと、入力欄にフォーカスできない
_ RasPython3.icon 接頭辞(>>> や... )の幅が広すぎる
x RasPython3.icon done [X]で終了するとData Abortによりクラッシュする
x RasPython3.icon done プログラムの実行終了後、[X]で終了してもプロセスが残ってしまう
_ RasPython3.icon スクロールに伴うバグ
_ RasPython3.icon ceOpener使用時に、キーボードショートカットに割り当てているキーの入力が著しく遅れる(フォントの問題?)
_ RasPython3.icon working importしたモジュールの中でエラーが発生した際の、エラー箇所のファイルのパスがおかしい
x RasPython3.icon resolved 一部の機種でModuleNotFoundError: no module named 'os'がsite内で発生
x RasPython3.icon resolved PYTHONPATHで指定した場所からモジュールを読み込めない(パスが日本語を含むと発生?)
動作不良モジュール
x asyncio
x tkinter(tk.Menuにバグまだあり)
_ signal(_signalを入れていない)
x socket
x? subprocess
_ pip(導入未成功)
x? zlib
_ pyexpat
TODO
puhitaku.icon done clang-format を準備する
puhitaku.icon done リモートリポジトリからプライベートなデータを消す
puhitaku.icon clang-format で加わった好ましくない変更点を直す
RasPython3.icon done プライベートなデータが入り込んでしまった cpython-wince をまるごと消す(Git 管理されてない方を誤って消さないように!!)
RasPython3.icon done grep -r などを使って、Git リポジトリに入れる前の cpython ディレクトリにあるプライベートなデータをすべて置き換える
RasPython3.icon done プライベートなデータがない状態でビルドを通す
RasPython3.icon done exeのアイコンの設定
RasPython3.icon pipの動作確認または代替プログラムの作成
RasPython3.icon ビルド時の警告や、無駄な処理を減らす
RasPython3.icon important working terminal.cの動作改善(作り直しもアリ?)
RasPython3.icon done 環境変数の再現
RasPython3.icon done DOS窓Openを使わずに起動可能にする
RasPython3.icon 現状で、Makefile等をWinCE以外へのビルドもできるように修正する
RasPython3.icon done tcltkのdllやライブラリ一式を、python3.10.exeと同じ場所から読み込めるようにする
done? 標準ライブラリの移植
RasPython3.icon 各種追加モジュールのビルド
x numpy
参考になりそう? https://runebook.dev/ja/docs/numpy/user/building#cross-compilation
RasPython3.icon tcltk(>=8.4.0)の移植(tk.Menuの動作をWinCE向けに変更)
RasPython3.icon cegccをzlibに対応させる(zlibモジュールが使えない)
RasPython3.icon tcltkのライセンス等を入れる
RasPython3.icon working Python 製アプリの雛形を作る
RasPython3.icon done? Python 製アプリの起動方法とパッケージング にて、グローバルおよびローカルの environ.ini に記す内容、_pth も含めた挙動、読まれる優先順位について記す
777shuang.icon GitHub の release に ZIP を置くよう改良する
最初の merge の流れ done
必要な差分だけがあり、かつ cpython を clone して即 make しても通る状態にする
PR 作成
多分ブランチに変更が積み重なってると思うので squash merge
分散作業を開始して CI (GitHub Actions) に乗せる
リリース
今後の PR と merge の流れ
wince に checkout する
ブランチを切る、たとえば {ユーザー名}/{変更を表す単語} とかで
例: git checkout -b puhitaku/fix-foo
変更してcommit, push
PR を提出し、必ず1名以上にレビューを依頼する
レビュー対応
Merge
後日 3.10 より新しいバージョンへ rebase するときのメモ
importlib_bootstrap*.h が変わっている
Modules/_io/winconsoleio.cの変更はModules/_io/winceconsoleio.cにも影響する
ce_*.shのなかには、3.10をハードコーディングしている箇所がある
Python3の同時起動問題
背景
WindowsCEでは、同名の異なるdllを別々に読み込むことができない。
そのため、異なる時期にビルドされたpythonの
python310.dll(旧libpython3.10.dll)や_tkinter.pyd(dll扱い)などが、それぞれのpythonを同時に起動した際に干渉して、誤った動作をしてしまう、という問題が発覚した。
解決策
*.pydの末尾を*.cpXY-wince_arm.pydに変更する。
pythonX.Y.exeとpythonXY.dllに、ソースから生成されたオブジェクトファイルのハッシュ値を埋め込み、実行時に照合する。
これにより、メジャー・マイナーバージョンが異なるpythonは同時に起動でき、マイクロバージョンが異なるか、ビルドが異なるpythonは同時起動できなくなった。(実行しても即時終了する)
統合元: Python3の同時起動問題
移植の流れメモ
PythonCEが2.5と古いから微妙だな、と思って、詳しく調べた
Python3.6への移行時にWinCE関連を消すパッチが当てられていたことに気づく()
そのパッチと、PythonCEの一部のファイルを、Python3.10.10のソースに突っ込む(実際には、2.5から3.6までの間に自然消滅していた箇所も多くあったため、ワンライナー等でPythonCEからWinCE関連のものを探しもした)
PythonCEが、疑似インタプリタをPythonコードで動かしていて、そのまま使いたくなかったため、とりあえずターミナルっぽいものを別で作る
Windowsを持っていないので、linuxのMakefileから作ることにする
Makefileやconfigureをいじくり回して、arm-mingw32ce-gccでWinCE向けのビルドができるようにする
configureとmakeとデバッグをひたすら繰り返す
事前に作っていたターミナルっぽいやつではまだうまく動いていないが(sys.std系が不完全)、DOS窓Openで、pyファイルを動かすことに成功
具体的な移植の流れ
BrainWikiでPythonCEを知る
当時は、cabインストールがなんだか怖くて入れていなかった。
しかもPython2.5だから、入れても使うのが難しいと感じていた。
そのため、PythonCEのPython3版を探したがどこにも無かった。
無いなら作ろう。
実はこの時点で、移植どころか、C言語やMakefileの経験、Pythonのビルド経験は全くと行っていいほどなかった。ただの興味。
それで、PythonCEに関することを調べまくったところ、Python3.6のタイミングで、PythonCEの名残のコードを削除するパッチが当てられていた事がわかり、さらに、PythonCEの配布ページには、Python2.5に当てるためのパッチもあり、それらをとりあえずダウンロードした。
3.10.10にした理由
確か、比較的安定そうなメジャーバージョンの当時の最新バージョンが3.10.10だったからだったと思う。(これが後に悪手となる)
パッチを当てる
当てる、といっても、パッチを具体的にどう当てたらよいかわからず、結局すべて手作業で当てた。よく考えたら、手動じゃなきゃ、2.5から3.10までの全パッチも使わないとできないので、結果オーライ?
ビルドのやり方
はじめは、PythonCEと同様に、sconsでビルドできるかなー、と、非常にのんきに考えていた。ところが、PythonCEではMicrosoft eMbedded Visual C++ 4.0をビルド時に必要としていた。scons自体も初めてだった私は、じゃあどうすれば?となった。
なかなか考えが浮かばず、とりあえず見た目からつくって動作時に達成感をより得られるようにしよう、と思い、scons等について調べる傍ら、ターミナルのようなものをtkinterで作成し、windowsapiでもどうにかそれっぽく再現した。
ゴリ押しは正義
悩んだ末、Windows依存のコード以外は共通なんだし、Makefileを魔改造したら行けるか、という結論に至った。アタマガオカシイ。ちなみにこの時点で、さすがに無茶だからうまく行かないと思っていた。
しかし、実は一つ可能性(?)があった。Makefileの作り方も知らない私は、それっぽいファイルを一通り覗いて回った。すると、config.subの中にmingw32ceがあり、これは、おそらくMakefile共通で使われるファイルなのだろうが、そんな事も知らない私はそれで少し希望を抱いた。
とりあえずビルドしてみる
ネットを彷徨って、クロスコンパイルのやり方を探した。そしてそれに則って、とりあえずconfigureとmakeを実行。案の定、「こんなマシン知るか」とエラーを吐かれる。というわけで、次に、Makefileやconfigureの作り方を調べ、Makefile.pre.inやconfigure.acにすこし記述を加え、環境変数でpthreadを無効にしたりして、どうにかcegccでのコンパイルまで持ってきた。
地獄の始まり
コンパイルが始まった、と思ったら、大量のエラー。当たり前だが、Windows用のフローではないので、色々と定義がなかったりする。だが本来のフローであるPCbuild内のファイル群(*.vcxprojなど)を読める環境はない。と思ったが、ほとんどのファイルの中身がxmlで、なんとか必要なファイル一覧を作成できた。それに従って、Makefileをいじり、再トライ。マクロが足りない。追加。再トライ。繰り返して繰り返し、どうにかコンパイルを乗り越えたら、今度は大量のundefined reference toが出てきた。
この原因は、Python2.5からPython3.10までに書き加えられた、多くの「WindowsCEに実装されていないモノ」で、PythonCEではPC/wince_compatibility.*で対応がされていた。それからは、そのファイルに、ひたすら代替定義を書きまくった。これが本当に多く、体感では百は越えていたような気がする。ここに一番時間がかかったと思う。
また、PythonCEのインタプリタの実装が、Pythonのモジュールとして作られていることに気がついたのもこのときだった。sconsのコード内に、pyファイルが依存関係として記述されているのはなぜだろうかとは思っていたが、その中身は、疑似インタプリタとPythonを仲介するプログラムだった。
コンパイルが終わり
大量の代替定義を書き終え、バイナリを生成できるまで至った。そこで問題となったのが、ファイルの構成をどうするか、である。生成物はlinuxの配置で生成されたが、使用環境はWindows系なので、変えて動くのかわからなかった。そこで、Python公式が配布しているembeddable packageの構成と、PythonCEの構成を参考にして、実機に移し、動かしてみた。
もう一つの難所
さて、実機での動作確認に映るのだが、最初は何も起こらず終了した。調べてみると、(少なくともPW-SH7では)CryptAPIの関数が削られていたため、それの代替関数を作った。その後、初期に一番多かったのが、クラッシュだった。c初心者のコードなので、間違いやミスが膨大にある。しばらくはその修正に追われた。具体的な修正方法だが、winapiが関係ない関数等は、linux上で動くよう少しだけ関数のコードを改変し、コンパイルして実行するというものと、winapiに関係するものは、OutputDebugStringWでエラー箇所を突き詰めていくというものだった。このようにして、なんとかエラーを減らしていった。
Hello World
なんとかwinapi以外の不具合を解消して、winapi関連の問題を調べていたときに、そういえばDOS窓Openでpythonのコードを実行できるのでは?と思って、やってみた。流石にいくつかエラーがあったが、それを修正したところ...Hello World動いた。えっ...えっ?...そして、Brain HackersのDiscord鯖にHello Worldが動いたことを報告した。(正直需要がそこまであると思っていなかったので、とりあえず、という感じだった。)
(not yet)
ビルド方法
64bitのDebianで、CeGCCとpython3を導入
ダミーのlocale.hを配置 (不要)
PythonCEのTkinter-Files.zipをダウンロード (不要)
./ce_build.sh && ./ce_pack.shを実行
wince_buildの中にファイル群が入っている。
ソース直下のtcl8.4.3をBrainのルート直下に、tcl84.dll、tk84.dll、celib.dllを\Windows直下にコピーすると、tkinterも動作する。
クリーンにするには、./ce_clean.shを実行