chez沼

chez-sys

前回からの続き。rustからchezschemeを動かそうと言う試み。lib.rsに少し追加して、何かやらせようという算段。

#[cfg(test)]
mod tests { ▶︎ Run Tests|Debug
    use super::*;

    fn myadd(x: i64, y: i64) -> i64 {
        unsafe {
            let ti = Stop_level_value(Sstring_to_symbol("+".as_ptr() as *const i8));
            Sfixnum_value(Scall2(ti, Sfixnum(x), Sfixnum(y)))
        }
    }
    #[test]
    fn it_works() { ▶︎ Run Test|Debug
        unsafe {
            Sscheme_init(None);
            Sregister_boot_file("/tmp/t/petite.boot".as_ptr() as *const i8);
            //            Sregister_boot_file("/tmp/t/scheme.boot".as_ptr() as *const i8);
            Sbuild_heap(0 as *const i8, None);
            println!("{}", myadd(123, 456));
        }
    }
}

petite.bootは、抜き出してきて、/tmp/t に置いた。これで走らせると

sakae@pen:/tmp/chez-sys$ cargo t
    Finished test [unoptimized + debuginfo] target(s) in 0.01s
     Running unittests (target/debug/deps/chez_sys-143b01c762533554)

running 1 test
cannot open boot file /tmp/t/petite.boot
S_generic_invoke return
error: test failed, to rerun pass '--lib'

見事に失敗してる。これが動くべきなんだろうけど、いまいち自信が無い。これはもう、一旦rustを離れて、慣れ親しんだC言語でやってみるべきだろう。

chez scheme

chezはたまに使う亊があるけど、単にaptから入れてる、一般ユーザーレべる。どんな構成になってるかなんて、知る由もない。で、周り道だと思いつつ、周りをあたってみた。

sakae@deb:/usr/lib$ tree csv9.5.4/
csv9.5.4/
└── ti3le
    ├── chezscheme.boot -> scheme.boot
    ├── equates.h
    ├── kernel.o
    ├── main.o
    ├── petite.boot
    ├── scheme.boot
    ├── scheme.h
    └── scheme-script.boot -> scheme.boot

ふむ、核心部分だな。なんか、オブジェクトファイルが置いてあるって、中々新鮮。

sakae@deb:/usr/lib/csv9.5.4/ti3le$ nm main.o | grep ' S'
         U Sbuild_heap
         U Scall1
         U Senable_expeditor
         U Sinteger
         U Skernel_version
         U Sregister_boot_file
         U Sretain_static_relocation
         U Sscheme_deinit
         U Sscheme_init
         U Sscheme_program
         U Sscheme_script
         U Sscheme_start
         U Sset_verbose
         U Sstring
         U Sstring_to_symbol
         U Sstring_utf8
         U Stop_level_value

main.oってのは、多分schemeのメインなんだろうね。こいつにライブラリィーを組み込むと、ユーザーが起動するschemeになるんだな。

Debianの場合はschemeの本体が/etc/alternatives/scheme経由で、chezschemeに接続されてた。

sakae@deb:/usr/bin$ ldd chezscheme
        linux-gate.so.1 (0xb7f0a000)
        libm.so.6 => /lib/i386-linux-gnu/libm.so.6 (0xb7b37000)
        libdl.so.2 => /lib/i386-linux-gnu/libdl.so.2 (0xb7b31000)
        libtinfo.so.6 => /lib/i386-linux-gnu/libtinfo.so.6 (0xb7b08000)
        libz.so.1 => /lib/i386-linux-gnu/libz.so.1 (0xb7aeb000)
        liblz4.so.1 => /lib/i386-linux-gnu/liblz4.so.1 (0xb7ac7000)
        libpthread.so.0 => /lib/i386-linux-gnu/libpthread.so.0 (0xb7aa5000)
        libuuid.so.1 => /lib/i386-linux-gnu/libuuid.so.1 (0xb7a9b000)
        libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb78b2000)
        /lib/ld-linux.so.2 (0xb7f0c000)

核心部分にあるkernel.oがschemeの機能を搭載してるに違いない。

sakae@deb:/usr/lib/csv9.5.4/ti3le$ nm kernel.o | grep Sscheme_
00034420 T Sscheme_deinit
000338b0 T Sscheme_init
000343c0 T Sscheme_program
00034390 T Sscheme_script
00034200 T Sscheme_start

どうやらビンゴだな。

参考に、chezのファイルの役割を解説したものを見付けた。 Welcome to the ChezScheme wiki! see Runtime C側をRuntimeって表現してるのが、目から鱗ですよ。

at Debian 32bit

