hello rust
rustは全部入り
goに行くかrustに行くか迷ったけども、rustを選択。何故かと言うとGCが無いから。 混ぜればごみ、分れば資源って合言葉を書いたごみ回収車が走っている。これにインスパイアーされたのさ。
GCはLISPの発明品。メモリーを裏で回収して、メモリーが無限にあるような幻想をいだかしている。これって、消費者を欺いていないか? 冷凍食品が売れる、コンビニ便利、、、なのはいいけど、大量にごみを撒き散らしている。反省しなさいは、コンピュータの世界も一緒。
大体、使い放題だから、辛抱強いおかーさんが、裏でメモリーを回収しまくっているんだ。その時は、世界が止められてしまう。そんな生活はいやだ。塵回収が必要になるのは、資源をジャブジャブ使い放題に使っているから。ごみの出ない、ださない生活をすれば一挙に問題解決。
さあ、ごみが出ない新生活へスイッチしよう(そういうなら、今後一切schemeなんて使うなと言われそう、ついでにrubyとかもだぞ)。
少し、人様の主張を聞いてみるか。
なぜRustを学ぶべきなのか 〜 5年経った今改めてまとめてみる
Re:FizzBuzzから始めるRust生活 これはお勧めな記事だ。
Rustに影響を与えた言語たち 良い所だけ取ってきて言語を作りましたとな。
そして、良く使うであろう Primitive Type str とか、人様のノウハウを集めた Rustで初めてツールを作るときに役にたったリンク集 が、参考になろう。
emacs + rust
例によってemacsからrustと言うかcargoを操作出来るようにしておく。世間一般にはVSCODEって言うMS製のEDITORを使うのが鉄板らしいけど、ロートルはCUIが好きなのよ。
GUIな編集装置向けにrustもサービスに一生懸命。その現れがrust-nalyzerって言うコンパイラーのフロントエンド。こいつの力を借りて、補完とかをする。で、ダイレクトにEDITORとやり取りする訳ではなく、間にインターフェースを介して行う。それがemacs上では、lsp-mode. MSの陰謀で提案されたものが、emacs用に移植されてるって訳。
rustは、産地直送で、ダイレクトにユーザーに屆くようになってる。間にOSなんていう問屋が有ると、どうしてもフレッシュな最新阪を届けられないからね。一度ご利用頂くと、その後はrustup upgradeってコマンド一発で、最新版に更新出来る。対応は、Windows,MacOS,Linux限定。
もうBSDはすっかり蚊帳の外だ。ついでに、32ビットマシンも対象外。そこでだ、
manualとか Rustプログラミングのための環境構築 を参照しつつ、手軽に Rust開発環境 on Emacs更新 に従って、rustic,rust-analyzerを入れる。
OpenBSDにソースからrust-analyzerを入れようとしたら、年式が2018なんで駄目だと言われたよ。2021式が來るのは何時だ?
しょうがないので、補完とかを諦め、その代わりにrust-gdbを入れておいた。こいつはどうしても欲しいからね。こやつshell-scriptなのね。核心部分は
# Find out where the pretty printer Python module is RUSTC_SYSROOT="$("$RUSTC" --print=sysroot)" GDB_PYTHON_MODULE_DIRECTORY="$RUSTC_SYSROOT/lib/rustlib/etc" # Run GDB with the additional arguments that load the pretty printers # Set the environment variable `RUST_GDB` to overwrite the call to a # different/specific command (defaults to `gdb`). RUST_GDB="${RUST_GDB:-egdb}" PYTHONPATH="$PYTHONPATH:$GDB_PYTHON_MODULE_DIRECTORY" exec ${RUST_GDB} \ --directory="$GDB_PYTHON_MODULE_DIRECTORY" \ -iex "add-auto-load-safe-path $GDB_PYTHON_MODULE_DIRECTORY" \ "$@"
pythonを使って、綺麗に見せますって方針になってる。
New year
年末に、友人から、もー幾つ寝るとお正月なんていう楽しいメールを頂いていた。それの返答がこれ。新年の挨拶用にも転用。久し振りにかくコードだ。構造体の名前が型名ってのが、何実にCより進歩してんな。
fn main() { struct Year { y: i16, d: i16, } let mut yd = Year { y: 2021, d: 365 }; while yd.d > 0 { yd.d -= 1 } println!("{} New year!", yd.y + 1); }
rustには、–i,++iという便利なやつが無いのは、確信犯なのかな? 何故だろう。
今年初めてのつたない英語、why don't support increment operator in rust で聞いてみた。出て来た案内を数Hopしたら、https://github.com/dtolnay/rust-faq#why-doesnt-rust-have-increment-and-decrement-operators 正しい言い回しに辿りついた。
公式回答では、++,– は、複雑であいまいさがありBUGの温床になるから、サポートしないよって箏だ。他のFAQもなかなか面白いな。
折角なのでバグを仕込んでみる。日々を足すね。
vbox$ cargo r Finished dev [unoptimized + debuginfo] target(s) in 0.04s Running `target/debug/hoge` thread 'main' panicked at 'attempt to add with overflow', src/main.rs:9:9 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
オーバーフローを掴まえてくれた。詳しく見てみる。あれ、省略されちゃってるよ。
OpenBSDと同じ年式のFreeBSDでもやってみる。
[sakae@fb /tmp/hoge]$ rustc -V rustc 1.55.0 [sakae@fb /tmp/hoge]$ head Cargo.toml [package] name = "hoge" version = "0.1.0" edition = "2018"
バージョン番号とeditionと言う年式の2本立てになってる。年式が同じだと共通仕様って事で、多分問題なく動くんだろうね。で、属に言う Run Time Errorのおでまし。
[sakae@fb /tmp/hoge]$ RUST_BACKTRACE=1 cargo r Finished dev [unoptimized + debuginfo] target(s) in 0.03s Running `target/debug/hoge` thread 'main' panicked at 'attempt to add with overflow', src/main.rs:8:9 stack backtrace: 0: rust_begin_unwind 1: core::panicking::panic_fmt 2: core::panicking::panic 3: hoge::main at ./src/main.rs:8:9 4: core::ops::function::FnOnce::call_once at /wrkdirs/usr/ports/lang/rust/work/rustc-1.55.0-src/library/core/src/ops/function.rs:227:5 note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
full traceも出来るってんで、上記の上流も出て来た。しっかりrustを作成した時の痕跡が記憶されてるな。
: 13: 0x1010791 - std::sys_common::backtrace::__rust_begin_short_backtrace::h81de2ce2115f8265 at /wrkdirs/usr/ports/lang/rust/work/rustc-1.55.0-src/library/std/src/sys_common/backtrace.rs:125:18 14: 0x1010b33 - std::rt::lang_start::{{closure}}::h7edc9139a1dc248d at /wrkdirs/usr/ports/lang/rust/work/rustc-1.55.0-src/library/std/src/rt.rs:63:18 15: 0x10267b9 - std::rt::lang_start_internal::h6521f84e51a30755 16: 0x1010af0 - std::rt::lang_start::ha93e0e8c16851be6 at /wrkdirs/usr/ports/lang/rust/work/rustc-1.55.0-src/library/std/src/rt.rs:62:5 17: 0x1010927 - main
manでリリース版のやり方を調べて実行。あれ? BUGが潰れているぞ。
[sakae@fb /tmp/hoge]$ man cargo-run ;; cargo help run for linux [sakae@fb /tmp/hoge]$ cargo r --release Finished release [optimized] target(s) in 0.02s Running `target/release/hoge` 2022 New year!
信じられない挙動だ。ええい、直の実行。
[sakae@fb /tmp/hoge]$ target/release/hoge 2022 New year! [sakae@fb /tmp/hoge]$ target/debug/hoge thread 'main' panicked at 'attempt to add with overflow', src/main.rs:8:9 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
こいつぁ、冬の珍事? かな。cargo cleanして、綺麗に痕跡を消してから実行しても、珍事は続くよ。正気のさたか???
こうなったら、河岸を変えて2021年式でcargoしてみる。いわゆる本家本元ね。 その前に、ちゃんとHELPを読め。 https://doc.rust-lang.org/cargo/reference/profiles.html
[profile.release] opt-level = 3 debug = false split-debuginfo = '...' # Platform-specific. debug-assertions = false overflow-checks = false lto = false panic = 'unwind' incremental = false codegen-units = 16 rpath = false
こいつに引掛ったんだな。詐欺っぽいぞ。通報するぞ、って、既に公式になってるじゃん。
exec …
tokioで外部コマンド実行 なんてのを見付けた。けど、究極はshellだよね。歳の始めに見付けておいた自作shellを試してみる。
vbox$ cargo b error: failed to parse manifest at `/tmp/shell-sample-code/step1/Cargo.toml` Caused by: feature `edition2021` is required The package requires the Cargo feature called `edition2021`, but that feature is not stabilized in this version of Cargo (1.55.0). Consider trying a newer version of Cargo (this may require the nightly release). See https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#edition-2021 for more information about the status of this feature.
お前の持ってるやつは、さび ついているから、新しいrustにしろって言われた。そうよ、pkgからだと陳腐なものしか用意出来無いのよ。まあ、諦めて年式が古いやつですって設定した。
vbox$ time cargo b Compiling autocfg v1.0.1 Compiling libc v0.2.112 Compiling bitflags v1.3.2 Compiling cfg-if v1.0.0 Compiling memoffset v0.6.5 Compiling nix v0.23.1 Compiling toysh v0.1.0 (/tmp/shell-sample-code/step1) Finished dev [unoptimized + debuginfo] target(s) in 24.64s 0m24.68s real 0m24.46s user 0m08.67s system
外部の依存は極力少くなるように配慮されてるようだけど、それでも関連品を含めてこれだけコンパイルされた。もう宿命なんだろうね。
vbox$ cargo r Finished dev [unoptimized + debuginfo] target(s) in 0.07s Running `target/debug/toysh` > uname -a OpenBSD vbox.local.jp 7.0 GENERIC.MP#3 i386
リナ用って事だけど、普通に動いた。へんてこなシステムコールをしない限りは大丈夫そう。
続いてgdbにかけてみる。emacsからだとrust-gdbが動かないので(なんたって、上で見たように、ラッパーですから)、別端末でアプリを起動して、それにアタッチした。
vbox$ rust-gdb -q toysh -p 54129 Reading symbols from toysh...done. Attaching to program: /tmp/shell-sample-code/step1/target/debug/toysh, process 54129 Reading symbols from /usr/lib/libc++abi.so.5.0...done. Reading symbols from /usr/lib/libc.so.96.1...done. Reading symbols from /usr/libexec/ld.so...done. [Switching to thread 200238] _thread_sys_read () at /tmp/-:3 3 /tmp/-: No such file or directory. (gdb) b execve Breakpoint 1 at 0xf90c100: file /tmp/-, line 3.
そして、システムコールの呼出にBPを億。別端末のアプリに入力。
Breakpoint 1, execve () at /tmp/-:3 3 /tmp/-: No such file or directory. (gdb) bt #0 execve () at /tmp/-:3 #1 0x0f9817d0 in _libc_execvpe (name=0x560e0230 "uname", argv=0x560bfd70, envp=0xcf7e139c) at /usr/src/lib/libc/gen/exec.c:201 #2 0x0f981577 in _libc_execvp (name=0x560e0230 "uname", argv=0x560bfd70) at /usr/src/lib/libc/gen/exec.c:249 #3 0x19febab9 in nix::unistd::execvp::hde14bd861e4012af (filename=0x560e0230, args=&[std::ffi::c_str::CString](size=2) = {...}) at /home/sakae/.cargo/registry/src/github.com-1285ae84e5963aae/nix-0.23.1/src/unistd.rs:781 #4 0x19feeeac in toysh::shell_exec_simple_command::he199460e396cd07e ( command=...) at src/main.rs:70 #5 0x19fee8a1 in toysh::shell_loop::h3b20613e6bb4af99 () at src/main.rs:24 #6 0x19fee757 in toysh::main::h4d8f867332179c54 () at src/main.rs:13 #7 0x19fe7958 in core::ops::function::FnOnce::call_once::h1db125a82d9e4cf6 () at /pobj/rust-1.55.0/rustc-1.55.0-src/library/core/src/ops/function.rs:227 #8 0x19fec123 in std::sys_common::backtrace::__rust_begin_short_backtrace::ha7f 35dc1e7ee0e86 (f=0x19fee740 <toysh::main::h4d8f867332179c54>) at /pobj/rust-1.55.0/rustc-1.55.0-src/library/std/src/sys_common/backtrace.rs:125 #9 0x19feb2b5 in std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::h8901638a45 779c16 () at /pobj/rust-1.55.0/rustc-1.55.0-src/library/std/src/rt.rs:63 #10 0x1a003f02 in std::rt::lang_start_internal::hfe0abd7a78dfa937 () #11 0x19feb263 in std::rt::lang_start::h3cd98e76ceb84846 ( main=0x19fee740 <toysh::main::h4d8f867332179c54>, argc=1, argv=0xcf7e1394) at /pobj/rust-1.55.0/rustc-1.55.0-src/library/std/src/rt.rs:62 #12 0x19feef3b in main ()
結構深い実行履歴が出てきたな。
(gdb) f 3 #3 0x19febab9 in nix::unistd::execvp::hde14bd861e4012af (filename=0x560e0230, args=&[std::ffi::c_str::CString](size=2) = {...}) at /home/sakae/.cargo/registry/src/github.com-1285ae84e5963aae/nix-0.23.1/sr c/unistd.rs:781 781 libc::execvp(filename.as_ptr(), args_p.as_ptr()) (gdb) l 776 #[inline] 777 pub fn execvp<S: AsRef<CStr>>(filename: &CStr, args: &[S]) -> Result<Inf allible> { 778 let args_p = to_exec_array(args); 779 780 unsafe { 781 libc::execvp(filename.as_ptr(), args_p.as_ptr()) 782 }; 783 784 Err(Errno::last()) 785 }
外部ライブラリィーの活躍の場を視察。インラインになってるって事は、スピード重視なんだな。
cすると何度かBPにヒットし、最後はSIGTRAP。この時、別画面で起動してたコマンドが実行されて、結果が出てきた。何度も隠れてexecveが走っているのね。
cargo
cargoはRustシステムのshellです。newとbuildとrunだけじゃ、もったいない。ってんで、オイラーの琴線に触れたものをあげておく。
-j
cargoはmakeも兼ているんで、きっとあれが有るはず。
sakae@pen:/tmp/shell-sample-code/step1$ time cargo b : real 0m13.154s user 0m11.751s sys 0m9.161s
並行コンパイルON
sakae@pen:/tmp/shell-sample-code/step1$ time cargo b -j 4 : real 0m9.069s user 0m12.272s sys 0m3.101s
多少はイライラが減少するかな。
tree
ライブラリィってかCratesの、こんがらがり具合を確認するやつ
sakae@pen:/tmp/shell-sample-code/step1$ cargo tree toysh v0.1.0 (/tmp/shell-sample-code/step1) └── nix v0.23.1 ├── bitflags v1.3.2 ├── cfg-if v1.0.0 ├── libc v0.2.112 └── memoffset v0.6.5 [build-dependencies] └── autocfg v1.0.1
このコマンド、cargo –helpでも案内に出てこないんだ。余り使われると、Cratesの作者様の手抜き具合、もとえ、人の褌で相撲をとる具合、もとえ、依存具合が白昼の元に晒されるんで、隠してるのさ。
doc –open
ドキュメントをソースから自動生成して、それをブラウザーに引き継いで閲覧出来る。
sakae@pen:/tmp/shell-sample-code/step1$ cargo doc --open Checking bitflags v1.3.2 Checking cfg-if v1.0.0 Documenting bitflags v1.3.2 Documenting cfg-if v1.0.0 : Documenting toysh v0.1.0 (/tmp/shell-sample-code/step1) Finished dev [unoptimized + debuginfo] target(s) in 8.59s Opening /tmp/shell-sample-code/step1/target/doc/toysh/index.html
出来上がったhtml類は、target/docの中にある。直接見るものではない。ブラウザーを通して、関連のCratesも参照出来るぞ。
例えば、libcのfunctionの項目にあるexecve
pub unsafe extern "C" fn execve( prog: *const c_char, argv: *const *const c_char, envp: *const *const c_char ) -> c_int
いちいち探し回らなくても、検索窓が有るから、execveとかすれば
Results for execve nix::unistd::execve Replace the current process image with a new one (see … libc::execve nix::unistd::fexecve Replace the current process image with a new one (see … nix::unistd::execveat Execute program relative to a directory file descriptor … libc::fexecve libc::SYS_execve libc::SYS_execveat nix::unistd::execv Replace the current process image with a new one (see … nix::unistd::execvp Replace the current process image with a new one and … nix::unistd::execvpe Replace the current process image with a new one and … libc::execv libc::execle libc::execvp libc::execvpe libc::execl libc::execlp
こんな具合に出て来る。ググル様も真っ青になる、検索機能が、target/docの中に鎮座してるのね。ただのクリック猿で十分ですよ。
vendor
外部のやつを、プロジェクトdirに鎮座させるサービスコマンド。
[sakae@fb /tmp/shell-sample-code/step1]$ cargo vendor Vendoring autocfg v1.0.1 (/home/sakae/.cargo/registry/src/github.com-1285ae84e5963aae/autocfg-1.0.1) to vendor/autocfg : Vendoring nix v0.23.1 (/home/sakae/.cargo/registry/src/github.com-1285ae84e5963aae/nix-0.23.1) to vendor/nix To use vendored sources, add this to your .cargo/config.toml for this project: [source.crates-io] replace-with = "vendored-sources" [source.vendored-sources] directory = "vendor"
こんな具合になる。
[sakae@fb /tmp/shell-sample-code/step1]$ ls Cargo.lock Cargo.toml src/ target/ vendor/ [sakae@fb /tmp/shell-sample-code/step1]$ ls vendor/ autocfg/ cc/ libc/ nix/ bitflags/ cfg-if/ memoffset/
CUIな人は、これでソースの閲覧に集中出来るな。
root of rust
本家本元のソース源、 source だ。けれども、
sakae@deb:~/src$ git clone https://github.com/rust-lang/rust.git Cloning into 'rust'... remote: Enumerating objects: 1626274, done. remote: Total 1626274 (delta 0), reused 0 (delta 0), pack-reused 1626274 Receiving objects: 100% (1626274/1626274), 721.81 MiB | 39.00 KiB/s, done. Resolving deltas: 100% (1300052/1300052), done. Updating files: 100% (31730/31730), done.
回線が非常に細いのでcloneするのに5時間はかかった。ふぅーー。