Lisp/Scheme and OpenBSD 6.1

いつもお世話になってる、MobaXterm なんだけど、ふとHelpを見たら、新バージョンの 確認メニューが有った。アクセスしてみると、新しいのが出てた。据え置き版を 取ってきて入れた。(一度目のインストールは失敗、二度目に成功)

前の版のやつは、すっかり消してしまっているので、良く使うmakeをインストール。で、最中に 何とかファイルが無いとか言ってたけど、インストール完了。本当に動くか、確認。

[atom] ➤ make -v
~/DOCUME~1/MOBAXT~1/slash/bin/make.exe: error while loading shared libraries: cygguile-17.dll: cannot open shared object file: No such file or directory

無いファイルをどこからか落としてきてもいいんだけど、やばそうなサイトばかり候補に出て くるので、止めた。makeは大した事に使っていないので、代わりのbatでも、考えて みるかな。 と思って、 バッチファイルの基本的な使い方なんてのを見たけど、余りに貧弱過ぎる。 Windowsで喜んでバッチを書く人は、真正なMに違いない。オイラーは、虐められて喜ぶような 人ではないので、unix流の shellコマンドを書こう。

cd C:/mine/piki
case $1 in
aa)
        ./piki template.html aa.piki > aa.html ;;
 :
ee)
        ./piki template.html ee.piki > ee.html ;;
*)
        ls -l [a-e]*.html ;;
esac

今まで使っていたMakefileをちょいと改造しただけ。これで動いているって事は、makeらしい 働きをさっぱり、させていなかったって事だな。引数をファイル名に置き換える方法を取れば もっとすっきりするけど、それは危険と隣合わせなので止めておいた。

Lisp/Scheme

64Bitマシンになってから、カッコまみれになっていない気がするので、それっぽい所を 見てたんだ。そしたら、CLで機械学習をやってる方に出会った。結構かっこよいグラフを 表示されてたので、どうされてるかと思ったら、

Common LispからGnuplotでグラフ表示するライブラリを作った

Gnuplotを呼ぶそうです。

