├── 00-setup.md ├── 00-setup ├── rust-vscode-terminal.png ├── vscode-codelldb-config-01.png ├── vscode-codelldb-config-02.png ├── vscode-remote-dev-install-ext.png ├── vscode-remote-dev-ssh-config-01.png ├── vscode-remote-dev-ssh-config-02.png ├── vscode-remote-dev-ssh-config-03.png ├── vscode-remote-dev-ssh-config-04.png └── vscode-remote-dev-ssh-config-05.png ├── 01-helloworld.md ├── 01-helloworld ├── open-folder-01.png ├── open-folder-02.png ├── open-folder-03.png └── open-main.png ├── 02-macro.md ├── 02-macro ├── rust-doc-01.png ├── rust-doc-02.png ├── rust-doc-03.png └── rust-doc-04.png ├── 03-function.md ├── 03-function ├── fn-diag-01.png ├── fn-diag-02.png └── fn-diag-ans.png ├── 04-detective.md ├── 04-detective └── criminal-in-fn-call.png ├── 05-debugger.md ├── 05-debugger ├── codelldb-brk-01.png ├── codelldb-brk-02.png ├── codelldb-brk-03.png ├── codelldb-brk-04.png ├── codelldb-launch-01.png ├── codelldb-launch-02.png ├── codelldb-launch-03.png ├── codelldb-launch-04.png ├── codelldb-launch-05.png ├── codelldb-launch-06.png └── step-in-out-over.png ├── 06-step-by-step.md ├── 06-step-by-step ├── step-01.png ├── step-02.png ├── step-03.png ├── step-04.png ├── step-05.png ├── step-06.png ├── step-07.png ├── step-08.png ├── step-09.png ├── step-10.png ├── step-11.png ├── step-12.png ├── step-13.png └── step-14.png └── README.md /00-setup.md: -------------------------------------------------------------------------------- 1 | # 環境構築 2 | 3 | ## 2つの環境 4 | 5 | ### ローカル環境 6 | 7 | 本資料では、手元のコンピュータのことを「ローカル環境」と呼びます。 8 | 9 | ローカル環境の OS はなんであっても構いませんが、後述の VS Code が動作する必要があります。 10 | 11 | ### 実験環境 12 | 13 | ローカル環境とは別に、実際にコードを動かして観察するための環境を用意してください。この環境を、以下「実験環境」と呼びます。 14 | 15 | 実験環境は x86_64 アーキテクチャの CPU 上で動く Ubuntu Server 18.04 とし、ローカル環境から SSH で接続可能なようにしてください。 16 | 17 | 実験環境のメモリやディスクの容量は足りるように調整してください。メモリは2GB程度、ディスクは20GB程度あれば足りるでしょう。 18 | 19 | ## VS Code 20 | 21 | 本資料の全編を通し、実験環境のファイルを編集するために VS Code の Remote Development 機能を用います。 22 | 23 | 本資料の執筆時点では Remote Developmet は Insider 版の VS Code でしか利用できません。 24 | 25 | 下記から **ローカル環境に** VS Code Insider をダウンロードし、インストールしてください。 26 | 27 | [Download Visual Studio Code Insiders](https://code.visualstudio.com/insiders/) 28 | 29 | インストールが完了したら、VS Code Insider を起動し、次の手順に進んでください。 30 | 31 | ### Remote Development 32 | 33 | 前述のとおり、Remote Development 機能を利用するため、当該の拡張機能をインストールします。 34 | 35 | 左のペインの拡張機能タブを開き、 `@id:ms-vscode-remote.vscode-remote-extensionpack` で検索してインストールします。 36 | 37 | ![](./00-setup/vscode-remote-dev-install-ext.png) 38 | 39 | 続いて、実験環境の接続情報を設定します。 40 | 41 | Remote Development では、`~/.ssh/config` に書いたホストにしか接続できないため、それに実験環境のエントリを追加します。 42 | 43 | まず VS Code でコマンドパレットを開きます(macOS では `Cmd-Shift-P`)。 44 | 45 | そして、コマンドパレットに `connect current` と入力し、`Remote-SSH: Connect Current Window to Host...` にフォーカスが合っていることを確認して enter キーを押します。 46 | 47 | ![](./00-setup/vscode-remote-dev-ssh-config-01.png) 48 | 49 | するとパレットが遷移しますが、`Configure SSH Hosts...` にフォーカスを合わせたまま enter キーを押します。 50 | 51 | ![](./00-setup/vscode-remote-dev-ssh-config-02.png) 52 | 53 | さらにパレットが遷移し、`.ssh/config` の場所を尋ねられますが、ここもそのまま enter キーを押して進みます。 54 | 55 | ![](./00-setup/vscode-remote-dev-ssh-config-03.png) 56 | 57 | `.ssh/config` が開いたら、接続情報を書いて保存します。 58 | 59 | ![](./00-setup/vscode-remote-dev-ssh-config-04.png) 60 | 61 | 以下は `.ssh/config` の一例です。詳しくは OpenSSH のマニュアルを参照してください。 62 | 63 | ``` 64 | Host helloworld-dev 65 | HostName nanika-vm.example.com 66 | User yourname 67 | ``` 68 | 69 | 設定が正しいか確認するため、試しに接続してみましょう。 70 | 71 | コマンドパレットを開き `connect to host` で検索、`Connect to Host...` を実行します。 72 | 73 | すると先程設定したホスト名が表示されるため、それを選択して実行してください。 74 | 75 | 画面が切り替わり、左下の緑色のリボンにホスト名が表示されていれば成功です。 76 | 77 | ![](./00-setup/vscode-remote-dev-ssh-config-05.png) 78 | 79 | 以下の手順は接続が完了したウィンドウで行ってください。 80 | 81 | ### Rust(rls) 82 | 83 | 続いて、VS Code に拡張機能 Rust(rls) をインストールします。 84 | 85 | Rust(rls) は Rust を書くために便利な拡張機能です。 86 | 87 | 先ほどと同様に、左のペインから拡張機能タブを開き、`@id:rust-lang.rust ` を検索してインストールします。 88 | 89 | ### CodeLLDB 90 | 91 | VS Code に拡張機能 CodeLLDB をインストールします。 92 | 93 | 拡張機能タブの検索窓で `@id:vadimcn.vscode-lldb` を検索してインストールします。 94 | 95 | インストールが完了したら設定をします。 96 | 97 | Settings を開き(macOS では `Cmd+,`)、`Remote` タブを選んだあと、右上の `{}` アイコンをクリックします。 98 | 99 | ![](./00-setup/vscode-codelldb-config-01.png) 100 | 101 | すると、Settings の JSON エディタが開くので、以下の内容を貼り付けて保存します。 102 | 103 | ```json 104 | { 105 | "debug.allowBreakpointsEverywhere": true, 106 | "lldb.adapterType": "bundled", 107 | "lldb.launch.sourceMap": { 108 | "/rustc/3c235d5600393dfe6c36eeed34042efad8d4f26e/src/": "${env:HOME}/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/", 109 | }, 110 | } 111 | ``` 112 | 113 | ![](./00-setup/vscode-codelldb-config-02.png) 114 | 115 | 以上で VS Code のセットアップは完了です。 116 | 117 | ## Rust コンパイラ 118 | 119 | ここから先は **実験環境** に SSH して作業します。 120 | 121 | 別途ターミナルエミュレータを立ち上げて SSH してもよいですが、先程セットアップした VS Code の Remote Development の機能を用いることもできます。 122 | 123 | Remote Development の機能で実験環境のターミナルを開くには、実験環境に接続が完了しているウィンドウで Integrated Terminal を開きます(macOS では `Ctrl-Shift-~`)。 124 | 125 | ![](./00-setup/rust-vscode-terminal.png) 126 | 127 | まずはじめに、Rust のコンパイラをインストールしましょう。 128 | 129 | ターミナルで以下のコマンドを実行します。行頭の `$` はシェルでの実行を示す単なるマークであり、入力する必要はありません。 130 | 131 | ``` 132 | $ curl https://sh.rustup.rs -sSf | sh 133 | ``` 134 | 135 | すると、途中で次のようなプロンプトが出るはずです。 136 | 137 | ``` 138 | Current installation options: 139 | 140 | default host triple: x86_64-unknown-linux-gnu 141 | default toolchain: stable 142 | modify PATH variable: yes 143 | 144 | 1) Proceed with installation (default) 145 | 2) Customize installation 146 | 3) Cancel installation 147 | > 148 | ``` 149 | 150 | これはインストールの設定を変更するかどうか尋ねるものですが、デフォルト設定でインストールするため、何も入力せずに enter キーを押します。 151 | 152 | 以上で Rust のコンパイラのセットアップは完了です。 153 | 154 | その他の各実験に必要なものは、資料の途中で随時インストール手順を示すので、それに従ってください。 155 | -------------------------------------------------------------------------------- /00-setup/rust-vscode-terminal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/00-setup/rust-vscode-terminal.png -------------------------------------------------------------------------------- /00-setup/vscode-codelldb-config-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/00-setup/vscode-codelldb-config-01.png -------------------------------------------------------------------------------- /00-setup/vscode-codelldb-config-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/00-setup/vscode-codelldb-config-02.png -------------------------------------------------------------------------------- /00-setup/vscode-remote-dev-install-ext.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/00-setup/vscode-remote-dev-install-ext.png -------------------------------------------------------------------------------- /00-setup/vscode-remote-dev-ssh-config-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/00-setup/vscode-remote-dev-ssh-config-01.png -------------------------------------------------------------------------------- /00-setup/vscode-remote-dev-ssh-config-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/00-setup/vscode-remote-dev-ssh-config-02.png -------------------------------------------------------------------------------- /00-setup/vscode-remote-dev-ssh-config-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/00-setup/vscode-remote-dev-ssh-config-03.png -------------------------------------------------------------------------------- /00-setup/vscode-remote-dev-ssh-config-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/00-setup/vscode-remote-dev-ssh-config-04.png -------------------------------------------------------------------------------- /00-setup/vscode-remote-dev-ssh-config-05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/00-setup/vscode-remote-dev-ssh-config-05.png -------------------------------------------------------------------------------- /01-helloworld.md: -------------------------------------------------------------------------------- 1 | # とりあえず普通に Hello, world! 2 | 3 | とにもかくにも、まずは普通に Hello, world! しましょう。 4 | 5 | ## ビルドのためのツールをインストールする 6 | 7 | TBD 8 | 9 | ``` 10 | $ sudo apt update 11 | $ sudo apt install build-essential 12 | ``` 13 | 14 | ## パッケージをつくる 15 | 16 | **開発環境** のターミナルを開き、次のコマンドを入力してください。各業の `#` より後ろの部分はコマンドの意味を示すコメントであり、入力する必要はありません。 17 | 18 | ``` 19 | $ mkdir hello # hello という名前のディレクトリを作成 20 | $ cd hello # hello ディレクトリに移動 21 | ``` 22 | 23 | `hello` ディレクトリがどこにあるのか確認しておきましょう。 24 | 25 | コマンド: 26 | ``` 27 | $ pwd # 現在のディレクトリを表示 28 | ``` 29 | 30 | 出力: 31 | ``` 32 | /home/ubuntu/hello 33 | ``` 34 | 35 | 出力はあなたのユーザー名によって違うでしょう。いずれにしても、きっとホームディレクトリの中に作成されているはずです。 36 | 37 | 次に、この時点では `hello` ディレクトリにはなにもないことを確認しましょう。 38 | 39 | コマンド: 40 | ``` 41 | $ ls 42 | ``` 43 | 44 | なにも表示されないはずです。 45 | 46 | このまっさらなディレクトリに Rust のパッケージを作成するには次のコマンドを実行します。これは整地作業のようなものです。 47 | 48 | ``` 49 | $ cargo init # 現在のディレクトリ(つまり hello)に Rust のパッケージを作成 50 | ``` 51 | 52 | すると以下のような表示が出ます。 53 | 54 | ``` 55 | Created binary (application) package 56 | ``` 57 | 58 | 整地作業によってどんなファイルができているか確認しましょう。 59 | 60 | コマンド: 61 | ``` 62 | $ ls 63 | ``` 64 | 65 | 出力: 66 | ``` 67 | Cargo.toml src 68 | ``` 69 | 70 | コマンド: 71 | ``` 72 | $ ls src 73 | ``` 74 | 75 | 出力: 76 | ``` 77 | main.rs 78 | ``` 79 | 80 | いくつかのファイルとディレクトリができていることが確認できました。 81 | 82 | ファイルの中身を見るのは VS Code でパッケージディレクトリを開いてからにしましょう。 83 | 84 | ## VS Code で開く 85 | 86 | 開発環境に接続済みのウィンドウを開いてください。 87 | 88 | 次に、左のペインからエクスプローラタブを開き、`Open Folder` をクリックします。 89 | 90 | ![](./01-helloworld/open-folder-01.png) 91 | 92 | ディレクトリのパスを尋ねるプロンプトが開くはずです。はじめに `pwd` コマンドで確認したパスを入力し、末尾に `/` を追加してから `OK` をクリックします。 93 | 94 | ![](./01-helloworld/open-folder-02.png) 95 | 96 | 左のペインに先程 `ls` で確認したのと同様のファイルが見えていれば完了です。 97 | 98 | ![](./01-helloworld/open-folder-03.png) 99 | 100 | ## main.rs を読む 101 | 102 | 先程実行した `ls` で `src/` ディレクトリ以下に `main.rs` というファイルがあることがわかっています。 103 | 104 | `.rs` というのは Rust 言語で書かれたソースコードの拡張子です。 105 | 106 | Rust のパッケージでは、まず `src/main.rs` からプログラムを始めることになっています。 107 | 108 | ではこの `src/main.rs` を開いてみましょう。 109 | 110 | 左のペインからエクスプローラタブを開き、`src` ディレクトリ以下にある `main.rs` を選択します。 111 | 112 | ![](./01-helloworld/open-main.png) 113 | 114 | なんということでしょう。もう Hello, world! のコードが書かれているではありませんか。 115 | 116 | Rust では `cargo init` するだけで Hello, world! が完成しているのです。 117 | 118 | Hello, world! をするのが目的にもかかわらず、1行もコードを書かないうちにそれが完成していることに驚く気持ちはわかりますが、落ち着いてソースコードを丁寧に観察していきましょう。 119 | 120 | ```rust 121 | fn main() { 122 | println!("Hello, world!"); 123 | } 124 | ``` 125 | 126 | まず1行目の `fn main() {` では `main` 関数を定義していることがわかります。 127 | 128 | Rust でもC言語と同じく、プログラムは `main` という名前の関数から始まります。 129 | 130 | 二行目の `println!("Hello, world!");` は、どうやら Hello, world! を出力する命令のように見えます。 131 | 132 | さて `println!` というのはどういう構文でしょうか。関数名の最後に感嘆符が付いているように見えます。 133 | 134 | 実は Rust では、マクロ呼出しのときにマクロ名の末尾に感嘆符を付けます。これは関数呼び出しとマクロ呼出しを区別するためです。 135 | 136 | つまり、この `println!` は `println` というマクロを呼び出しているのです。 137 | 138 | マクロについてはここでは詳しく触れません。次のチャプターで詳しく見ていくことにします。 139 | 140 | `"Hello, world!"` については解説は不要でしょう。文字列リテラルです。 141 | 142 | そして、最後の `}` は `main` 関数を閉じているだけです。よいですね? 143 | 144 | ## Hello, world! する 145 | 146 | ソースコードも確認したところで、実際にプログラムを実行してみましょう。 147 | 148 | 実行するには **開発環境** のターミナルを開き、パッケージのディレクトリの中で次のコマンドを実行します。 149 | 150 | ``` 151 | $ cargo run 152 | ``` 153 | 154 | 出力: 155 | ``` 156 | Compiling hello v0.1.0 (/home/ubuntu/hello) 157 | Finished dev [unoptimized + debuginfo] target(s) in 0.33s 158 | Running `target/debug/hello` 159 | Hello, world! 160 | ``` 161 | 162 | Congrats! 🎉 163 | 164 | 無事に Hello, world! ができました。Rust ってなんて簡単なんでしょう。 165 | 166 | ## まとめ 167 | 168 | - Rust ではパッケージを作るだけで Hello, world! が完成している 169 | - `cargo run` で実行できる 170 | - Rust は簡単 171 | -------------------------------------------------------------------------------- /01-helloworld/open-folder-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/01-helloworld/open-folder-01.png -------------------------------------------------------------------------------- /01-helloworld/open-folder-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/01-helloworld/open-folder-02.png -------------------------------------------------------------------------------- /01-helloworld/open-folder-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/01-helloworld/open-folder-03.png -------------------------------------------------------------------------------- /01-helloworld/open-main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/01-helloworld/open-main.png -------------------------------------------------------------------------------- /02-macro.md: -------------------------------------------------------------------------------- 1 | # マクロは真っ黒 2 | 3 | ## 事前準備 4 | 5 | このチャプターでは `cargo-expand` というツールを使います。次の手順に進む前に、とりあえず先にこのコマンドを実行しましょう。 6 | そうすればきっといいことがありますよ。 7 | 8 | ``` 9 | rustup toolchain install nightly && cargo install cargo-expand 10 | ``` 11 | 12 | ※コマンドの終了を待たずに、次を読み進めてよい 13 | 14 | ## 定義を探して 15 | 16 | さて、先程見て見ぬふりをしたマクロに正面から向き合うことにしましょう。 17 | 18 | マクロとはつまり、コードを書き換えるルールのことです。 19 | 20 | マクロの呼び出しはそのルールに従って *展開* されます。つまり、コードが書き換わるのです。 21 | 22 | マクロはメタプログラミングの一種で、実行時に作用する関数呼び出しとは異なり、*コンパイル時* に作用します。 23 | 24 | マクロはコンパイル時に作用するコードの書き換えルールなのだとすれば、先程の `println!` にもそのルールの定義がどこかにあり、また書き換えられたあとの真の姿があるはずです。 25 | 26 | そうと決まれば、それを探しに行きましょう。 27 | 28 | 探すアテはあるのか? あります。公式のドキュメンテーションはあなたの味方です。Rust で迷子になったときはいつでも頼もしい地図となるでしょう。 29 | 30 | 外部のライブラリを一切導入した記憶はない(そもそもパッケージを作成しただけである)とするならば、`println!` の定義は標準ライブラリにあるのだろうと見当が付くでしょう。 31 | 32 | その予想は当たっており、`println!` について調べるには標準ライブラリのドキュメンテーションを開くのが正解です。 33 | 34 | [std - Rust](https://doc.rust-lang.org/std/) 35 | 36 | せっかくなので標準ライブラリのドキュメンテーションの使い方を練習してみましょう。 37 | 38 | まず上記リンクをウェブブラウザで開くと以下のようなページが表示されます。 39 | 40 | ![](./02-macro/rust-doc-01.png) 41 | 42 | この上部にある検索窓に、今探したいマクロの名前である `println` を入力します。 43 | 44 | ![](./02-macro/rust-doc-02.png) 45 | 46 | するとインクリメンタルサーチが行われ、下に検索結果が表示されます。 47 | 48 | `std::println` がお目当てのマクロですので、これを開きます。 49 | 50 | ![](./02-macro/rust-doc-03.png) 51 | 52 | 使い方の例などが表示されましたが、今知りたいのは具体的な定義ですので、右上の 53 |  `[src]` リンクをクリックして、ソースコードにジャンプします。 54 | 55 | ![](./02-macro/rust-doc-04.png) 56 | 57 | 定義にたどり着けました。 58 | 59 | ``` 60 | macro_rules! println { 61 | () => (print!("\n")); 62 | ($($arg:tt)*) => ({ 63 | $crate::io::_print(format_args_nl!($($arg)*)); 64 | }) 65 | } 66 | ``` 67 | 68 | 雰囲気で察するに、`std::io::_print` という関数の呼び出しに書き換える、というルールのようです。 69 | 70 | しかしまだ問題があります。マクロの定義の中にマクロ呼び出しがあります。`format_args_nl!` とはなんでしょうか。 71 | 72 | 次は `format_args_nl!` の定義を追いますか? 73 | 74 | ちょっと待ってください。マクロの定義は再帰的なため、マトリョーシカ人形のように中から次々にマクロ呼出しが出てくる可能性があります。 75 | 76 | このような反復的な作業は人間がやるべきではありません。コンピュータにやらせるべきです。 77 | 78 | もっとも、このケースでは雰囲気で Rust のコードを読み進めている我々よりも、コンパイラの方がよっぽど Rust のマクロ展開について詳しいのは明白ですから、人間がやる理由はほとんどありません。 79 | 80 | ## 真の姿 81 | 82 | ときに人間、このセクションの冒頭に書いてあったコマンドは実行しましたか? そしてその実行は完了していますか? 83 | 84 | `cargo-expand` を用いると、マクロをすべて展開した後の *真の姿* を簡単に調べることができます。 85 | 86 | (インストールコマンドの実行がまだ完了していない場合はそれを待ってから、)実行してみましょう。 87 | 88 | コマンド: 89 | ``` 90 | $ cargo expand 91 | ``` 92 | 93 | 出力: 94 | ``` 95 | Checking hello v0.1.0 (/home/ubuntu/hello) 96 | Finished dev [unoptimized + debuginfo] target(s) in 0.06s 97 | 98 | #![feature(prelude_import)] 99 | #![no_std] 100 | #[prelude_import] 101 | use ::std::prelude::v1::*; 102 | #[macro_use] 103 | extern crate std as std; 104 | fn main() { 105 | { 106 | ::std::io::_print(::std::fmt::Arguments::new_v1(&["Hello, world!\n"], 107 | &match () { 108 | () => [], 109 | })); 110 | }; 111 | } 112 | ``` 113 | 114 | ジャジャーン。 115 | 116 | 真の姿を見せました。`fn main() {` より上に書いてある呪文は無視しましょう。ここで真面目に取り合ってもロクなことにならないからです。 117 | 118 | 大切なのは `main` 関数の中です。`println!` マクロ呼出しは `::std::io::_print` や `::std::fmt::Arguments::new_v1` といった関数の呼び出しに書き換えられるようです。 119 | 120 | このように、マクロの定義を追うのは一苦労です。マクロには、普通の関数にはない特別なパワーがありますが、その例外的な強力さ故にわかりづらくなってしまいます。 121 | 122 | そのため、抽象化のためにマクロを用いるのは最終手段にするのがよいでしょう。諸刃の剣ともなりうる切り札は最後までとっておくものです。 123 | 124 | ## まとめ 125 | 126 | - マクロの定義を追うのは面倒 127 | - `cargo-expand` を使うと真の姿を簡単に暴ける 128 | - マクロは最終手段の黒魔術 129 | -------------------------------------------------------------------------------- /02-macro/rust-doc-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/02-macro/rust-doc-01.png -------------------------------------------------------------------------------- /02-macro/rust-doc-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/02-macro/rust-doc-02.png -------------------------------------------------------------------------------- /02-macro/rust-doc-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/02-macro/rust-doc-03.png -------------------------------------------------------------------------------- /02-macro/rust-doc-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/02-macro/rust-doc-04.png -------------------------------------------------------------------------------- /03-function.md: -------------------------------------------------------------------------------- 1 | # 関数呼び出し 2 | 3 | さぁ、お絵かきの時間です。算数の時間かもしれません。いずれにしても、未知なものの正体を解き明かそうとするとき、想像力は大切です。 4 | 5 | 抽象的な言葉で遊ぶのはこれくらいにして、ゲームのルールを説明しましょう。 6 | 7 | このゲームではまず、簡単な Rust のコードが与えられます。そして、あなたはそれの動きを一種の図で可視化してください答えてください。 8 | 9 | ## 例題1 10 | 11 | ```rust 12 | fn main() { 13 | let x = f(1); 14 | } 15 | 16 | fn f(n: i32) -> i32 { 17 | n + 2 18 | } 19 | ``` 20 | 21 | 見ての通り、`f(n)` は引数に `2` を足した数を返す関数です。 22 | 23 | (`i32` が気になりますか? ただの符号付き32bit整数の型名です) 24 | 25 | そして、`main` 関数はそれに `1` を渡して、戻り値を `x` に代入しています。 26 | 27 | つまり、`1` に `2` を足して `3` を `x` に代入しているということになります。 28 | 29 | おっと、求められている答えは `3` ではなく、**図** でした。 30 | 31 | この場合の解答は、次のようになります。 32 | 33 | ![](03-function/fn-diag-01.png) 34 | 35 | ## 例題2 36 | 37 | ルールを理解するために、もう少し練習してみましょう。 38 | 39 | ```rust 40 | fn main() { 41 | let x = f(1); 42 | let y = f(x); 43 | } 44 | 45 | fn f(n: i32) -> i32 { 46 | n + 2 47 | } 48 | ``` 49 | 50 | この問題の解答は次のようになります。 51 | 52 | ![](03-function/fn-diag-02.png) 53 | 54 | 察しがついてきましたか? 55 | 56 | 解答の図の書き方は以下のとおりです。 57 | 58 | 1. `main` 関数の実行から始まる 59 | 2. 関数の実行は、関数名と、括弧で囲まれた引数の値と、下線によって表現される 60 | 3. 関数の呼び出し順は先のものが左、後のものが右になる 61 | 4. 関数呼び出しは斜め右下向きの矢印で表現される 62 | 5. 関数の戻りは斜め右上向きの矢印で表現される 63 | 6. 関数の戻り値は、関数の戻りの矢印の右に書く 64 | 7. 関数の下線は、呼び出した関数が戻ってくるまで伸びていなければならない 65 | 66 | ## 問題 67 | 68 | ゲームのルールを理解したところで、次の問題を解いてみてください。 69 | 70 | ```rust 71 | fn main() { 72 | let x = f(1); 73 | let y = g(x); 74 | } 75 | 76 | fn f(n: i32) -> i32 { 77 | n + 2 78 | } 79 | 80 | fn g(n: i32) -> i32 { 81 | let x = a(n); 82 | let y = b(n); 83 | x + y 84 | } 85 | 86 | fn a(n: i32) -> i32 { 87 | n * 2 88 | } 89 | 90 | fn b(n: i32) -> i32 { 91 | let x = f(n); 92 | a(x) 93 | } 94 | ``` 95 | 96 | 正解の図はリンク先に置いておきます。解けたら答え合わせをしてみてくださいね。 97 | 98 | [正解の図](./03-function/fn-diag-ans.png) 99 | 100 | ## まとめ 101 | 102 | この図からは大切なことがいくつか読み取れるのですが、それらについてまとめるのはまた別の機会としましょう。 103 | -------------------------------------------------------------------------------- /03-function/fn-diag-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/03-function/fn-diag-01.png -------------------------------------------------------------------------------- /03-function/fn-diag-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/03-function/fn-diag-02.png -------------------------------------------------------------------------------- /03-function/fn-diag-ans.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/03-function/fn-diag-ans.png -------------------------------------------------------------------------------- /04-detective.md: -------------------------------------------------------------------------------- 1 | # 名探偵 Hello, world! 2 | 3 | 準備運動はもう十分できたでしょうから、そろそろ本題に入りましょう。 4 | 5 | 名探偵 Hello, world! の出番ですよ。 6 | 7 | ## 捜査のゴール 8 | 9 | 本資料の目的は、「"Hello, world!" の動きを深掘り」することです。ただし、「深掘り」ではちょっと曖昧なので、どのあたりまで掘るかを決めることにしましょう。 10 | 11 | `println!()` を分解していけば、どこかに "Hello, world!" の一部または全部を出力する不可分な処理があるはずだ、という予想がつきます。 12 | 13 | 一部または全部とは、まずは先頭一文字 "H" のみが出力されるかもしれないし、またはいっぺんに "Hello, world!" と出力されるかもしれない、ということです。 14 | 15 | 不可分な処理とは、より直感的(しかし不正確)には、その1行の前では何も出力されていないが、その1行を超えた瞬間に何かが出力されているような1行ということです。 16 | 17 | 真犯人とも言うべきその1行を突き止めることができれば、まぁまぁ深掘りしたと言えるでしょう。(言えませんか?) 18 | 19 | ```rust 20 | // ここではなにも出力されてないが 21 | ???不可分な処理??? // ←この行を特定する 22 | // ここではなにかが出力されている 23 | ``` 24 | 25 | というわけで、半ば強引ではありますが、その「不可分な処理」を特定することを今回の捜査のゴールとしましょう。 26 | 27 | ## 捜査の方針 28 | 29 | ゴールが決まったところで、捜査の方針を考えましょう。 30 | 31 | 真犯人たる「不可分な処理」というのが、`println!()` の呼び出しの中にどのように潜んでいるかを予想してみます。 32 | 33 | 先程のチャプターでの図の書き方を真似すると: 34 | 35 | ![](./04-detective/criminal-in-fn-call.png) 36 | 37 | こんな感じで潜んでいるはずです。 38 | 39 | ここからどうやって犯人の居場所を絞り込めるでしょうか。 40 | 41 | たとえば、すべての関数呼び出しの前後で出力を比較すれば、少なくとも真犯人を匿っている関数呼び出しは特定できそうです。 42 | 43 | そんな都合よく捜査ができるのかって? 実はデバッガというツールを使うとそれが可能なのです。 44 | 45 | そうとわかれば早速捜査開始です。 46 | 47 | ## まとめ 48 | 49 | - Hello, world! の一部または全部を出力する不可分な処理を見つけるのがゴール 50 | - デバッガを使うとその不可分な処理の在り処を絞り込める(らしい) 51 | -------------------------------------------------------------------------------- /04-detective/criminal-in-fn-call.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/04-detective/criminal-in-fn-call.png -------------------------------------------------------------------------------- /05-debugger.md: -------------------------------------------------------------------------------- 1 | # むしとりしょうねん 2 | 3 | このチャプターに麦わら帽子は要りません。必要なのはデバッガです。 4 | 5 | 実は、デバッガは環境構築のチャプターで既にインストール済みです。 6 | 7 | ただし、デバッガを起動するための設定が足りません。 8 | 9 | ## デバッガの設定 10 | 11 | まず左のペインで、いかにも虫が取れそうなアイコンのデバッグタブを開き、続いてデバッグの設定アイコンをクリックします。 12 | 13 | ![](./05-debugger/codelldb-launch-01.png) 14 | 15 | すると、デバッガのタイプを選択するダイアログが開くため、`LLDB` を選択します。 16 | 17 | ![](./05-debugger/codelldb-launch-02.png) 18 | 19 | 気を利かせて、設定を自動生成するかどうか尋ねるダイアログ開きます。ご厚意に甘えて `Yes` をクリックします。 20 | 21 | ![](./05-debugger/codelldb-launch-03.png) 22 | 23 | デバッガの起動設定が生成されました。 24 | 25 | 正しく生成されない場合は以下の内容を `.vscode/launch.json` に貼り付けてください。 26 | 27 | ``` 28 | { 29 | // Use IntelliSense to learn about possible attributes. 30 | // Hover to view descriptions of existing attributes. 31 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 32 | "version": "0.2.0", 33 | "configurations": [ 34 | { 35 | "type": "lldb", 36 | "request": "launch", 37 | "name": "Debug executable 'hello'", 38 | "cargo": { 39 | "args": [ 40 | "build", 41 | "--bin=hello", 42 | "--package=hello" 43 | ], 44 | "filter": { 45 | "name": "hello", 46 | "kind": "bin" 47 | } 48 | }, 49 | "args": [], 50 | "cwd": "${workspaceFolder}" 51 | }, 52 | { 53 | "type": "lldb", 54 | "request": "launch", 55 | "name": "Debug unit tests in executable 'hello'", 56 | "cargo": { 57 | "args": [ 58 | "test", 59 | "--no-run", 60 | "--bin=hello", 61 | "--package=hello" 62 | ], 63 | "filter": { 64 | "name": "hello", 65 | "kind": "bin" 66 | } 67 | }, 68 | "args": [], 69 | "cwd": "${workspaceFolder}" 70 | } 71 | ] 72 | } 73 | ``` 74 | 75 | ![](./05-debugger/codelldb-launch-04.png) 76 | 77 | 起動設定のタブを閉じ、`main.rs` のタブに戻ります。そして、左ペインの実行ボタンをクリックします。 78 | 79 | ![](./05-debugger/codelldb-launch-05.png) 80 | 81 | すると、プログラムが実行され、下のペインに出力が表示されます。 82 | 83 | ![](./05-debugger/codelldb-launch-06.png) 84 | 85 | デバッガによる出力が混ざっていますが、たしかに "Hello, world!" が出力されています。 86 | 87 | ## ブレークポイント 88 | 89 | デバッガの最大の特徴は、プログラムの実行を途中で一時停止できることです。 90 | 91 | プログラムの実行を一時停止するには、一時停止したい行にブレークポイントを貼ります。 92 | 93 | ブレークポイントを貼るには、行番号の左側の部分をクリックします。 94 | 95 | ![](./05-debugger/codelldb-brk-01.png) 96 | 97 | そして、先ほどと同様に実行ボタンをクリックします。 98 | 99 | すると、プログラムはブレークポイントが貼られた行の直前で一時停止します。 100 | (つまり、停止したときにはその行はまだ実行されていない) 101 | 102 | ![](./05-debugger/codelldb-brk-02.png) 103 | 104 | この場合、`println!` の行はまだ実行されていないため、下のペインの出力には `Hello, world!` の文字はありません。 105 | 106 | ここで、実行を再開するには、左のペインの実行ボタンではなく、画面上部に浮いているツールバーの青い再開ボタンをクリックします。 107 | 108 | ![](./05-debugger/codelldb-brk-03.png) 109 | 110 | 実行が再開し、完了します。そしてまた、下のペインに `Hello, world!` が出力されているのが確認できます。 111 | 112 | ![](./05-debugger/codelldb-brk-04.png) 113 | 114 | ブレークポイントは複数貼ることもできます。その場合は実行を再開する度に、次のブレークポイントで停止します。 115 | 116 | ## ステップオーバー・ステップイン・ステップアウト 117 | 118 | ブレークポイント等で停止したところからそのまま実行を再開するのではなく、細かな単位で少しずつ実行を進めることができます。 119 | 120 | 細かく実行を進める機能には3つの種類がありますが、それぞれの動きについては言葉で説明するより図で説明するほうがわかりやすいでしょう。 121 | 122 | ![](./05-debugger/step-in-out-over.png) 123 | 124 | チャプター3で練習したみなさんなら即座に理解できるでしょう。 125 | 126 | ## まとめ 127 | 128 | - デバッガを使うとプログラムの実行を途中で止められる 129 | - ブレークポイントを貼ることで一時停止場所を設定できる 130 | - ステップオーバー・ステップイン・ステップアウトで少しずつ実行できる 131 | -------------------------------------------------------------------------------- /05-debugger/codelldb-brk-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/05-debugger/codelldb-brk-01.png -------------------------------------------------------------------------------- /05-debugger/codelldb-brk-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/05-debugger/codelldb-brk-02.png -------------------------------------------------------------------------------- /05-debugger/codelldb-brk-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/05-debugger/codelldb-brk-03.png -------------------------------------------------------------------------------- /05-debugger/codelldb-brk-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/05-debugger/codelldb-brk-04.png -------------------------------------------------------------------------------- /05-debugger/codelldb-launch-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/05-debugger/codelldb-launch-01.png -------------------------------------------------------------------------------- /05-debugger/codelldb-launch-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/05-debugger/codelldb-launch-02.png -------------------------------------------------------------------------------- /05-debugger/codelldb-launch-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/05-debugger/codelldb-launch-03.png -------------------------------------------------------------------------------- /05-debugger/codelldb-launch-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/05-debugger/codelldb-launch-04.png -------------------------------------------------------------------------------- /05-debugger/codelldb-launch-05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/05-debugger/codelldb-launch-05.png -------------------------------------------------------------------------------- /05-debugger/codelldb-launch-06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/05-debugger/codelldb-launch-06.png -------------------------------------------------------------------------------- /05-debugger/step-in-out-over.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/05-debugger/step-in-out-over.png -------------------------------------------------------------------------------- /06-step-by-step.md: -------------------------------------------------------------------------------- 1 | # 一歩ずつ 2 | 3 | ## 捜査は足で 4 | 5 | 前のチャプターで、デバッガを使えばプログラムを少しずつ実行できるということを学びました。 6 | 7 | とくに、ステップインを使えば、とにかくすべての処理を1つずつ飛ばさずに実行できるということがわかりました。 8 | 9 | つまり、ステップインですべての処理を1つずつ実行しながら、その前後で出力に変化があるかどうかを確認すれば、真犯人を見つけることができそうですね! 10 | 11 | まずはブレークポイントを貼ります。 12 | 13 | ![](./06-step-by-step/step-01.png) 14 | 15 | そしてステップイン。 16 | 17 | ![](./06-step-by-step/step-02.png) 18 | 19 | まだ変化なし。 20 | 21 | ステップイン。 22 | 23 | ![](./06-step-by-step/step-03.png) 24 | 25 | まだ変化なし。 26 | 27 | ステップイン。 28 | 29 | ![](./06-step-by-step/step-04.png) 30 | 31 | まだ変化なし。 32 | 33 | ステップイン。 34 | 35 | ![](./06-step-by-step/step-05.png) 36 | 37 | まだ変化なし。 38 | 39 | ステップイン。 40 | 41 | ![](./06-step-by-step/step-06.png) 42 | 43 | まだ変化なし。 44 | 45 | ステップイン。 46 | 47 | ![](./06-step-by-step/step-07.png) 48 | 49 | まだ変化なし。 50 | 51 | ステップイン。 52 | 53 | ![](./06-step-by-step/step-08.png) 54 | 55 | まだ変化なし。 56 | 57 | ステップイン。 58 | 59 | ![](./06-step-by-step/step-09.png) 60 | 61 | まだ変化なし。 62 | 63 | ステップイン。 64 | 65 | ![](./06-step-by-step/step-10.png) 66 | 67 | まだ変化なし。 68 | 69 | ステップイン。 70 | 71 | ![](./06-step-by-step/step-11.png) 72 | 73 | まだ変化なし。 74 | 75 | ステップイン。 76 | 77 | ![](./06-step-by-step/step-12.png) 78 | 79 | まだ変化なし。 80 | 81 | 82 | ステップイン。 83 | 84 | ![](./06-step-by-step/step-13.png) 85 | 86 | まだ変化なし。 87 | 88 | 89 | ステップイン。 90 | 91 | ![](./06-step-by-step/step-14.png) 92 | 93 | まだ変化なし。 94 | 95 | …… 96 | 97 | 果たしてこの作業はいつ終わるのでしょうか。 98 | 99 | わたしたちは一体何ステップ実行すれば真犯人にたどり着けるのでしょうか。 100 | 101 | 以前にも一度、似たようなことを言ったような気がしますが、こういう作業は人間がやるべきではありません。 102 | 103 | 「退屈なことはPythonにやらせよう」というやつです。 104 | 105 | ## 退屈なことはPythonにやらせよう 106 | 107 | 今使っているこのデバッガの正体は LLDB というものです。 108 | 109 | 今までポチポチしてきた VS Code の画面は本当にただの画面にすぎず、デバッガの実体である LLDB を間接的に操作しているだけです。 110 | 111 | さてこの LLDB、実は他にも操作する方法があります。それは Python による方法です。 112 | 113 | なんと、Python によってデバッガの操作ができるため、先程のような退屈な操作を自動化することができます。 114 | 115 | ここで、さぁ Python でスクリプトを書いてみましょう、というのはあまりに難易度が高すぎるため、筆者の書いたスクリプトを貼っておきます。 116 | 117 | ``` 118 | import lldb 119 | 120 | exe = "target/debug/hello" 121 | 122 | dbg = lldb.SBDebugger.Create() 123 | dbg.SetAsync(False) 124 | 125 | dbg.HandleCommand("settings set target.source-map /rustc/3c235d5600393dfe6c36eeed34042efad8d4f26e/src/ /home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/") 126 | dbg.HandleCommand('settings set frame-format frame "frame #${frame.index}: ${frame.pc}{ ${module.file.basename}{`${function.name-with-args}{${frame.no-debug}${function.pc-offset}}}}{ at ${line.file.fullpath}:${line.number}}{${function.is-optimized} [opt]}\n"') 127 | 128 | target = dbg.CreateTarget(exe) 129 | launch_info = lldb.SBLaunchInfo([exe]) 130 | breakpoint = target.BreakpointCreateBySourceRegex( 131 | 'Hello, world!', lldb.SBFileSpec("main.rs")) 132 | error = lldb.SBError() 133 | process = target.Launch(launch_info, error) 134 | 135 | dbg.HandleCommand("f") 136 | 137 | thread = process.GetThreadAtIndex(0) 138 | out = "" 139 | while len(out) == 0 and process.GetState() != lldb.eStateExited: 140 | thread.StepInto() 141 | out = process.GetSTDOUT(1024) 142 | 143 | dbg.HandleCommand("bt") 144 | dbg.HandleCommand("f") 145 | ``` 146 | 147 | このスクリプトを実行するためには少々面倒な環境設定が必要なため、ここでは実行結果を示すに留めることとします。 148 | 149 | 自分で実行してみたい人は、あとできっと用意されるであろう付録を参照してください。 150 | 151 | ``` 152 | frame "frame #0: 0x0000555555557cd7 hello`hello::main::h796ecd7574dcc3b0 at /home/ubuntu/hello/src/main.rs:2 153 | " 1 fn main() { 154 | -> 2 println!("Hello, world!"); 155 | 3 } 156 | * thread #1, name = 'hello', stop reason = step in 157 | * frame "frame #0: 0x000055555555af1c hello`flush_buf> [inlined] write at /home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/./libstd/sys/unix/fd.rs:110 158 | " frame "frame #1: 0x000055555555af07 hello`flush_buf> [inlined] write at /home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/./libstd/sys/unix/stdio.rs:28 159 | " frame "frame #2: 0x000055555555af07 hello`flush_buf> [inlined] write at /home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/./libstd/io/stdio.rs:84 160 | " frame "frame #3: 0x000055555555af07 hello`flush_buf> [inlined] write at /home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/./libstd/io/stdio.rs:100 161 | " frame "frame #4: 0x000055555555af07 hello`flush_buf> at /home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/./libstd/io/buffered.rs:494 162 | " frame "frame #5: 0x000055555555bcb1 hello`write [inlined] flush> at /home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/./libstd/io/buffered.rs:628 163 | " frame "frame #6: 0x000055555555bca9 hello`write [inlined] flush> at /home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/./libstd/io/buffered.rs:976 164 | " frame "frame #7: 0x000055555555bca9 hello`write [inlined] write> at /home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/./libstd/io/buffered.rs:960 165 | " frame "frame #8: 0x000055555555bc98 hello`write at /home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/./libstd/io/stdio.rs:499 166 | " frame "frame #9: 0x000055555555c49f hello`write_all at /home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/./libstd/io/mod.rs:1208 167 | " frame "frame #10: 0x000055555555cabb hello`write_str at /home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/./libstd/io/mod.rs:1268 168 | " frame "frame #11: 0x00005555555741fb hello`write at /home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/./libcore/fmt/mod.rs:1033 169 | " frame "frame #12: 0x000055555555b961 hello`write_fmt [inlined] write_fmt at /home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/./libstd/io/mod.rs:1279 170 | " frame "frame #13: 0x000055555555b920 hello`write_fmt at /home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/./libstd/io/stdio.rs:493 171 | " frame "frame #14: 0x000055555555c099 hello`_print [inlined] {{closure}} at /home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/./libstd/io/stdio.rs:737 172 | " frame "frame #15: 0x000055555555c045 hello`_print [inlined] try_with>>,closure,core::result::Result<(), std::io::error::Error>> at /home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/./libstd/thread/local.rs:299 173 | " frame "frame #16: 0x000055555555bf5c hello`_print [inlined] print_to at /home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/./libstd/io/stdio.rs:731 174 | " frame "frame #17: 0x000055555555bf5c hello`_print at /home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/./libstd/io/stdio.rs:753 175 | " frame "frame #18: 0x0000555555557cf4 hello`hello::main::h796ecd7574dcc3b0 at /home/ubuntu/hello/src/main.rs:2 176 | " frame "frame #19: 0x0000555555557e30 hello`std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::h9ff2a3ce32f1f5df at /home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/./libstd/rt.rs:64 177 | " frame "frame #20: 0x0000555555561d33 hello`do_call [inlined] {{closure}} at /home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/./libstd/rt.rs:49 178 | " frame "frame #21: 0x0000555555561d27 hello`do_call at /home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/./libstd/panicking.rs:293 179 | " frame "frame #22: 0x00005555555638ca hello`__rust_maybe_catch_panic at /home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/./libpanic_unwind/lib.rs:87 180 | " frame "frame #23: 0x00005555555627ed hello`lang_start_internal [inlined] try at /home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/./libstd/panicking.rs:272 181 | " frame "frame #24: 0x00005555555627af hello`lang_start_internal [inlined] catch_unwind at /home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/./libstd/panic.rs:388 182 | " frame "frame #25: 0x00005555555627af hello`lang_start_internal at /home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/./libstd/rt.rs:48 183 | " frame "frame #26: 0x0000555555557e09 hello`std::rt::lang_start::h869673eb9744a958(main=(hello`hello::main::h796ecd7574dcc3b0 at main.rs:1), argc=2, argv=0x00007fffffffee18) at /home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/./libstd/rt.rs:64 184 | " frame "frame #27: 0x0000555555557d2a hello`main + 42 185 | " frame "frame #28: 0x00007ffff71c2b97 libc.so.6`__libc_start_main(main=(hello`main), argc=2, argv=0x00007fffffffee18, init=, fini=, rtld_fini=, stack_end=0x00007fffffffee08) at /build/glibc-OTsEL5/glibc-2.27/csu/../csu/libc-start.c:310 186 | " frame "frame #29: 0x0000555555557bca hello`_start + 42 187 | "frame "frame #0: 0x000055555555af1c hello`flush_buf> [inlined] write at /home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/./libstd/sys/unix/fd.rs:110 188 | " 107 } 189 | 108 190 | 109 pub fn write(&self, buf: &[u8]) -> io::Result { 191 | -> 110 let ret = cvt(unsafe { 192 | 111 libc::write(self.fd, 193 | 112 buf.as_ptr() as *const c_void, 194 | 113 cmp::min(buf.len(), max_len())) 195 | ``` 196 | 197 | ちなみに、ここまで到達するには456ステップが必要だったようです。Python にやらせて正解でしたね。 198 | 199 | ## 真犯人を観察する 200 | 201 | Python が突き止めてくれた結果によれば、犯人は以下の場所の付近にいるようです。 202 | 203 | ``` 204 | /home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/./libstd/sys/unix/fd.rs:110 205 | ``` 206 | 207 | この場所は「何かが出力された直後」の位置ですから、真犯人はこの直前の呼出のあたりにいるはずです。 208 | 209 | 真相に迫るため、VS Code で当該のコードを開きましょう。 210 | 211 | 左のペインでエクスプローラタブを開き、右クリックして `Add Folder to Workspace` をクリックします。 212 | 213 | そして、以下のパスを入力し、開きます。 214 | 215 | ``` 216 | /home/ubuntu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/ 217 | ``` 218 | -------------------------------------------------------------------------------- /06-step-by-step/step-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/06-step-by-step/step-01.png -------------------------------------------------------------------------------- /06-step-by-step/step-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/06-step-by-step/step-02.png -------------------------------------------------------------------------------- /06-step-by-step/step-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/06-step-by-step/step-03.png -------------------------------------------------------------------------------- /06-step-by-step/step-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/06-step-by-step/step-04.png -------------------------------------------------------------------------------- /06-step-by-step/step-05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/06-step-by-step/step-05.png -------------------------------------------------------------------------------- /06-step-by-step/step-06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/06-step-by-step/step-06.png -------------------------------------------------------------------------------- /06-step-by-step/step-07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/06-step-by-step/step-07.png -------------------------------------------------------------------------------- /06-step-by-step/step-08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/06-step-by-step/step-08.png -------------------------------------------------------------------------------- /06-step-by-step/step-09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/06-step-by-step/step-09.png -------------------------------------------------------------------------------- /06-step-by-step/step-10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/06-step-by-step/step-10.png -------------------------------------------------------------------------------- /06-step-by-step/step-11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/06-step-by-step/step-11.png -------------------------------------------------------------------------------- /06-step-by-step/step-12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/06-step-by-step/step-12.png -------------------------------------------------------------------------------- /06-step-by-step/step-13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/06-step-by-step/step-13.png -------------------------------------------------------------------------------- /06-step-by-step/step-14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOBA789/helloworld-deep-dive-in-rust/1da04037a22e0654595b429b3955c589d61364ad/06-step-by-step/step-14.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rust で学ぶ "Hello, world!" 2 | 3 | 本資料では、プログラミング言語 Rust で書かれた "Hello, world!" の動きを深掘りします。 4 | 5 | 一見とても簡単に見える "Hello, world!" の裏側を知ることで、自分で書いたプログラムを動かすために、CPU やメモリ、Linux カーネルがどのように活躍しているかを学びます。 6 | --------------------------------------------------------------------------------