手慰めで、世界で一番簡単なchezの呼出をやってみる。舞台は、debian 32bit

#include "scheme.h"
#include <stdio.h>

double myadd(double x, double y) {
    ptr times = Stop_level_value(Sstring_to_symbol("+"));
    return Sflonum_value(Scall2(times, Sflonum(x), Sflonum(y)));
}

int main(){
  Sscheme_init(NULL);
  Sregister_boot_file("./petite.boot");
  Sregister_boot_file("./scheme.boot");
  Sbuild_heap(0, 0);
  printf("%f\n", myadd(1.111, 2.222));
}

実験コードは、浮動少数点の足し算。これをkernel.oと共にコンパイルして、chezの機能を使ってみようという作戦。

@deb:/tmp/t$ cc hoge.c kernel.o -lm -ldl -ltinfo -lz -lpthread -luuid  -llz4
/usr/bin/ld: cannot find -llz4
collect2: error: ld returned 1 exit status

が、あろう亊か、変なエラーで引掛った。悩んでいてもしょうがないので、別環境でやってみる。

at Debian 64bit

rustのサンプル chez-sys/build.rsの例に合わせてコンパイル・インストールすると

sakae@pen:/usr/lib/csv9.5.6/a6le$ ls
libkernel.a  libz.a  petite.boot  scheme.boot  scheme-script.boot
liblz4.a     main.o  revision     scheme.h

こんな風になったので、必要な物を取出して/tmp/tに配置。libkernel.aは、リナスに怒られそうなので、libchez.aに改名してる。

sakae@pen:/tmp/t$ cc hoge.c -L/tmp/t -lchez -lz -lm -llz4 -ldl -luuid
sakae@pen:/tmp/t$ ./a.out
3.333000

-ldl,-lm,-luuidとかの必要そうなのは、/usr/bin/schemeをlddで成分調査して入れ込んだ。

どうやら動いてくれたな。

蛇足になるけど、ライブラリィーのリンクを忘れると、勿論下記のようなエラーになる。

sakae@pen:/tmp/t$ cc hoge.c -L/tmp/t -lchez -lz -lm -llz4 -ldl
/usr/bin/ld: /tmp/t/libchez.a(stats.o): in function `S_unique_id':
stats.c:(.text+0x1c): undefined rehference to `uuid_generate'
collect2: error: ld returned 1 exit status

この例だと、 S_unique_id の関数で使ってるやつが名前解決出来無いとな。一つぐらいのエラーなら追い掛ける元気も有るけど、バーと出て来るとうんざりするね。手本に習うのが一番だ。

at FreeBSD 32bit

FreeBSDにもportsで用意されてるので、試してみた。

[sakae@fb /tmp/ti3fb]$ ldd /usr/local/bin/chez-scheme
/usr/local/bin/chez-scheme:
        libm.so.5 => /lib/libm.so.5 (0x204bd000)
        libncursesw.so.9 => /lib/libncursesw.so.9 (0x204ef000)
        libthr.so.3 => /lib/libthr.so.3 (0x20555000)
        libossp-uuid.so.16 => /usr/local/lib/libossp-uuid.so.16 (0x2057e000)
        libuuid.so.1 => /usr/local/lib/libuuid.so.1 (0x2058d000)
        libc.so.7 => /lib/libc.so.7 (0x20594000)

核心部分は、/usr/local/lib/csv9.5.4/ti3fbにあるんで、丸ごと/tmpにコピー。コンパイル時に長々PATHを入力するのが面倒なので、単なる手抜きです。

[sakae@fb /tmp/ti3fb]$ cc hoge.c kernel.o -lm -lncursesw -lthr -lossp-uuid -luuid
ld: error: unable to find library -lossp-uuid
ld: error: unable to find library -luuid
cc: error: linker command failed with exit code 1 (use -v to see invocation)
[sakae@fb /tmp/ti3fb]$ cc hoge.c kernel.o -L/usr/local/lib -lm -lncursesw -lthr -lossp-uuid -luuid
[sakae@fb /tmp/ti3fb]$ ./a.out
3.333000

まあ、動いたな。

FreeBSDとくれば次はOpenBSDかと思うんだけど、portsには無い。Ciscoの支援を嫌って親分が許しませんなのかな。ライセンスは、APACHE20 だから、目くじら立てる程の亊もないな。

=> Attempting to fetch http://distfiles.pirateparty.in/ashish/chez-scheme-boot-ta6fb-9.5.6.tar.xz

コンパイルに必要なやつは、こういう所からDLしてる。って、何よそれ。

source tour

折角なので、ソースと対面しとく。

BUILDING

