current-trace-port

Windows7ユーザーに新年のあいさつを兼ねて、連絡を取ってみた。EOLになる事をすっかり失念していた風だった。

どうするのかなあ? 棄てちゃう? HDDだけは抜き出して粉砕ですかね。それとも円盤の所でも穴を開けてから塩水に漬ける。そんなの生温い。塩素系漂白剤とかトイレ用塩素洗剤にでも漬けなさい。 円盤はコーティングしてあるから、案外丈夫だったりして。

去年のHDD横流し事件で、中古業界に困惑が広がっているとか。大手電器店でほとんど無料でパソコンを引き取ってくれる。HDDを再生して売ると良い利益が出たらしい。それが、事件後は、物理的に破壊をする人が多くなって、やりにくくなってるとか。そんなものなんですかね。

そう言えば、オリンピックのメダル用に、都市鉱山に期待をかけられていたけど、思うように調達出来たのかしらん。オリンピック・オリンピックと騒々しい年になりそうだなあ。

サポート切れのWin7搭載PCを処分、内蔵HDDから情報漏洩させない方法

グッドタイミングで記事が出てた。HDDを取り出してから消去って面倒。で、USBに焼いたOpenBSDから起動して、ddコマンドでHDDを消去するのさ。その為にUSBを作ってあるのよ。

git-pull and log

Gaucheのgit場所は、 https://github.com/shirok/Gaucheだ。 ここに最新版がある。一度git cloneしても、その後追従しない手は無い。 追従は下記のようにする。

(base) [sakae@c8 Gauche]$ git pull
  :
Fast-forward
 lib/data/skew-list.scm     | 27 ++++++++++++++++++++++++++-
 lib/gauche/vm/debugger.scm |  7 +++++--
 src/libmacbase.scm         |  3 ++-
 test/data.scm              | 30 ++++++++++++++++++++++++++++++
 4 files changed, 63 insertions(+), 4 deletions(-)

前回からの差分を取ってくると同時に、どんな変更が有ったか要約を報告してくる。 どんな変更が有ったかは、ログを見ればよい。

(base) [sakae@c8 Gauche]$ git log
  :
Date:   Sun Jan 5 22:40:21 2020 -1000

    Flush trace port after each trace output

    If we're logging, it's more convenient.
----
Date:   Sat Jan 4 21:02:52 2020 -1000

    Document current-trace-port
----
Date:   Sat Jan 4 20:47:19 2020 -1000

    Add current-trace-output to be used for debug-print and trace-macro

これを見るだけで、ハワイ在住の夜型の人って分かる。時差はどれぐらいあんの? ググルで、時差 ハワイって聞いたら、-19時間ですって。

オイラーは引き算に弱いので、24時間との差を元に、日本との時差は5時間進んでるよ(但し前日ね)って理解してる。日本の正午は、向こうの時間で何時? 5時間足すと向こうでは夕暮れ(但し1日遅れね)って分かる。

そんな事で、日本を夜に出発すると、ホノルル着は、同日の朝。何か得した気分にさせられたと、例のハネムーナーは言ってた。

#?= 再び

前々回だったか、goshのdebug支援機能に結果表示をログに落とせるようにお願いした。したらすかさず実現して貰えた。

なるほど。まずdebug-printの出力先の変更ですが、これはcurrent-debug-portみたいな
パラメータを使って切り替えられるようにしとくと便利かもしれないですね。
CLで*debug-io*とか*trace-output*が別になっているように。

スタックトレースに関しては、#?! (debug-break) という、ブレークポイント発動して
デバッガに入るという機能をいつかつけるつもりでいました。
デバッガ内からスタックは覗けます。#?=で出すと情報量が大量になりすぎるので。
ただ、他のファイルにダンプするなら情報量が増えてもいいので、
debug-print-preとdebug-print-postに何らかのカスタマイズ手段を設けても良いかも
しれないです。

current-trace-outputを作ったらマクロトレースにも使えるな。
                                                  2020/01/05 07:03:18 UTC
-------------------------------------------------------------------------
current-trace-portつけました。
                                                  2020/01/05 22:52:55 UTC

git diff

それを実現する為にどんな変更が入ったの? それは下記のようにすると調べられる。(予め手を入れたファイルが分かっている場合)0.9.9からの変更を洗い出す。

