vinix
Table of Contents
where filter
前回やった配列関連のメソッドだけど、どんな風に実装されてるの? 興味本位で 確認してみたい。遡上に載せるのは、簡単なコード。
sakae@lu:t$ cat mytest.v fn main(){ mylist := [1,2,3,4,5] myfil := mylist.filter(it % 2 == 1) println(myfil) }
v help build-c したら、おあつらえなオプションが有ったので使ってみた。
sakae@lu:t$ v -dump-c-flags - -g mytest.v -fwrapv -g -o "/tmp/t/mytest" -D GC_THREADS=1 -D GC_BUILTIN_ATOMIC=1 -I "/var/my/srcs/v/thirdparty/libgc/include" "/tmp/v_1000/mytest.01JPH8ZN2QW4A0AFVZYN2T09CP.tmp.c" -std=gnu99 -D_DEFAULT_SOURCE -bt25 -rdynamic "/var/my/srcs/v/thirdparty/tcc/lib/libgc.a" -ldl -lpthread
知らないのが出てきたんで、即確認。
-bt N Display N callers in stack traces. This is useful with -g or -b.
Tiny C Compiler Reference Documentation
sakae@lu:t$ wc /tmp/v_1000/mytest.01JPH8ZN2QW4A0AFVZYN2T09CP.tmp.c 11704 30752 417027 /tmp/v_1000/mytest.01JPH8ZN2QW4A0AFVZYN2T09CP.tmp.c
数行なコードが1万行を越える行数に展開されるって、驚くポイントですよ。
#line 1 "../../../../../../tmp/t/mytest.v" void main__main(void) { #line 2 "../../../../../../tmp/t/mytest.v" Array_int mylist = new_array_from_c_array_noscan(5, 5, sizeof(int), _MOV((int[5]){1, 2, 3, 4, 5})); Array_int _t1 = {0}; Array_int _t1_orig = mylist; int _t1_len = _t1_orig.len; _t1 = __new_array_noscan(0, _t1_len, sizeof(int)); for (int _t2 = 0; _t2 < _t1_len; ++_t2) { int it = ((int*) _t1_orig.data)[_t2]; if ((int)(it % 2) == 1) { array_push_noscan((array*)&_t1, &it); } } #line 3 "../../../../../../tmp/t/mytest.v" Array_int myfil =_t1; #line 4 "../../../../../../tmp/t/mytest.v" println(Array_int_str(myfil)); }
デバッグに便利な様に行番号を付いてる。親切ですネェ。で、元コードに有った filterは影を潜めてすっかり解けてしまっているな。forで配列をスキャンしてるのは 読み取れるけど。まあ、配列に寄生して何かやるってのがメソッドの得意技だから、 自然な成行ではあるのですが。。
このあたり、純粋オブジェクト指向のrubyでは、どうなっているんだろう? 名著 RHG(Ruby Hacking Guide)を所有してる方の解説をキボンヌ。
map
今度はmapで確認。プロダクト版ね。
sakae@lu:t$ v -dump-c-flags - -prod mytest.v -fwrapv -O3 -flto -DNDEBUG "/home/sakae/.vmodules/.cache/2f/2f684be88af0f9e272b6028424eca5bd.module.builtin.o" -o '/home/sakae/t/mytest' -D GC_THREADS=1 -D GC_BUILTIN_ATOMIC=1 -I "/var/my/srcs/v/thirdparty/libgc/include" "/tmp/v_1000/mytest.01JPJZFPVP8G486HZGYR2KF5DV.tmp.c" -std=gnu99 -D_DEFAULT_SOURCE -ldl -lpthread -lm
残念ながらC語のソースは直ぐに削除されちゃって閲覧不能だった。しょうがないので -gを 付けて永続化?したよ。
#line 3 "../../../../../../home/sakae/t/mytest.v" Array_int mylist = new_array_from_c_array_noscan(4, 4, sizeof(int), _MO\ V((int[4]){2, 3, 4, 5})); Array_string _t1 = {0}; Array_int _t1_orig = mylist; int _t1_len = _t1_orig.len; _t1 = __new_array(0, _t1_len, sizeof(string)); for (int _t3 = 0; _t3 < _t1_len; ++_t3) { int it = ((int*) _t1_orig.data)[_t3]; string _t2 = f64_str(math__sqrt(it)); array_push((array*)&_t1, &_t2); } #line 4 "../../../../../../home/sakae/t/mytest.v" Array_string myfil =_t1;
こちらもmapは影も形も消え失せている。素直にforが有って、粛々とmylist.map(math.sqrt(it).str()) の結果を矯め込んでいる。一応、 実行結果をば。
sakae@lu:t$ ./mytest ['1.4142135623730951', '1.7320508075688772', '2.0', '2.23606797749979']
ケチな人には、たまにはルート3してよ(ひとなみに、おごれや)と言ってやりたいぞ。 今の人は、こういう語呂合わせで数値を覚えるって事しないのかな。
新人にお小遣いをあげて、どや良い先輩だろうとにんまりしてたら、野党やら身内 からも顰蹙を買った首相がいた(まだいるな)。TPOを弁えて、鳥貴族あたりで新人 歓迎のコンパでもやっとけば良かったのに。それってパワハラ兼アルハラと言われ かねないか。どっちにころんでも、大変だ脳。おつむが更にツルツルになりますよ。
complex
配列のメソッドは組み込みだったので、vlibになってる、それを見て億。例にする のは、前回やった複素数ね。
void main__main(void) { #line 3 "../../../../../../tmp/t/mytest.v" math__complex__Complex z = math__complex__complex(3, 4); #line 4 "../../../../../../tmp/t/mytest.v" f64 myth = math__complex__Complex_angle(z); #line 5 "../../../../../../tmp/t/mytest.v" f64 myps = math__complex__Complex_abs(z);
インライン展開せずに、普通の関数呼出になってる。関数名が鬼のように長いな。 absを追跡してみる。
#line 30 "../../../../../../var/my/srcs/v/vlib/math/complex/complex.v" f64 math__complex__Complex_abs(math__complex__Complex c) { #line 31 "../../../../../../var/my/srcs/v/vlib/math/complex/complex.v" return math__hypot(c.re, c.im); }
これの元ネタは
pub fn (c Complex) abs() f64 { return math.hypot(c.re, c.im) }
だったから、機械的な置き換えで済むんだな。
builtin
前回のm8pをOpenBSDのvlang(V 0.4.5)で確認したら下記の様に見事にpanic
vm$ cat vmware | ./m8p ================ V panic ================ module: builtin function: tos() message: tos(): nil string file: /usr/local/lib/vlang/vlib/builtin/string.v:105 v hash: a03da95 =========================================
そんな事より衝撃を受けたのは、vlib/builtinが有った事。見事にスルーしてました。 オイラーの目は節穴です。気を取り直して、そこのREADMEを見ると
`builtin` is a module that is implicitly imported by every V program. It implements the builtin V types `array`, `string`, `map`. It also implements builtin functions like `println`, `eprintln`, `malloc`, `panic`, `print_backtrace`. The autogenerated documentation for `builtin` functions is lacking, so for these functions, please refer to the [official V documentation](https://github.com/vlang/v/blob/master/doc/docs.md).
配列のメソッドを改めて確認すると、こんな風に定義されてたぞ。
pub fn (a array) filter(predicate fn (voidptr) bool) array pub fn (a array) map(callback fn (voidptr) voidptr) array
冒頭にpubが付いてて、皆に公開するね。引数は関数だからねってのは、いにしえから 有るLispの血筋を受け継いでいます。
ついでに配列の構造。
// array is a struct, used for denoting all array types in V. // `.data` is a void pointer to the backing heap memory block, // which avoids using generics and thus without generating extra // code for every type. pub struct array { pub mut: data voidptr offset int // in bytes (should be `usize`), to avoid copying data while making slices, unless it starts changing len int // length of the array in elements. cap int // capacity of the array in elements. flags ArrayFlags pub: element_size int // size in bytes of one element in the array. }
これで、下記の {} の意味が氷解したよ(今頃かい)。
>>> mut c := []int {len: 5} >>> c [0, 0, 0, 0, 0]
orm
たまたま、こんな本を読んでいたんだ。 世界最凶のスパイウェア ペガサス 池上 彰さんが警鐘を鳴らしている、 「あなたのスマホは、大丈夫ですか?」って。
アンドロイドOSでは記録を余り残さない仕様みたいだけど、アプルのそれはタイムマシン を売りにしてるせいか、しっかり記録を残しているそうな。で、それにsqliteを使って いるとか。
vlangはwebのサポートもしっかり行なわれている。バックエンドのDBサポートも必須。 ormってライブラリィーにて提供されてた。ボラクルは論外だけど、mysql,pg,mssql,sqlite はサポートされてた。
sakae@lu:orm$ v test . ---- Testing... ---------------------------------------------------------------- OK [ 1/23] C: 425.6 ms, R: 3.516 ms /var/my/srcs/v/vlib/orm/orm_fk_test.v OK [ 2/23] C: 689.6 ms, R: 4.434 ms /var/my/srcs/v/vlib/orm/orm_custom_operators_test.v : OK [22/23] C: 527.1 ms, R: 3.054 ms /var/my/srcs/v/vlib/orm/orm_sum_type_insert_test.v OK [23/23] C: 474.0 ms, R: 5.913 ms /var/my/srcs/v/vlib/orm/orm_test.v -------------------------------------------------------------------------------- Summary for all V _test.v files: 23 passed, 23 total. Elapsed time: 4557 ms, on 3 parallel jobs. Comptime: 13166 ms. Runtime: 1 08 ms.
最初テストがことごとくフェイルした。例のいやがらせね。sudo apt install libsqlite3-dev これにて無事を確認した。はて、何に使おうか。
vinix
近頃のリナはC言語推しの保守派とrust推しの革新派のせめぎあいで政治論争に なってるらしい。rust派の人が辞任するとか。そんな事を尻目に、清くvlangで カーネルを作成しましょって中道派が、ひそかに活動してる。して、その名は
興味深いので参戦してみる。
makeすると、gccやらのユーザーランドのコンパイルが始まった。しゃらくさいので、 ISOを頂いてきて、実行してみた。
ISO
Limine ってのがgrubに代って採用されてる。シンプルなんだろうね。ISOを分解 して、どんな構成になってるか確認。
ob$ doas vnconfig vnd0 /var/SRC/vinix/vinix.iso ob$ doas mount -t cd9660 /dev/vnd0c /mnt ob$ tree /mnt /mnt |-- EFI | `-- BOOT | |-- BOOTIA32.EFI | `-- BOOTX64.EFI |-- boot | |-- initramfs.tar | |-- limine-bios-cd.bin | |-- limine-bios.sys | |-- limine-uefi-cd.bin | |-- limine.conf | `-- vinix `-- boot.catalog
limine.confはこんなの。カーネルガvinixで、モジュールはinitramfsとな。
timeout: 3 /Vinix protocol: limine kernel_path: boot():/boot/vinix module_path: boot():/boot/initramfs.tar
そのモジュール扱かいされる中身は
initramfs.tar
ob$ ls -l total 12 lrwxr-xr-x 1 sakae wheel 7 Mar 15 09:58 bin@ -> usr/bin drwxr-xr-x 3 sakae wheel 512 Mar 15 09:58 etc/ lrwxr-xr-x 1 sakae wheel 7 Mar 15 09:58 lib@ -> usr/lib lrwxr-xr-x 1 sakae wheel 7 Mar 15 09:58 lib64@ -> usr/lib drwxr-xr-x 2 sakae wheel 512 Mar 15 09:58 root/ drwxr-xr-x 2 sakae wheel 512 Mar 15 09:58 run/ lrwxr-xr-x 1 sakae wheel 7 Mar 15 09:58 sbin@ -> usr/bin drwxr-xr-x 2 sakae wheel 512 Mar 15 09:58 tmp/ drwxr-xr-x 7 sakae wheel 512 Mar 15 11:03 usr/ drwxr-xr-x 3 sakae wheel 512 Mar 15 09:58 var/
リナでISOの中身を確認するなら、こうするのかな。OpenBSDより、ちょっと楽天か。
sakae@lu:vinix$ sudo mount -o loop /var/my/srcs/vinix/vinix.iso /mnt mount: /mnt: WARNING: source write-protected, mounted read-only. sakae@lu:vinix$ ls /mnt EFI/ boot/ boot.catalog
run-kvm
GNUMakefileを見ると、kvmで起動できる様にターゲットが設定されてた。但しメモリー8G で4cpuって設定だったので、軽くした。
残念ながらVGAな画面なので、起動時からのログは提示できない。bashが起動して くると、com1にリダイレクトが可能になるので、ホスト側に情報を流せるようになる。
root@vinx [ ~ ] # ls -l /dev > /dev/com1 ;; in gestOS sakae@lu:vinix$ make run-kvm ;; on Lubuntu qemu-system-x86_64 -enable-kvm -cpu host -M q35,smm=off -m 4G -cdrom vinix.iso -serial stdio -smp 2 crw-r--r-- 1 root root 0, 9 Mar 19 06:52 com1 crw-r--r-- 1 root root 0, 8 Mar 19 06:52 console crw-rw-rw- 1 root root 0, 7 Mar 19 06:52 fb0 crw-rw-rw- 1 root root 0, 5 Mar 19 06:52 full crw-r--r-- 1 root root 0, 10 Mar 19 06:52 mouse crw-rw-rw- 1 root root 0, 3 Mar 19 06:52 null crw-rw-rw- 1 root root 0, 6 Mar 19 06:52 urandom crw-rw-rw- 1 root root 0, 4 Mar 19 06:52 zero
gcc -v > /dev/com1 2>&1
Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-vinix-mlibc/14.2.0/lto-wrapper Target: x86_64-vinix-mlibc Configured with: /base_dir/sources/gcc/configure ... : Thread model: posix Supported LTO compression algorithms: zlib zstd gcc version 14.2.0 (GCC)
ちゃんとハロワがコンパイル&実行できたから、カーネルとしては、ちゃんと動作 してるっぽい。
vlangで記述されたユーザーランドも用意されてた。下記はそのうちのlscpu
Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Address sizes: 39 bits physical, 48 bits linear Byte Order: Little Endian CPU Count: 2 Vendor ID: GenuineIntel Model name: Intel(R) Core(TM) i5-6200U CPU @ 2.30GHz CPU family: 6 Model number: 78 Stepping: 3 Flags: aes, apic, avx, ... ssse3, tsc, vme, vmx, x2apic, xsave
see source
上で出てきた奴から。
sakae@lu:vinix$ ls util-vinix/lscpu/ cpu_x64.v main.v v.mod
main.v
module main import os import cpu fn main() { mut idx := 1 for idx < os.args.len { match os.args[idx] { '--help' { : info := cpu.get_cpu_info() or { println('Could not fetch CPU information') exit(1) } info.print()
mainは何の変哲もないな。ああ、matchなんてのがポートされてるのか。途中で乱入 してるんで、良く知らないな。感覚で見ております。
module cpu : pub fn get_cpu_info() ?CPUInfo { // Fetch vendor. mut str0 := &RawVendorID{} _, _, str0.ebx, str0.ecx, str0.edx = cpuid(0, 0) vendor_id := unsafe { cstring_to_vstring(charptr(&str0.ebx)) } // Fetch model, stepping and family. _, a1, _, c1, d1 := cpuid(1, 0) : return CPUInfo{ address_sizes: [physical_size, linear_size] is_little_endian: true cpu_count: core_count vendor_id: vendor_id model_name: model_name cpu_family: cpu_family model_number: model_number stepping: stepping_id flags: flags }
アセンブラの世界から情報を引いてきて、最後は、構造体にして返却ってやってる。 これがcpuモジュールの定義とな。
これならlubuntu側でも動くんじゃなかろうか? 試してみる。モジュールが別々に 定義されてる場合、それが存在するdirを指定してコンパイルすればいいのか。そんな 事はエラー駆動でhelp buildして知見を得たぞ。
sakae@lu:util-vinix$ v lscpu sakae@lu:util-vinix$ ls -l lscpu/ 合計 468 -rw-rw-r-- 1 sakae sakae 9191 3月 16 06:08 cpu_x64.v -rwxrwxr-x 1 sakae sakae 457032 3月 20 06:33 lscpu* -rw-rw-r-- 1 sakae sakae 651 3月 16 06:08 main.v -rw-rw-r-- 1 sakae sakae 130 3月 16 06:08 v.mod sakae@lu:util-vinix$ lscpu/lscpu Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit :
もう一発、軽いfetchが有ったので試した。
sakae@lu:util-vinix$ v fetch sakae@lu:util-vinix$ fetch/fetch __ __ \ \ / // sakae@lu \ \ / // OS: Linux x86_64 #57-Ubuntu SMP PREEMPT_DYNAMIC Wed Feb 12 23:42:21 UTC 2025 \ \ / // KERNEL: Linux \ \ / // SHELL: /bin/bash \ \/ // \/_// __ __ \ \ / // root@vinix \ \ / // OS: \ \ / // KERNEL: \ \ / // SHELL: /bin/bash \ \/ // \/_//
下側のやつはゲストOSであるvinuxからの転送結果。まだ間に合ってない項目が有る んだね。頑張って実装して下さい。
init
大事なbashを起動する奴。これなくしては、ユーザーは手も足も出ない。カーネルの 起動の最後に、これが呼び出される。
fn main() { println('Vinix Init started') os.setenv('HOME', '/root', true) os.setenv('TERM', 'linux', true) os.setenv('PATH', '/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin', true) os.setenv('USER', 'root', true) : os.chdir('/root') or { panic('Could not move to root') } : for { os.system("exec -a '-bash' bash --login") }
儀式として環境変数をセットしてから、所定の場所に移動。そしてbashを起動する。 簡易ではあるが、よく動きが分かるな。
How to make ISO
途中で諦めてしまったISO作成工程。懺悔して作成手順を確認しとけ。 最終的にはbuild-support/makeiso.shでISOが作成されるんだけど、その為の内容物を 準備しておかねばならない。
それには、jinxと言う現場監督が招聘される。recipesの中に格納されてる設計図を 頼りにソースを取り寄せ、sourcesの下を作業場所としてコンパイルしてくって仕組み のようだ。途中まで作成した残骸が3.6Gもsourcesの下に残っていたぞ。full-build したら、一体どこまで肥大化するやら? 怖くて継続する有機が有りませんです。
次回は、いよいよ本丸のkernelかな。
README
ウェイリー版 源氏物語を読んだ。100分de名著の方ね。
紫式部が書いた有名な物語。古語なんで、難しくて読めんと言う事で、与謝野晶子 さんが現代風に翻訳。
イギリスの大英博物館に勤務してたウェイリー氏も独自に英訳。これで世界に 広がり絶賛されるようになった。更にその英訳を元に、日本語に翻訳された方も おられる。これが読みやすいと評判らしい。
原文では几帳となってる所をcurtainと翻訳した。これを日本語に再翻訳する時 カーテンとした。几帳とはしなかったんだ。翻訳には2種あるという。
同化翻訳、翻訳先の文化に同化させるって方法。異化翻訳は、異質のまま翻訳して、 注を入れるって方法。 AIの翻訳は、どっちの方針を採用してんかな? とか考えちゃったぞ。
紫式部日記なんてのも勧められていた。同業者の枕草子を書いた清少納言を こっぴどく、こきおろしてるのには笑ってしまった。
光源氏を、シャイニング・プリンス(光る君)と訳した。大河ドラマの方はパクったんだな。