python VM
実践はSmall Basicで!「インドの小学校で教えるプログラミングの授業」
こういう本が有ったので、読んでみた。インドはIT大国。どんな事を教えているかと思ったら basicでやってるのね。日本でも小学生からパソコンを教えるとか英語を教えるとか、世界に 打って出ていけるように必死になってるな。
どこかのママが調べてくれたのがあった。 世界のプログラミング教育事情
こちらは、その筋の先生。
オイラーも入れてみた。
Microsoft Small Basic 1.2 - 日本語
インターナショナルって謳っているので、マイクロソフトの考える世界標準かな。
International Small Basic Getting Started Guide
これを卒業したら、下記を見ればよい。
灯台下暗しで、
C:\Program Files (x86)\Microsoft\Small Basic\Samples
に、サンプルが置いてあるから、適当な所に取り出して、いじくり倒せばよい。エラーを 出した回数だけ、知力が増すぞ。あーだこーだが勉強さ。
いくつかのエラーが発見されました。 アクセスが拒否されました。(HSRESULTからの例外:0x80070005(E_ACCESSDENIED))
オリジナルな場所にあるサンプルで実行すると上記のエラー。で、きっと書き込み権限が 無いんだろうと思って、DeskTopに持ってきたら、実行出来た。オリジナルのソースである、*.sb に対して、*.pdb ってのと、*.exe と、SmallBasicLibrary.dllが作られていた。*.exeを ダブルクリックすると、そのままアプリが実行出来たよ。ちょいとアプリを作るには 便利なやつだな。起動するたびに、OneDriveを設定しろと言ってくるのはうざいけどね。
python VM
a = 1 とだけ書いたt.pyを実行。
#0 run_file (fp=fp@entry=0x955780, filename=filename@entry=0x916280 L"t.py", p\ _cf=p_cf@entry=0x7fffffffe360) at ../Modules/main.c:323 #1 0x0000000000435443 in Py_Main (argc=argc@entry=2, argv=argv@entry=0x915010)\ at ../Modules/main.c:780 #2 0x000000000041d14a in main (argc=2, argv=0x7fffffffe4d8) at ../Programs/pyt\ hon.c:69
python t.pyのように実行した場合は、run_file関数の中で処理が行われる。t.pyにimportが 含まれていると、importの膨大な処理が入ってきてめげるので、簡単なスクリプトがお得。 以下、処理の追跡結果。
(gdb) bt 5 #0 _PyEval_EvalCodeWithName (_co=_co@entry=0x7ffff7ea41c0, globals=globals@ent\ ry=0x7ffff7eb2a30, locals=locals@entry=0x7ffff7eb2a30, args=args@entry=0x0, arg\ count=argcount@entry=0, kwnames=kwnames@entry=0x0, kwargs=kwargs@entry=0x8, kwc\ ount=kwcount@entry=0, kwstep=kwstep@entry=2, defs=defs@entry=0x0, defcount=defc\ ount@entry=0, kwdefs=kwdefs@entry=0x0, closure=closure@entry=0x0, name=name@ent\ ry=0x0, qualname=qualname@entry=0x0) at ../Python/ceval.c:3862 #1 0x0000000000530b58 in PyEval_EvalCodeEx (_co=_co@entry=0x7ffff7ea41c0, glob\ als=globals@entry=0x7ffff7eb2a30, locals=locals@entry=0x7ffff7eb2a30, args=args\ @entry=0x0, argcount=argcount@entry=0, kws=kws@entry=0x0, kwcount=kwcount@entry\ =0, defs=defs@entry=0x0, defcount=defcount@entry=0, kwdefs=kwdefs@entry=0x0, cl\ osure=closure@entry=0x0) at ../Python/ceval.c:4140 #2 0x0000000000530ba2 in PyEval_EvalCode (co=co@entry=0x7ffff7ea41c0, globals=\ globals@entry=0x7ffff7eb2a30, locals=locals@entry=0x7ffff7eb2a30) at ../Python/\ ceval.c:695 #3 0x00000000004230f4 in run_mod (mod=mod@entry=0x955aa8, filename=filename@en\ try=0x7ffff0b6f860, globals=globals@entry=0x7ffff7eb2a30, locals=locals@entry=0\ x7ffff7eb2a30, flags=flags@entry=0x7fffffffe360, arena=arena@entry=0x7ffff7e885\ 20) at ../Python/pythonrun.c:980 #4 0x0000000000425974 in PyRun_FileExFlags (fp=fp@entry=0x955780, filename_str\ =filename_str@entry=0x7ffff7e599b8 "t.py", start=start@entry=257, globals=globa\ ls@entry=0x7ffff7eb2a30, locals=locals@entry=0x7ffff7eb2a30, closeit=closeit@en\ try=1, flags=flags@entry=0x7fffffffe360) at ../Python/pythonrun.c:933 (More stack frames follow...)
ソースを参照しながら追って行くと気づくけど、returnの所に置いてある関数が主力の処理と なる。それ以前のものは、準備をしてるだけ。こういう書き方は、OSのシステムコールとか でも煩雑に行われているので、迷う事なく、深く潜って行けるぞ。
#0 _PyEval_EvalFrameDefault (f=<optimized out>, throwflag=<optimized out>) at \ ../Python/ceval.c:1220 #1 0x000000000052fb14 in PyEval_EvalFrameEx (f=f@entry=0x976e18, throwflag=thr\ owflag@entry=0) at ../Python/ceval.c:718 #2 0x000000000053053b in _PyEval_EvalCodeWithName (_co=_co@entry=0x7ffff7ea41c\ 0, globals=globals@entry=0x7ffff7eb2a30, locals=locals@entry=0x7ffff7eb2a30, ar\ gs=args@entry=0x0, argcount=argcount@entry=0, kwnames=kwnames@entry=0x0, kwargs\ =kwargs@entry=0x8, kwcount=kwcount@entry=0, kwstep=kwstep@entry=2, defs=defs@en\ try=0x0, defcount=defcount@entry=0, kwdefs=kwdefs@entry=0x0, closure=closure@en\ try=0x0, name=name@entry=0x0, qualname=qualname@entry=0x0) at ../Python/ceval.c\ :4119 #3 0x0000000000530b58 in PyEval_EvalCodeEx (_co=_co@entry=0x7ffff7ea41c0, glob\ als=globals@entry=0x7ffff7eb2a30, locals=locals@entry=0x7ffff7eb2a30, args=args\ @entry=0x0, argcount=argcount@entry=0, kws=kws@entry=0x0, kwcount=kwcount@entry\ =0, defs=defs@entry=0x0, defcount=defcount@entry=0, kwdefs=kwdefs@entry=0x0, cl\ osure=closure@entry=0x0) at ../Python/ceval.c:4140 (More stack frames follow...)
こんな風に、そろりそろりと潜っていくのが、観光と言うか探検のセオリーです。
解説書によると、三つの基本要素:CodeObject, FunctionObject, FrameObject を理解する必要があるそうだ。
CodeObjectってlispで言うatomの事かな。FunctionObjectはlambdaか。そしてFrameObjectは、実行環境と、今の所思っておこう。(後で、修正されるかも知れないので、真にうけないで)
また、FrameObjectは、モジュール、クラス、functionと別々にデータスタックを持つとな。 C語みたいにマシンべったりではなくて、整理されてるな。
ちょいと復習で、dis用コード
[cent py]$ cat a.py def hoge(x): return x * x y = hoge(321) # import dis;import inspect as ins;dis.dis(ins.stack()[0][0].f_code)
普通に、disる。
[cent py]$ python3 -m dis a.py 1 0 LOAD_CONST 0 (<code object hoge at 0x7fde75012f40, file "a.py", line 1>) 2 LOAD_CONST 1 ('hoge') 4 MAKE_FUNCTION 0 6 STORE_NAME 0 (hoge) 4 8 LOAD_NAME 0 (hoge) 10 LOAD_CONST 2 (321) 12 CALL_FUNCTION 1 14 STORE_NAME 1 (y) 16 LOAD_CONST 3 (None) 18 RETURN_VALUE
肝心のdef内部が見えない。
[cent py]$ python3 -i a.py >>> import dis >>> dis.dis(hoge) 2 0 LOAD_FAST 0 (x) 2 LOAD_FAST 0 (x) 4 BINARY_MULTIPLY 6 RETURN_VALUE
こういう時は、codeを実行後もreplが回っているように、-iを 付けて起動。そして、disで関数をdisる。
gdb for python debug
前回ちらっと探し当てていた、gdb実行中にpythonのスタックを見られたりする拡張方法。 試してみたけど、py-btとかは見つからないと拒否されていた。
試しに、gdbの起動時に、gdb -x python-gdb.py python とか、gdbの起動後に、source python-gdb.py すると、使えるようになる。
何でかな? ~/.gdbinitに書いたやつが無視されてるっぽい。穴のあくほど、説明書を 読みましたよ。そして裏読みです。pythonをコンパイルしたdirで実行ってなってるな。 オイラーは、残骸を全部消して、python-gdb.pyだけを残していたんだ。 ひょっとして、gdbを起動したdir内に、python本体が必要かも知れんぞ。
ものは試しと、
[cent ~]$ tree py py ├── a.py ├── pg.py ├── python └── python-gdb.py
のようにしてみた。そしたら、説明書のごとく、普通に動いた。これって、gdbはwork-dirに pythonが有ると、お供のpython-gdb.pyって言う初期化ファイルを特別に読み取って くれるのではなかろうか。
もし、そうなら、今使ってる(CentOS様ご提供の)gdbに仕掛けが施されているに違いない。 痕跡を探してみる。
[cent ~]$ strings /usr/bin/gdb | grep python libpython2.7.so.1.0 : set auto-load python-scripts show auto-load python-scripts info auto-load python-scripts :
こういうのは見つかったけど、ずばりのpython-gdb.pyは出てこないですね。
しゃーない、ソース嫁。
[cent tmp]$ tar Jxf gdb-7.12.1.tar.xz [cent gdb-7.12.1]$ find . -name '*.[ch]' | xargs grep -l -- -gdb.py ./gdb/extension-priv.h ./gdb/python/python.c ./gdb/auto-load.c ./gdb/extension.c
なにか、それっぽいのが引っかかってきたぞ。
その前に、新しいgdbを入れておくか。インストールしようとしたら、infoを作れないと言われてSTOPした。makeinfoが必要らしいんだけど、入っていない。 texinfoを入れると付いて くるそうだ。それから、pythonって名前のやつしか認識しないようなので、もし、python3系 を使いたかったら、pythonにリンクしておけ。
python.cに名前の定義が、auto-load.cに、pythonと言う拡張言語用のスクリプト読み込み ルーチンが登録されてた。で、ソースを見てる時、何が読み込まれた知る方法が示されて いたので、試してみる。
[cent py]$ gdb -q python Reading symbols from python...done. (gdb) info auto-load python-scripts Loaded Script Yes /home/sakae/py/python-gdb.py (gdb) q [cent py]$ mv python python3 [cent py]$ gdb -q python3 Reading symbols from python3...done. (gdb) info auto-load python-scripts No auto-load scripts. [cent py]$ gdb -q /my/bin/python Reading symbols from /my/bin/python...done. (gdb) info auto-load python-scripts No auto-load scripts.
このように、debug対象のプログラム名は、work-dirにあるpython(3)、そいつに-gdb.pyをくっつけたファイルが有る場合のみ、auto-loadされる。python開発者の便を図る特殊 仕様なんだな。(installしなくても、lib等が使えるように、sys.pathがセットされてるぞ)
早速、gdbとpythonの癒着の成果を使ってみる。
Breakpoint 2, PyEval_EvalFrameEx ( f=f@entry=Frame 0x97c698, for file a.py, line 1, in hoge (x=321), throwflag=throwflag@entry=0) at ../Python/ceval.c:716 716 { (gdb) py-list >1 def hoge(x): 2 return x * x 3 4 y = hoge(321) (gdb) py-bt Traceback (most recent call first): File "a.py", line 1, in hoge def hoge(x): File "a.py", line 4, in <module> y = hoge(321)
いよいよVMの始動。実行を進めていくと
(gdb) s 717 PyThreadState *tstate = PyThreadState_GET(); (gdb) 718 return tstate->interp->eval_frame(f, throwflag); (gdb) _PyEval_EvalFrameDefault ( f=Frame 0x97c698, for file a.py, line 1, in hoge (x=321), throwflag=0) at ../Python/ceval.c:723 723 {
大分進んだ所
(gdb) py-bt Traceback (most recent call first): File "a.py", line 2, in hoge return x * x File "a.py", line 4, in <module> y = hoge(321) (gdb) py-list 1 def hoge(x): >2 return x * x 3 4 y = hoge(321)
これに対する、C語の部分も分かるので、プチ嬉しいぞ。と、いささか猫に小判状態であります。
virtualBox Disk compress
Vboxも長く使っていると、Diskが肥大化してくる。VMWARE Playerだと、open-vm-tools相当を入れておけば
[fb11: sakae]# vmware-toolbox-cmd disk shrink / Please disregard any warnings about disk space for the duration of shrink process. Progress: 54 [======> ]
こんな風にして圧縮出来るんだけど、vboxの場合は如何に?
仕組みは同じだけど、一手間余計にかかる。まず、Windows上のdiskファイルサイズ
2017/03/28 05:38 9,895,411,712 Debian.vdi
続いて、Debianでの使用状態
[debian ~]$ df Filesystem 1K-blocks Used Available Use% Mounted on /dev/sda1 19620732 4304940 14296044 24% /
約5Gの無駄が有るな。ゴミをzeroで埋めて、gcの目印を作る。
root@debian:/home/sakae# dd if=/dev/zero of=/zero bs=4k dd: error writing '/zero': No space left on device 3813833+0 records in 3813832+0 records out 15621455872 bytes (16 GB) copied, 29.0207 s, 538 MB/s
続いて、ごみの /zeroを削除しとく。そしてdebianを落とす。
C:\Users\sakae\VirtualBox VMs>"c:\Program Files\Oracle\VirtualBox\VBoxManage.exe" list hdds UUID: 72f6c0b3-9639-4676-9dab-4b16a507e756 Parent UUID: base State: created Type: normal (base) Location: C:\Users\sakae\VirtualBox VMs\Debian\Debian.vdi Storage format: VDI Capacity: 20480 MBytes Encryption: disabled
idが分かったら、それを指定して、圧縮。
C:\Users\sakae\VirtualBox VMs>"C:\Program Files\Oracle\VirtualBox\VBoxManage.exe" modifyhd 72f6c0b3-9639-4676-9dab-4b16a507e756 --compact 0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100% 2017/03/14 14:20 5,313,134,592 Debian.vdi
diskを取り戻せたぞ。半年に一度ぐらいは実行しよう。
VMWAREでゲストしてる、OpenBSDはどうする? 移植しようとしたら、作りが異端児なんで 拒否されたぞ。
etc
やっぱり VM となれば、Forthは外せません。
SmallBasicは、Windowsでしか動かんからなあ。その点、こちらはブラウザーが有れば、 どこでもおk。
p5.min.jsを落としてきて、index.htmlをクリック。後は、マウスでぐりぐり。
[debian tmp]$ cat index.html <html> <head> <script src="p5.min.js"></script> <script src="testme.js"></script> </head> <body> </body> </html>
[debian tmp]$ cat testme.js function setup() { createCanvas(640, 480); } function draw() { if (mouseIsPressed) { fill(0); } else { fill(255); } ellipse(mouseX, mouseY, 80, 80); }
なんか、プロセッシングに源流が有るそうですよ。javascript恐るべし。