(base) [sakae@c8 Gauche]$ git diff release0_9_9 lib/gauche/vm/debugger.scm
diff --git a/lib/gauche/vm/debugger.scm b/lib/gauche/vm/debugger.scm
index b0ed5047d..8035525d3 100644
--- a/lib/gauche/vm/debugger.scm
+++ b/lib/gauche/vm/debugger.scm
@@ -79,23 +79,25 @@
                        (car info) (cadr info) (debug-print-width) form)
                (format "#?=~a~,,,,v:s\n" thr-prefix
                        (debug-print-width) form))
-             (current-error-port))))
+             (current-trace-port))
+    (flush (current-trace-port))))
       :

お前、gitのアカウントを持っていないのにgitに詳しくなってどうする? 勉強ついでに、プルリクエストって何ぞや。

Pull Requestの手順

Gitを使ってPull Requestを投げるまで

手がかりから追跡

上の例では、天下り的にやっちゃったけど、また刑事になって追ってみるか。手掛かりは、current-trace-port しかない。

(base) [sakae@c8 Gauche]$ find . -type f | xargs grep -l current-trace-port
./lib/gauche/vm/debugger.scm
./ChangeLog
./doc/corelib.texi
./src/libmacbase.scm
./src/libio.scm

他にも手が入ってるファイルが有るのね。ファイル名が分かれば、上の方法を使える。あるいは直接ファイルを開いて、trace-portぐらいで検索するのも手だな。

libmacbase.scmの方は、trace-macroへの対応だった。一粒で2度美味しいって訳だな。もう一方のlibos.scmでは、

(inline-stub
 (initcode
  (Scm_BindPrimitiveParameter (Scm_GaucheModule)
                              "current-trace-port"
                              (Scm_Stderr) 0)))

こんな手続きが追加されてた。Scm_Bind... ってのは束縛だ。平たく言うと名前を付けるって事。current-trace-portって、名は体を表す名前になってる。キラキラネームじゃなくて良かった。登録と同時に初期値も決めているな。

その点、 某OSでのNIC名はenp8s3みたいになってる。昔はどんなチップが載っていようとeth0みたいな感じだったね。*8s3って、独房の番号ですかい。これじゃ愛もない囚人番号みたい。 (遠方で吠えていた人の記者会見で囚人なんて言ってたから、つい釣られました)

NICのドライバーを苦労して開発した人を讃えて、命名権ぐらいは与えよ。(BSDとかだと、em0とか、蟹さんだとre0とかって名が付いてるぞ)国際物理学とか天文学では、最初に新しい元素を生み出した人に命名権が与えられるし、新星を見つけた場合も同様だ。全く敬意が感じられない。

ついでにChangeLogも見ておく。

2020-01-04  Shiro Kawai 

        * src/libio.scm (current-trace-port): A parameter to keep trace output.
        * src/libmacbase.scm: Macro traces goes to current-trace-port.
        * lib/gauche/vm/debugger.scm: Debug print goes to current-trace-port.

なんか、まとめサイトみたい(笑)

コンパイル and ゴー

と行きたいのだけど、少々前準備が要る。gitからの提供品には、みんな大好きなconfigureが用意されていないんだ。configureは巨大なshellスクリプトなんだけど、コンパイル環境によってまちまちになるんで、最初から提供は出来ないんだ。

その為、環境に合わせてconfigureを自動生成するスクリプトが用意されてる。

(base) [sakae@c8 Gauche]$ ./DIST gen
libtoolize: putting macros in AC_CONFIG_MACRO_DIRS, 'm4'.
libtoolize: copying file 'm4/libtool.m4'
  :
libtoolize: copying file 'm4/lt~obsolete.m4'
Makefile.am: installing '../depcomp'

Ready to run './configure'.

用意が整いました。後はテストまで実行してくれるコマンド列を書いて、お茶(今ならタピオカか、ってJKじゃねぇーよ)してれば良い。