(ql:quickload :clgplot)
(clgp:plot '(3 1 2 3 2 4))

こんなんで、グラフが書けるって楽すぎ。パラメータが色々あるけど、eldocが先導してくれる ので、簡単に思い出せるとの事。そんなのどういう設定すれば良い?

emacs for Lisper

こちらにヒントが有った。久しぶりに Steel Bank Common Lispslime を入れてみたぞ。

そして、ラケットの設定も出てた。そうか、drracketは起動に 時間がかかるんだよな。入れてみるか。Racket

binの下に色々入ってるけど、CUI中心の人はracketを起動するだけでよいみたい。 そして、ちょっと図形とか出したい時は、下記のようにディレクティブを設定するとな。

[debian tmp]$ cat aaa.rkt
#lang slideshow

(rectangle 10 20)

scheme-complete

schemeでコードを書こうとすると、資料豊富なgaucheが良さそう。補完が強く効いて欲しいな。 そんな時は、 scheme-complete がよさそう。最近忘れたように手が入っているからね。入れてみた。試してみた。

(define (a x)
  (string-reTAB  ;; => Can't find completion for "string-re" on  *Messages* buf

あれ、候補が無いと言ってるぞ。世界中の好き者から愛されていて文句が出てない所をみると、 オイラー側の問題だろうね。何かヒントが無いかな? ぐぐる先生に聞いてみたけど、皆無。 自分で何とか、解決策を見つけ出すんだ!

で思ったね。裏側ではelispが動いてるじゃん。これって、schemeから地続きなLispの世界。 Lispの虫取りはどうやるってのに帰結するだろう。debuggerかな? その前にtraceかな?

elispでtraceはどうやるか調べたよ。そしたら、M-x trace-function して、traceしたい 関数を登録するとな。scheme-complate.elを眺めて、人間traceしてみた。呼ばれそうな 関数を登録した。下記は、その結果。(関数を登録しといて、普通に補完してみる)

1 -> (scheme-complete-or-indent nil)
| 2 -> (scheme-smart-complete nil)
| | 3 -> (scheme-do-completion "string-re" (("import") ("a")))
| | | 4 -> (try-completion "string-re" (("import") ("a")) nil)
| | | 4 <- try-completion: nil
| | 3 <- scheme-do-completion: nil
| 2 <- scheme-smart-complete: nil
1 <- scheme-complete-or-indent: nil

scheme-do-complation に候補として出てるのは何だ? この文脈での候補はこれしか 無いと言う事か。と言う事は、C語で言うヘッダーファイルを元に、補完候補を出しているに 違いない。

(import (scheme base))

(define (a x)
  (string-TAB
===================================================================
In this buffer, type RET to select the completion near point.

Possible completions are:
string->list       string->number     string->symbol     string->utf8
string->vector     string-append      string-copy        string-copy!
string-fill!       string-for-each    string-length      string-map
string-ref         string-set!

こんな風に、候補が出てきた。さすがプロが使う道具だなあ。

なお、下記はgauche用の設定。ウナギのたれみたいに、秘伝の設定が混じっています。 (infoを引くやつ)

;; gauche smart-complete
(setq scheme-program-name "gosh -i -r7")
(autoload 'scheme-smart-complete "scheme-complete" nil t)
(eval-after-load 'scheme
  '(define-key scheme-mode-map "\t" 'scheme-complete-or-indent))

(autoload 'scheme-get-current-symbol-info "scheme-complete" nil t)
 (add-hook 'scheme-mode-hook
   (lambda ()
     (make-local-variable 'eldoc-documentation-function)
     (setq eldoc-documentation-function 'scheme-get-current-symbol-info)
     (eldoc-mode)))
(setq lisp-indent-function 'scheme-smart-indent-function)

;; info lookup
(define-key global-map "\C-c\C-i" 'info-lookup-symbol)
(eval-after-load "info-look"
  '(progn
     (info-lookup-add-help
      :topic 'symbol
      :mode 'scheme-mode
      :regexp "[^()`',\"\t\n]+"
      :ignore-case t
      :doc-spec '(("(gauche-refj.info)Index - 手続きと構文索引" nil
                   "^ -+ [^:]+: *" "[\n ]")
                  ("(gauche-refj.info)Index - モジュール索引" nil
                   "^ -+ [^:]+: *" "[\n ]")
                  ("(gauche-refj.info)Index - クラス索引" nil
                   "^ -+ [^:]+: *" "[\n ]")
                  ("(gauche-refj.info)Index - 変数索引" nil
                   "^ -+ [^:]+: *" "[\n ]"))
      :parse-rule "[^()`',\" \t\n]+"
      :other-modes nil)

     (info-lookup-add-help
      :mode 'inferior-scheme-mode
      :other-modes '(scheme-mode))
))

そして、サンプル。折角なのでr7rsとやらを使ってます。上の設定でも、goshを起動する時に、 r7rs用のreplが回るようにしてます。そうしておかないと、定義した手続きがrepl上から見えません。これも、shiroさんがきちんと書いてくれた取説のおかげです。記して感謝します。

こういうの全部英語のマニュアルから読み取れじゃ、荷が重すぎますよ。

[fb11: tmp]$ cat aa.scm
(import (scheme base) (scheme write))
(import (srfi 1))

(display "Hello, world!\n")

(define (foo x)
  (number->string x))

(foo 1234)
(display (iota 10))

下記は、emacsのgosh-bufferの結果。これで土台が出来たな。

gosh[r7rs.user]> (load "./aa")
Hello, world!
(0 1 2 3 4 5 6 7 8 9)#t

OpenBSD on CentOS

速いCUPの恩恵確認に、昔やったOpenBSD 探検 を、再度やってみます。

なんでも、qemu-kvm が、良いらしいので、CentOS上です。qemu-kvmを入れると、qemu-imgも 付属で付いてきましたよ。(armとかの石をやる時は、えっちらおっちらと、qemuを自前で、 コンパイルするんだろうね。あれは、付属品が沢山必要で面倒なんだよな。)

[cent tmp]$ qemu-img create -f qcow2 disk 1G
Formatting 'disk', fmt=qcow2 size=1073741824 encryption=off cluster_size=65536 lazy_refcounts=off

して、小さいdiskを作成。qemu-kvmは、昔有った、qemu-system-x86_64の代替品らしい。 裸で使う物ではないそうで、変な所に置いてある。

まずは、インストール。

[cent tmp]$  /usr/libexec/qemu-kvm  -m 256M -net nic -net user -cdrom install61.iso disk
VNC server running on `::1:5900'

普通なら、新たなターミナルが開いて、起動画面が流れてくるはずなんだけど、そういうのは 無し。VNCで眺めるようだ。しかも、IPv6のアドレスを提示してきたぞ。じわじわとIPv6化が 進んでいるんでしょうかね。

[cent tmp]$ sudo yum install tigervnc
[cent tmp]$ vncviewer localhost:5900

TigerVNC Viewer 64-bit v1.3.1 (20161116)
Built on Nov 16 2016 at 13:37:43
Copyright (C) 1999-2011 TigerVNC Team and many others (see README.txt)
See http://www.tigervnc.org for information on TigerVNC.
  :

慌てて、一番簡単そうなvnc-clientを入れ、IPv4で接続。その画面から、OpenBSDを インストールしましたよ。

そして、起動スクリプトを作成。ここに 手回しよく、-sを混ぜておいて、何時でもとgdbが使えるようにしておきました。

[cent ob61]$ cat boot
/usr/libexec/qemu-kvm  -m 256M -net nic -net user -s \
  -redir tcp:2022::22 disk

Cent側から、OpenBSDに乗り入れてみた。

[cent tmp]$ ssh -p 2022 localhost
sakae@localhost's password:
$ uname -a
OpenBSD ob61.my.domain 6.1 GENERIC#19 amd64
$ df -h
Filesystem     Size    Used   Avail Capacity  Mounted on
/dev/wd0a      991M    395M    546M    42%    /

要らないプロセスを止める設定。

[ob: ~]$ cat /etc/rc.conf.local
smtpd_flags=NO
sndiod_flags=NO
ntpd_flags=NO
pflogd_flags=NO

gdbにかけられるようにカーネルをコンパイル

# cd /usr/src/sys/arch/amd64/conf
# cp GENERIC DEBUG
# vi DEBUG
makeoptions DEBUG="-g"      ## <-- ADD this line
# config DEBUG
# cd ../compile/DEBUG
# make depend
# COPTS="-O0" make
text    data    bss     dec     hex
12193124        288360  671744  13153228        c8b3cc
mv bsd bsd.gdb
strip -S -o bsd bsd.gdb
    2m32.98s real     1m40.25s user     0m34.57s system

随分速いな。これ、qemu-kvmの恩恵かな? 起動も38秒ぐらいだったから、待ち時間としては ぎりぎりの許容範囲だな。

仮想のPC側に出来た、bsd.gdbをCentOSに持ってきます。そしてそれを、~/ob61/sys/arch/amd64/compile/DEBUG/ の中に鎮座させました。(CentOS側にも、OpenBSDのソースツリーを展開し、その中にDEBUG-dirを作成しときます)

いよいよ、gdbの試運転。先にOpenBSDを起動しておきます。(38秒の忍耐) 次に、CentOS側のDEBUG/の下で、gdb bsd.gdbして、gdbを起動。target remore :1234 して、 OpenBSDにアタッチします。

で、問題発生。該当ソースが見つからんと文句を垂れてきましたよ。どうも、ソースの在処は、 絶対PATHになってて、OpenBSD側のソースツリーそのものの、/usr/src/sys/amd64/... とかに なってました。

これはもう、その場所をCentOSでも用意するしかないかな。 /home/sakae/ob61/sys の、sys-dirを、強引に、/usr/src/の下に移動しましたよ。 (/usr/src/の下には、先客がいましたけど、sysは幸いな事に空いてました。)

でも、私事のために、/usr/srcにツリーを置くのは、なんとなく美意識に反する。 コンパイルも速い事なので、OpenBSD側のソースツリーの置き場所を、CentOS側と同一に しておこう。そして再コンパイル。再び、bsd.gdbをCentOS側に持ってくる。

ああ、再コンパイルに際して、いらないUSBの検出をしないように、コントローラの類を 取り除いておいた。そうでないと、

Apr 28 15:15:34 ob61 /bsd: iic0 at piixpm0
Apr 28 15:15:34 ob61 /bsd: iic0: addr 0x18 00=00 01=00 02=00 03=00 04=00 05=00 06=00 07=00 08=00 words 00=0000 01=0000 02=0000 03=0000 04=0000 05=0000 06=0000 07=0000
 :

こんなのをずっと見せられるからね。

[cent ~]$ strings ob61/sys/arch/amd64/compile/DEBUG/bsd.gdb | grep /home/sakae
    sakae@ob61.hoge.net:/home/sakae/ob61/sys/arch/amd64/compile/DEBUG
/home/sakae/ob61/sys/dev/ic/vga.c
  :
/home/sakae/ob61/sys/arch/amd64/amd64/acpi_wakecode.S
/home/sakae/ob61/sys/arch/amd64/amd64/vmm_support.S

こちらは、ソースツリーを変更した後、カーネルを作った時の埋め込み状況。ちゃんと出目を 記憶してるな。今回はツリーの場所を変えちゃったけど、gdbでツリーの探索場所を変更 出来たはず。

ソースが存在するディレクトリの指定を見ると、ファイル名しか埋め込んでないとなってるけど、OpenBSDのkernelは、 特別仕様なのかな?

OpenBSD 6.0で、qemu-systemo-x86_64 というアクセラレーションが利かない趣味れーたを 使って、昔作ったやつを起動したら、promptが出てくるまで、72秒かかっていた。 やっぱり、qemu-kvmだと速いな。

これから、探検してくけど、実施は/tmp(と言うRAMDISK)に置いたdisk上でやろう。これなら、しくじってパニクっても、元からコピーしてくれば簡単に初期状態に戻りますからね。 特製スナップショットみたいなものだな。

そして、こんな資料を見つけた。後で見て桶。

OpenBSD Kernel Internals

Debugging Kernel Problems