上であげたOpenBSDはサポートしていないのか?

On OpenBSD, Chez Scheme must be built and installed on a filesystem
that is mounted with wxallowed.

こんな注意書きがあるって亊は、過去にはサポートされてたって亊だ。更に更新記録であるLOGをみると、

9.4.1 changes:
   :
- commented out one of the thread mats that consistently causes
  indefinite delays under Windows and OpenBSD due to starvation.
    thread.ms

て亊で、痕跡はある。gitからheadを取ってきて、tagを確認するとv9.4ってのが存在。switchしてみたけど、OpenBSDとかは現れず。残念。

boot

[sakae@fb /tmp/csv9.5.6]$ ls boot
a6le/           arm32le/        i3osx/          ta6osx/         ti3osx/
a6nt/           i3le/           ta6le/          ti3le/
a6osx/          i3nt/           ta6nt/          ti3nt/

現在、公式にサポートしてるのは、これだけ。頭についてるtは、スレッド版。i3とかa6は、インテルさんの石の区別。その後ろにあるleはlinux。osx,ntは言わずと知れたやつ。

configure

その証拠は、手書きされたconfigureにも残っている。どんな石とOSがサポートされてたかは、このファイルを開いてみればよい。面倒なら、これでもOK

[sakae@fb /tmp/csv9.5.6]$ ls s/M*
s/Mf-a6fb       s/Mf-arm32le    s/Mf-i3ob       s/Mf-ta6nb      s/Mf-ti3nb
s/Mf-a6le       s/Mf-base       s/Mf-i3osx      s/Mf-ta6nt      s/Mf-ti3nt
s/Mf-a6nb       s/Mf-cross      s/Mf-i3qnx      s/Mf-ta6ob      s/Mf-ti3ob
  :

configureできっちりMakefileを作成しなかった、つけがこういう所に現れている。それぞれが、個別のシステムのMakefileになる。

Mf-baseは、共通なMakefileだ。Schemeなソースをどんな風にコンパイルするとかの設定とか、実際のコンパイルはS式になってるとか、見所満載ですよ。

from make log

Makefileをチマチマ見ていくよりも、実行来歴を見るのて手っ取り速い。 ログは、

make |& tee LOG-make

とかやって採取するのがお手軽だ。

ar rc ../boot/a6le/libkernel.a statics.o segment.o alloc.o symbol.o intern.o gc\
wrapper.o gc-011.o gc-ocd.o gc-oce.o number.o schsig.o io.o new-io.o print.o fa\
sl.o stats.o foreign.o prim.o prim5.o flushcache.o schlib.o thread.o expeditor.\
o scheme.o compress-io.o i3le.o
gcc  -m64 -msse2 -Wpointer-arith -Wall -Wextra -Werror -Wno-implicit-fallthroug\
h -O2  -c -DX86_64 -I../boot/a6le -I../zlib -I../lz4/lib main.c
cp -p main.o ../boot/a6le/main.o
gcc  -m64 -msse2 -Wpointer-arith -Wall -Wextra -Werror -Wno-implicit-fallthroug\
h -O2  -rdynamic -o ../bin/a6le/scheme ../boot/a6le/main.o ../boot/a6le/libkern\
el.a -lm -ldl  -lrt -luuid ../zlib/libz.a ../lz4/lib/liblz4.a

Runtime関係のコンパイル

             '(delete-file (string-append (path-root "../boot/a6le/scheme.boot"\
) ".covin"))'\
             '(apply #%$make-boot-file "../boot/a6le/scheme.boot" (quote a6le) \
(quote ("petite"))'\
             '  (map symbol->string (quote (cpnanopass.a6le compile.a6le cback.\
a6le))))'\
             '(when #f (profile-dump-html))'\
             '(when #f (profile-dump-data "source.pd"))'\
             '(when #f (profile-dump-data "block.pd"))'\
             > script.all

こちらは、scheme.bootの作りかただ。

cannot find -llz4

冒頭の方で取り上げたdebian 32bit のリンク問題、悔しいのでネットで調べてみた。sudo ldconfig してキャッシュを更新してみたらってのが出でた。もう一つ、リンクを作り直したらってのも有った。ldconfigは効果がなかったので、2番目の方法。

sakae@deb:/lib/i386-linux-gnu$ ls -l liblz4*
lrwxrwxrwx 1 root root     15 May  5  2021 liblz4.so.1 -> liblz4.so.1.9.3
-rw-r--r-- 1 root root 140828 May  5  2021 liblz4.so.1.9.3
sakae@deb:/lib/i386-linux-gnu$ sudo ln -s liblz4.so.1.9.3 liblz4.so
sakae@deb:/lib/i386-linux-gnu$ sudo ldconfig

