maximaとか(6)

暫く前の事になるけど、こんなおふれが出てた。『鳥追いのドッカン爆竹は、安眠妨害になりますので、 昼間だけにして。ドッカンの時間間隔も長くしてください。』

現代人は、そこらに居る鳥さんより寝坊だからなあ。日の暮れと共に眠り、日の出と共に起きれば、 無問題と思うぞ。それとも、案山子(かかし)でもあちこちに立てるか。なんて思っていたら、 農業の人が子供達を募って、かかしの作り方を伝授、コンクールが開かれました、なんてのが ニュースになってた。

野に出ると、黄色く実った田には、鳥避けのネットやら、脅かしの為の銀色テープとかが あちこりに張られていた。やっぱり案山子は不作なのね。

三連休で、稲刈りも大分進んでた。やっぱり、大人の休日==稲刈り休み と言うのは、この地方で 昔から成り立ってるようだ。そうそう、稲刈り休みだけじゃなくて、田植え休みでもいいけど。

刈られた稲は、田に大きな物干し竿をわたして、天日干ししてる。いきなり、脱穀して農協の 倉庫へ直行って訳でもなさそうだ。昔からの光景だなあ。

ふと、大きな田だと、ごはん何杯ぐらいになるんだろう? なんて、食欲の秋なんで考えちゃったよ。 百姓学宣言 なんて言う本によると、お茶碗一杯で、3000から4000粒ぐらいとか。稲株で3株に なるとか。

するってえと、田の株数を数えれば、お茶碗換算出来るんだな。1平方メートル当たり、何株 ぐらい植わっているんだろう? 明日、調べてみよっと。それから、田の面積だな。巻尺持って 行って測る訳にもいかないので、何食わぬ顔して、歩幅を数えてくればいいんか。

田の形状が長方形とかじゃ無かったら、ちと面積を求めるのに苦労するな。田の形を多角形に 近似して、後は数値積分すればいいのかな。maximaやってて良かったね。

舞台を移して

前回、sbcl on FreeBSDで、地雷っぽいのに触れた。で、今日は違う大地にも地雷が埋まって いるか検証してみる。

今度の大地は3年ものだかのウブにした。他にもArchLinuxを持っているんだけど、こちらは先端を 走っているんで、そのまま走らせておこうと思うからだ。

余計な事だけど、ArchLinuxは、自分で何とかするって方針のLinuxなんで、やっぱりウブ風味の Archが欲しいって要求があるみたいだ。(面倒な事するの嫌いって人用) ArchBangがそれだ。Latest Linux Kernel 3.0.4-1 って事で、飛ばし ぶりをご賞味あれ。

無闇に飛ばしてるFireFoxはシェアを落としてるみたいだから、余り先走りしすぎるのも実験台 のモルモットみたいで嫌なのかも知れんな。ほんとに消費者の動向は分からんわ。(と、おまえが 言ってもしょうがないだろうに)

話を戻して、ウブにmaximaを入れてみた。maximaだけ欲しかったのにほっておいたら、Tex関係が ごっそりと付属してきたよ。で、毒食わば皿までで、Texmacsも入れてみた。maximaを起動すると

sakae@ubuntu:~$ maxima

Maxima 5.20.1 http://maxima.sourceforge.net
using Lisp GNU Common Lisp (GCL) GCL 2.6.7 (a.k.a. GCL)
Distributed under the GNU Public License. See the file COPYING.
Dedicated to the memory of William Schelter.
The function bug_report() provides bug reporting information.
(%i1)

つう事で、GNU関係者ばかりでした。しょうがない、最新のsbclを入れるかな。作成にやっぱり10分 かかったよ。 sbclは、最低でも、sbclって言うランタイムとsbcl.coreって言う *.lisp を固めたsbcl.coreって のが有れば動く。よって、簡単に、sbcl.coreをrenameしておいて起動したら、エラーで、 ローレベルデバッガーに落ちるんじゃないかと、期待。

sakae@ubuntu:~/app/lib/sbcl$ mv sbcl.core Xsbcl.core
sakae@ubuntu:~/app/lib/sbcl$ ~/app/bin/sbcl
fatal error encountered in SBCL pid 2341(tid 3085104832):
can't find core file at /home/sakae/app/lib/sbcl//sbcl.core

sakae@ubuntu:~/app/lib/sbcl$