(base) [sakae@c8 Gauche]$ ./configure && make && make check
  :
 12  (do ((#:p999 insns (cdr #:p999))) ((null? #:p999) (let1 insn  ...
        expanded from (dolist (insn insns) (case-label insn) (render1 insn))
        at "./geninsn":170
 13  (construct-vmbody insns)
        at "./geninsn":445
make[1]: *** [Makefile:281: gauche/vminsn.h] Error 70
make[1]: Leaving directory '/tmp/Gauche/src'
make: *** [Makefile:45: all] Error 1

投入コマンド間を結んでいる && は、前のコマンドの実行結果が成功したら次のコマンドを実行すると言う意味。

今回はmakeに実行中にgoshの実行に失敗したと言う事だ。開発者と今の環境(CentOS)が違うため、齟齬が有ったのだろう。こういう場合に備えて、debianを用意してるのさ。

それから最初に書き忘れていたけど、開発版を扱う場合は、事前に最新版のgaucheをインストールしておく必要が有るからね。

と言う事で、舞台をdebianに移したら、すんなり行けた。後は普通にインストールすれば良い。

尚、変更部分が *.scm に限定されるなら、コンパイルの過程を省いて、直接、/usr/local/share/gauche-0.97/0.9.9/lib/の下あたりに有るやつを更新してもいいだろう。(やった事ないけどね)

あ、今回はそういう訳にもいかない。変更部分の内、libmacbase.scmとlibio.scmはsrc/の下に配置されてる。これらは最終的にプリコンパイルされてC語になっちゃうから、debuuger.scmだけを(強引に)更新しても、根幹のcurrent-trace-portが使えないな。以後、配置にも気を付けろだな。

0.9.9を作った時のログが残ってたので、ちょいと調べてみる。

(base) [sakae@c8 Gauche-0.9.9]$ grep libmacbase MAKE.log
gcc -DHAVE_CONFIG_H -I. -I. -I./../gc/include -I../gc/include `./get-atomic-ops-flags.sh .. .. --cflags`   -g -O2 -Wall -Wextra -Wno-unused-label -fPIC -fomit-frame-pointer  -c libmacbase.c
TARGETLIB="`pwd`"  gcc -g -O2 -Wall -Wextra -Wno-unused-label -fPIC -Wl,--rpath="`pwd`" -L.  -Wl,--soname,libgauche-0.97.so.0.9  -shared -o libgauche-0.97.so box.o core.o vm.o compaux.o macro.o connection.o code.o error.o class.o dispatch.o prof.o collection.o boolean.o char.o string.o list.o hash.o dws32hash.o dwsiphash.o treemap.o bits.o port.o write.o read.o vector.o weak.o symbol.o gloc.o compare.o regexp.o signal.o parameter.o module.o proc.o number.o bignum.o load.o lazy.o repl.o autoloads.o system.o compile.o libalpha.o libbool.o libchar.o libcode.o libcmp.o libdict.o libeval.o libexc.o libfmt.o libio.o liblazy.o liblist.o libmacbase.o libmacro.o libmisc.o libmod.o libnum.o libobj.o libomega.o libproc.o
librx.o libsrfis.o libstr.o libsym.o libsys.o libvec.o libgc_pic.a `./get-atomic-ops-flags.sh .. .. --libs` -ldl -lcrypt -lutil -lrt -lm  -lpthread

陽にlibmacbase.scmは出てこないけど、片鱗のlibmacbase.cがいきなり出て来ているなあ。どこで変換をかけているのだろう?

(base) [sakae@c8 src]$ grep libmacbase Makefile
        liblazy.$(OBJEXT) liblist.$(OBJEXT) libmacbase.$(OBJEXT) \
libmacbase.c : libmacbase.scm $(PRECOMP_DEPENDENCY)
            libmacbase.c libmacro.c \

ああ、見つかった。実際の変換はgenstubかな。そしてその中から、gaucheの既存のモジュール、(use gauche.cgen) (use gauche.cgen.stub) とかを呼んでる。だから、コンパイルするにはgaucheが必要とな。なんだか鶏・卵問題が出てきたな。何も無い環境にgaucheを入れる場合、親元で変換された、libmacbase.cとかを供給して、gauche-lessでも済むように配慮してるんだな(多分)。 やや、precompなんてのもあるぞ。

それから、get-atomic-ops-flags.shなんてのが上のLOGに出てたけど、どうもgcと密結合するための道具みたいだ。 複雑過ぎて、頭が回らんな。昔の手書きのMakefileぐらいがオイラーには丁度良いぞ。

current-trace-port試運転

以前から何度も実験に使っているgenstubで試してみる。

(base) sakae@debian:tmp$ gosh
gosh> current-trace-port
#<primitive-parameter current-trace-port @0x7f663e84a6c0>
gosh> current-error-port
#<subr (current-error-port :optional newport)>
gosh> (define current-trace-port (open-output-file "LOG.txt"))
current-trace-port
gosh> current-trace-port
#<oport LOG.txt 0x7f663e880c00>
gosh> ,l ./genstub
#?="./genstub":168:(c-name-of cproc)
#?-    "stdlib_eqvP"

うん、current-trace-portって叩いて、それなりの反応が返ってきた。error-portって内部関数なの知らなかったなあ。

次はtrace-portにファイルポートを設定。確認するとちゃんとセットされてた。 走らせてみると、結果がreplに出てきちゃったぞ。で、指定したファイルは作成されているものの中身は、からっぽ。

shiroさんに相談すると、ちゃんとファイルポートをクローズした?って助言。

debian:test$ gosh
gosh> (define current-trace-port (open-output-file "LOG.txt"))
current-trace-port
gosh> ,l ./genstub
#?="./genstub":168:(c-name-of cproc)
#?-    "stdlib_eqvP"
 :
#?="./genstub":168:(c-name-of cproc)
#?-    "stdlib_procedure_info"
#t
gosh> (display "HOGEFUGA" current-trace-port)
#<undef>
gosh> (close-port current-trace-port)
#<undef>
gosh> ^D
debian:test$ cat LOG.txt
HOGEFUGAdebian:test$

今度はちゃんとクローズした。HOGEFUGAを自分で書き込んだら、それは書かれていた。

しげしげとdebugger.scmを見ると、current-trace-portが関数扱いになってた。自分的には、変数だと思っていたんで、不思議発見である。先生に聞いたら、current-trace-portは、 current-output-port などと同じパラメータです、との事。

(current-trace-port) と引数なしで呼び出すと現在の値が返り、
(current-trace-port <ポート>) と呼び出すと<ポート>が新しい出力先になります。

と言う物らしい。今まで知りませんでした。

current-trace-port成功

(base) sakae@debian:test$ gosh
gosh> (current-trace-port)
#<oport (standard error output) 0x7ff63354ad80>
gosh> (current-trace-port (open-output-file "LOG.txt"))
#<oport (standard error output) 0x7ff63354ad80>
gosh> (current-trace-port)
#<oport LOG.txt 0x7ff6332590c0>
gosh> ,l ./genstub
#t
gosh> ^d
(base) sakae@debian:test$ tail -2 LOG.txt
#?="./genstub":168:(c-name-of cproc)
#?-    "stdlib_procedure_info"

新しいportを設定すると、古い設定値を(保存用に)返すようになってるのね。とにかく、これで先端に踊り出れた。良かったなあ。

尚、当初は flushが組み込まれていなかったんだけど、オイラーみたいな馬鹿者向けに、追加されてる。ポートをクローズしない為、ファイルに書き出されないって言うケアレスミスを防ぐ為、gauche側で是正策を施したって訳。

昔リナを盛んに布教してたオゴちゃんが言ってたな。タコは大事だ。心して育てよと。馬鹿でも使えるように、馬鹿よけしましょ。確かに真実な面があるな。

Parameter とは何者?

自分で作った説明書(のhtml)を見ると

Parameter: current-trace-port

    デバッグトレース出力に使われる出力ポートを保持するパラメータです。
    初期値はcurrent-error-portの初期値と同じです。

    debug-print機能(デバッグ補助参照)と、 マクロトレース機能
    (マクロ展開をトレースする参照)がこのポートを使っています。

ちゃんと項目が出てきた。小気味いい対応だ。どこかのOS連中も見習えよ。機能追加にはドキュメント更新も含まれますってね。それが徹底してるのはOpenBSD。これを使ってる限り、ぐぐるのお世話になって、各人のノウハウを拾い上げる事は、まずない。

謎の(単に、オイラーが知らないだけ)Prarameterにも当たっておく。いわゆるcurrent-trace-portの上位概念ね。

9.22 gauche.parameter - パラメータ

Module: gauche.parameter

    「パラメータ」は基本的にゼロもしくは一個の引数を取る状態を持つ手続きとみなせます。
    引数が与えられなかった場合、それは内部に保持した値を返します。 一つの引数が与えら
    れた場合、その値が新たなパラメータ内部の値となり、 変更前の値が返されます。 パラメ
    ータは状態を保持する手段として、 単なるグローバル変数に比べていくつかの利点を持っ
    ています。

どんなやつが該当しているのだろう? ブラウザーで説明書をぐぐっても(変な表現だ)いいんだけど、それじゃ猿と見做されそうなので、unixerらしく、

debian:doc$ grep Parameter gauche-refe.texi | grep @def
@deffn {Parameter} default-endian
@deffn {Parameter} current-input-port
@deffnx {Parameter} current-output-port
@deffnx {Parameter} current-error-port
@deffn {Parameter} standard-input-port
  :
@deffn {Parameter} command-line
@deffn {Parameter} log-default-drain
@deffn {Parameter} current-language
@deffnx {Parameter} current-country
@deffnx {Parameter} current-locale-details
  :

ふーん、もっと沢山あるかと思ったら、32個しか無かった。便利な機構だと思うんだけど、インプリメンターの熟考の末の決定なんでしょうね。

今回、つらつらと説明書で語句説明とかを見ていたんだけど、そこに出ていないで、突然使われている専門用語に出くわした。thunk(サンクと言うらしい)。なんだ、サンクスと違うものかってんで、 用語集を引いてみた。

引数を取らない手続きのことを言うそうだ。scheme業界の標準語なの? なんか、今回出て来たパラメータと似てる雰囲気だな。引数と取らないって事、かつ手続って事は、それを使う場合、(hoge)とかってやるんだな。

こんなの意味あるの? 効能を調べてみると、長いコードブロックに名前を付けて、整理しましょって場合に使うようだ。

Function: with-input-from-process command thunk :key ...

    子プロセスで command を実行し、コマンドの標準出力に 接続された現在の入力ポートと
    ともに thunk を呼び出します。

    (with-input-from-process "ls -l *" read-line)

こんな例が載ってた。この例の場合、thunkに相当するのは、既定の手続きread-lineだけど、これを自分で書いた独自関数にしてもいいよって訳。このthunk関数の引数は入力ポートって決まってるので定義する必要は無し。

自分で書いた関数の中で、read-lineして、特定の条件を満たすものだけに何かするなんて場合に便利だ。その何かを別の場所で定義しておけば、コードを読む時の妨げにもならないしね。ただ、どんな関数名にするかは、悩みどこだな。迷ったら、直接thunkの所を(lambda () ...)と、展開してしまうのも手だ。

on lem

嬉しくなって、lem のscheme-slimeから試してみた。動的に補完してくれるようで、current-trace-modeが一発で候補に出て来た。楽でいいわいと思っていたら、

(user)> (gauche-version)
"0.9.9"
(user)> #?= (cdr '(a b c))
(b c)
(user)> (current-trace-port (standard-output-port))
#<oport (standard error output) 0x7fe00e5a2d80>
(user)> (current-trace-port)
#<oport (standard output) 0x7fe00e5a2e40>
(user)> #?= (cdr '(a b c))
(b c)

リーダーマクロって無視される仕様? それとも、stderrへの出力は無視? 強制的に出力を標準ポートに向けても、やはりdebug-printは働かないなあ。

gosh> #?= (cdr '(a b c))
#?="(standard input)":1:(cdr '(a b c))
#?-    (b c)
(b c)

emacsのrun-schemeからのreplは、動くんだけど。

後、開くファイルにサフィックス .scm が無いけど、ファイル末尾に

;; Local variables:
;; mode: scheme
;; end:

が書かれていると、emacsではちゃんとscheme-modeに成るんだけど、lemだとfundamental だなあ。これもlemの仕様かな。些細な特殊事例だからユーザーが気を付けるべし。

でもね、

(define (tasu2 x)
  (+ 2 x))

こんなのを、gauche-schemeの(編集)窓の中で、C-x C-e すると

The variable X is unbound.
Backtrace for: #<SB-THREAD:THREAD "editor" RUNNING {1002CC0D63}>
0: ((LAMBDA ()))
1: (SB-INT:SIMPLE-EVAL-IN-LEXENV (LEM-SCHEME-MODE::DEFINE (LEM-SCHEME-MODE::TASU
2: (EVAL (LEM-SCHEME-MODE::DEFINE (LEM-SCHEME-MODE::TASU2 LEM-SCHEME-MODE::X) (+
3: (LEM-LISP-MODE::SELF-INTERACTIVE-EVAL "(define (tasu2 x)
  (+ 2 x))")
4: (LEM:CALL-COMMAND LEM-LISP-MODE::SELF-LISP-EVAL-LAST-EXPRESSION NIL)
5: (LEM::COMMAND-LOOP)
:

落ちるなあ。これは何とかして欲しいです。切に願っております。 lemはインストールも楽だし、人に勧めるにもうってつけですから。