ちゃんとリンクが張られていた。でも、libzの方に習って、しつこくリンクを追加。おまけでldconfigも実行。

sakae@deb:/tmp/t$ cc hoge.c kernel.o -lm -ldl -ltinfo -lz -lpthread -luuid  -llz4
sakae@deb:/tmp/t$ ./a.out
3.333000
sakae@deb:/tmp/t$ ldd ./a.out
        linux-gate.so.1 (0xb7eda000)
        libm.so.6 => /lib/i386-linux-gnu/libm.so.6 (0xb7b0c000)
        libdl.so.2 => /lib/i386-linux-gnu/libdl.so.2 (0xb7b06000)
        libtinfo.so.6 => /lib/i386-linux-gnu/libtinfo.so.6 (0xb7add000)
        libz.so.1 => /lib/i386-linux-gnu/libz.so.1 (0xb7ac0000)
        libpthread.so.0 => /lib/i386-linux-gnu/libpthread.so.0 (0xb7a9e000)
        libuuid.so.1 => /lib/i386-linux-gnu/libuuid.so.1 (0xb7a94000)
        liblz4.so.1 => /lib/i386-linux-gnu/liblz4.so.1 (0xb7a70000)
        libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7887000)
        /lib/ld-linux.so.2 (0xb7edc000)

何故か動いた。どうもリナは挙動不審な部分があるな。余り深入りしないで、そっとしておこう。

single binary

petite等は、複数のファイルから構成されてる。少くともRuntimeに必要なpetiteと、Schemeのソースをコンパイルしたpetite.bootが必要。

sakae@pen:/tmp/csv9.5.6/s$ petite --verbose
trying /usr/lib/csv9.5.6/a6le/petite.boot...opened
version and machine type check
Petite Chez Scheme Version 9.5.6
Copyright 1984-2021 Cisco Systems, Inc.
  :
sakae@pen:/tmp/csv9.5.6/s$ scheme --verbose
trying /usr/lib/csv9.5.6/a6le/scheme.boot...opened
version and machine type check
trying /usr/lib/csv9.5.6/a6le/petite.boot...opened
version and machine type check
Chez Scheme Version 9.5.6

ファイルが複数になってると扱いにくい。gaucheは多数のユーザー要求で、ひとつのファイルにまとめてしまう亊が出来るようになった。これが世界の潮流と思っていたら、前回、一つのファイルにpetiteをまとめてしまう技を、中国の方が発表されてた。

最初に、make.txtに習ってmain.cをコンパイル。foo.ssは簡易なrepl。この2つをsession.txtに習って、融合させるとな。

single-chez.tgz

chez-sys lib -> bin but …

chez-sysのlib.rsにあるtestを走らせていたけど、ひょっとしたらbinに切り換えたら動くようにならないか。淡い期待を込めて、ちょっとソースを改造。 Cargo.toml

#[lib]
#name = "chez_sys"
#path = "src/lib.rs"

libを無効にするとbinになるんだろうな。

src/main.rs

mod bindings;
pub use bindings::*;

fn myadd(x: i64, y: i64) -> i64 {
    unsafe {
        let ti = Stop_level_value(Sstring_to_symbol("+".as_ptr() as *const i8));
        Sfixnum_value(Scall2(ti, Sfixnum(x), Sfixnum(y)))
    }
}

fn main() {
    unsafe {
        Sscheme_init(None);
        Sregister_boot_file("/tmp/t/petite.boot".as_ptr() as *const i8);
        Sregister_boot_file("/tmp/t/scheme.boot".as_ptr() as *const i8);
        Sbuild_heap(0 as *const i8, None);
        println!("{}", myadd(123, 456));
    }
}

lib.rsの名前をmain.rsに変更しつつ、体裁をbinを作るようにした。

sakae@pen:/tmp/chez-sys$ cargo r
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/chez-sys`
cannot open boot file /tmp/t/petite.boot/tmp/t/scheme.boot
S_generic_invoke return

やっぱり、エラーだ。何か特有の処理が必要なんだろうか?

rust 本、2冊追加

コンセプトから理解するRust

なかなかよさげ。オイラーみたいに野生の感を頼りにしてきた人が、まとめで読む本かな

手を動かして考えればよくわかる高効率言語 Rust 書きかた・作りかた

誰でも知ってるPythonからrustに乗り換えて自慢する本。みんなrustなんて知らないからrust語をPython語に翻訳してみせて、ドヤ顔するのにうってつけ。ざっと見、面白そうな話題を扱っているな。波形合成なんて面白そう。


This year's Index

Home