結果は残念ながら、落ちませんでした。後は、sbcl.coreを傷付けてって方針があるけど、それでは sbclの開発者の方々を冒涜するみたいで、気分が乗らない。地道に、古いsbclでmaximaを 作って、それを新しいsbclで起動するって事にする。

maximaの作り方

熱い(厚い)pdf本を参照すると、作り方が懇切丁寧に書いてあるんだけど、ソースを展開すると 出てくる説明書も一応見とく。

Maxima can be built in three ways.

(1) Lisp-only build

    Lisp-only build is suitable for systems lacking GNU Autotools,
    e.g. MS Windows systems. Lisp-only build creates a Maxima
    executable image, but it does not create the Maxima texinfo
    documentation, it does not adjust various pathnames and other
    environmental variables in the maxima and xmaxima scripts,
    it does not install Gnuplot, and it does not create an
    installer file (neither RPM or Windows installer).

(2) Win32 build and install

    Win32 build and install is suitable for MS Windows systems
    with GNU Autotools (Mingw or otherwise).

(3) Unix GNU Autotools build and install

    Unix GNU Autotools build and install is suitable for Unix and
    Unix-like systems (e.g. Linux) with GNU Autotools.

Lispが有るなら、それでけで出来まっせとな。unixもどきが入っていないWindowsには最適とな。 後は、GUNの道具達が入ってれば、その道具を使う方法もあるよ。

INSTALL.lispを見ると、いろいろとlispを上げたり下げたりして面倒そうだったので、GNUの道具に 依存する事にした。どんなLispが対応してるかは、

  --enable-clisp               Use clisp
  --enable-cmucl               Use CMUCL
  --enable-cmucl-exec          Create a maxima executable image.
                                No check is made if the version of
                                CMUCL supports executable images
  --enable-scl                 Use SCL
  --enable-sbcl                Use SBCL
  --enable-acl                 Use ACL
  --enable-gcl                 Use GCL
  --enable-openmcl             Use OpenMCL
  --enable-ccl                 Use CCL (Clozure Common Lisp)
  --enable-ecl                 Use ECL

こんな風に列挙されてました。で、私は、勿論 --enable-sbcl して作りましたよ。約3分 ぐらいで出来た。ドキュメントの生成にPerlだとかPythonを使ってたのには、ちょっとびっくり しましたです。

そんなんで、取りあえず起動してみる。

sakae@ubuntu:~$ app/bin/maxima
Maxima 5.25.1 http://maxima.sourceforge.net
using Lisp SBCL 1.0.29.11.debian
Distributed under the GNU Public License. See the file COPYING.
Dedicated to the memory of William Schelter.
The function bug_report() provides bug reporting information.
(%i1)

古いsbcl上で新しいmaximaが動いてます。これで準備完了かな。

実験開始

sakae@ubuntu:~$ PATH=/home/sakae/app/bin:$PATH
sakae@ubuntu:~$ maxima
fatal error encountered in SBCL pid 2632(tid 3085104832):
can't load .core for different runtime, sorry


Welcome to LDB, a low-level debugger for the Lisp runtime environment.
ldb> backtrace
Backtrace:
Segmentation fault
sakae@ubuntu:~$

実験成功! 違うOSでも再現したわい。但しゲロ死体は出来ていなかった。ウブってデフォでは ただ使うだけ仕様に振ってあるのね。

sakae@ubuntu:~$ ulimit -c unlimited
sakae@ubuntu:~$ maxima
fatal error encountered in SBCL pid 2784(tid 3085104832):
can't load .core for different runtime, sorry


Welcome to LDB, a low-level debugger for the Lisp runtime environment.
ldb> ba
Backtrace:
Segmentation fault (コアダンプ)
sakae@ubuntu:~$ gdb sbcl core
GNU gdb (GDB) 7.1-ubuntu
  :
(gdb) bt
#0  stack_pointer_p (fp=0xbfffb358, nframes=100) at backtrace.c:310
#1  x86_call_context (fp=0xbfffb358, nframes=100) at backtrace.c:331
#2  backtrace_from_fp (fp=0xbfffb358, nframes=100) at backtrace.c:540
#3  0x08052a07 in lisp_backtrace (nframes=100) at backtrace.c:586
#4  0x0805a927 in sub_monitor () at monitor.c:499
#5  ldb_monitor () at monitor.c:515
#6  0x08056792 in call_lossage_handler (
    fmt=0x8069b4c "can't load .core for different runtime, sorry\n")
    at interr.c:71
#7  lose (fmt=0x8069b4c "can't load .core for different runtime, sorry\n")
    at interr.c:89
#8  0x08052f5c in load_core_file (
    file=0x808bed8 "/home/sakae/app/lib/maxima/5.25.1/binary-sbcl/maxima.core", file_offset=0) at coreparse.c:361
#9  0x0805d5c3 in main (argc=17, argv=0xbffff724, envp=0xbffff76c)
    at runtime.c:548
(gdb) l
305        * x86 and x86-64.  (But note that false positives would not cause much harm
306        * given the heuristical nature of x86_call_context.) */
307       unsigned long stack_alignment = sizeof(long);
308
309       return (altstack_pointer_p(p)
310               || (p < (void *) arch_os_get_current_thread()->control_stack_end
311                   && (p > (void *) &p || altstack_pointer_p(&p))
312                   && (((unsigned long) p) & (stack_alignment-1)) == 0));
313     }
314
(gdb) print p
$1 = (void *) 0xb7f864e0
(gdb) fr 1
#1  x86_call_context (fp=0xbfffb358, nframes=100) at backtrace.c:331
331       if (!stack_pointer_p(fp))
(gdb) l
326     {
327       void *c_ocfp;
328       void *c_ra;
329       int c_valid_p;
330
331       if (!stack_pointer_p(fp))
332         return 0;
333
334       c_ocfp    = *((void **) fp);
335       c_ra      = *((void **) fp + 1);

これって、フレームポインターとスタックポインターの整合性を見てるんだって所までは分かる んだけど、あの複雑な判定が何やってるかは分からんな。セグフォだから、とんでもない所を 見てるっぽいのは想像出来るけど。。。

ちょいとお遊びを

深追いしようとすると、理解の範囲を超えるっぽいので、もう少し難度の低い事をやります。 どんな風に、エラーをチェックしてるんだろう?

先ほどのgdb案内によれば、チェックしてる所は以下っぽい。(coreparse.c)

        case BUILD_ID_CORE_ENTRY_TYPE_CODE:
            SHOW("BUILD_ID_CORE_ENTRY_TYPE_CODE case");
            {
                unsigned int i;

                FSHOW((stderr, "build_id[]=\"%s\"\n", build_id));
                FSHOW((stderr, "remaining_len = %d\n", remaining_len));
341:            if (remaining_len != strlen((const char *)build_id))
                    goto losing_build_id;
                for (i = 0; i < remaining_len; ++i) {
                    FSHOW((stderr, "ptr[%d] = char = %d, expected=%d\n",
                           i, ptr[i], build_id[i]));
                    if (ptr[i] != build_id[i])
                        goto losing_build_id;
                }
                break;
            losing_build_id:
                   :
                lose("can't load .core for different runtime, sorry\n");
            }

runtimeに埋め込まれてる期待値とcore内にあるbuild番号を照合してるのか。どんな番号かな?

sakae@ubuntu:~$ gdb sbcl
  :
(gdb) b coreparse.c:341
Breakpoint 1 at 0x8052edf: file coreparse.c, line 341.
(gdb) run --core /usr/lib/sbcl/sbcl.core
Starting program: /home/sakae/app/bin/sbcl --core /usr/lib/sbcl/sbcl.core
 :
Breakpoint 1, load_core_file (file=0x808baa0 "/usr/lib/sbcl/sbcl.core",
    file_offset=0) at coreparse.c:341
341                     if (remaining_len != strlen((const char *)build_id))
(gdb) p ptr
$1 = (lispobj *) 0x808d2e8
(gdb) p build_id
$2 = "ubuntu-sakae-2011-09-23-09-45-24"
(gdb) p remaining_len
$3 = 36
(gdb) s
361                     lose("can't load .core for different runtime, sorry\n");

面倒なので、使うコアファイルを、ウブ備え付けのものにしてみた。 どうやら、期待値と長さが違うようです。2段構えのチェックの前段で撥ねられています。 厳重に見てるなあ。感心しますよ。

でも、本当にこんな名前入りのidを使ってチェックしてるのだろうか? それだと、その人の 持ってるランタイムでしか走らない事になっちゃうからなあ。おいらは、バージョン番号ぐらいの 整合性をチェックしてると思ってたよ。もう少し精査してみっかな。

バージョン番号

ここでふと、バージョン番号ってlispの関数から取れるんだろうかと疑問に思った。gosh -v で 出てくるやつね。調べるヒントは無いかな?

しばし瞑想に耽って、maximaに範を求める事にした。build_info()なんてので確か表示されてたな。 ソースから盗んできちゃえ。探してみたら、macsys.lisp に有った。

(defmfun $build_info ()
  (format t (intl:gettext "~%Maxima version: ~a~%") *autoconf-version*)
  (format t (intl:gettext "Maxima build date: ~a:~a ~a/~a/~a~%")
          (third cl-user:*maxima-build-time*)
          (second cl-user:*maxima-build-time*)
          (fifth cl-user:*maxima-build-time*)
          (fourth cl-user:*maxima-build-time*)
          (sixth cl-user:*maxima-build-time*))
  (format t (intl:gettext "Host type: ~a~%") *autoconf-host*)
  (format t (intl:gettext "Lisp implementation type: ~a~%") (lisp-implementation-type))
  (format t (intl:gettext "Lisp implementation version: ~a~%~%") (lisp-implementation-version))  "")

maximaは、Lispの生きた実例です。どんどん技を盗みましょう。で、共通Lispで確認してみる。

CL-USER> (lisp-implementation-type)
"SBCL"
CL-USER> (lisp-implementation-version)
"1.0.29.11.debian"

ウブってdebianから搾取(もとえ、おすそわけ)してるんですかい。思わぬ所でお里が知れて 面白いぞ。そんじゃ、元定義は?と思ったら、ソースが入ってなかった。Linuxって、頼まないと ソースを入れてくれない、不親切なOSだ事。 (例えばこんな具合です。)

まあ、Windowsを乗り越えろを標榜してますから、 それでもいいんでしょうが。しょうがないので、自分で作ったsbclで見ようとすると、、

This is SBCL 1.0.51, an implementation of ANSI Common Lisp.
More information about SBCL is available at <http://www.sbcl.org/>.

SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses.  See the CREDITS and COPYING files in the
distribution for more information.
*
; loading #P"/usr/share/common-lisp/source/slime/swank-loader.lisp"

debugger invoked on a SB-C::INPUT-ERROR-IN-COMPILE-FILE in
      thread #<THREAD "initial thread" RUNNING {AAA9981}>:
  READ failure in COMPILE-FILE:
    SB-INT:SIMPLE-READER-PACKAGE-ERROR at 5151 (line 128, column 45)
      on #<SB-SYS:FD-STREAM for
         "file /usr/share/common-lisp/source/slime/swank-loader.lisp" {AAB2C01}>:
      package "CLC" not found

何か、お気に召さない事が有るみたい。こういうのを調べるのも楽しみの一つだなあ。と、わき道に 逸れるといつになっても終わらないので、srcを直接に覗いてみます。

(in-package "SB!IMPL")

(defun sb!xc:lisp-implementation-type ()
  "SBCL")

(defun sb!xc:lisp-implementation-version ()
  #.(sb-cold:read-from-file "version.lisp-expr"))

version.lisp-exprと言うファイルから読み取ってるとな。多分sbclがコンパイルされる初期の 段階での事だな。それにしても、#. のリーダーマクロは何するものぞ。次々と知りたい事が 出てきて尽きないなあ。

切りがないので、1.0.51って文字が埋め込んであるか、確認して終わりにしよう。

sakae@ubuntu:~/app$ hexdump -C bin/sbcl | fgrep 1.0.51
000568b0  2d 31 2e 30 2e 35 31 2f  73 72 63 2f 72 75 6e 74  |-1.0.51/src/runt|
00056900  61 6b 61 65 2f 73 62 63  6c 2d 31 2e 30 2e 35 31  |akae/sbcl-1.0.51|
000686a0  62 63 6c 2d 31 2e 30 2e  35 31 2f 73 72 63 2f 72  |bcl-1.0.51/src/r|
sakae@ubuntu:~/app$ hexdump -C lib/sbcl/sbcl.core | fgrep 1.0.51
013c9220  a6 00 00 00 18 00 00 00  31 2e 30 2e 35 31 00 00  |........1.0.51..|