Open6

VSCodeを使ってRustのデバッグを行う方法

kutokuto

普段はPythonを使うことが多いが、Rustの場合VSCodeでdebugをする方法が少し異なったのでメモする。

前提

  • RustのVSCode実行環境が整っていること
kutokuto

1. 拡張機能CodeLLDBをインストール

pythonの場合は、pythonの拡張機能にpython debuggerが含まれているがRustの場合別で拡張機能を入れる必要がある。以下の拡張機能をインストールする。

kutokuto

2. launch.jsonファイルを作成

VSCodeの左側のRun and Debugタブを選択しcreate a launch.json fileをクリックしLLDBを選択する。

プロジェクト配下にCargo.tomlがあればそれに従って設定ファイルを自動で作成してくれるのでYesを選択。

すると以下のようなlaunch.jsonファイルが自動で作成される
--binや--packageはCargo.tomlの内容で変わる。

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "lldb",
            "request": "launch",
            "name": "Debug executable 'main'",
            "cargo": {
                "args": [
                    "build",
                    "--bin=main",
                    "--package=ahc-template"
                ],
                "filter": {
                    "name": "main",
                    "kind": "bin"
                }
            },
            "args": [],
            "cwd": "${workspaceFolder}"
        },
        {
            "type": "lldb",
            "request": "launch",
            "name": "Debug unit tests in executable 'main'",
            "cargo": {
                "args": [
                    "test",
                    "--no-run",
                    "--bin=main",
                    "--package=ahc-template"
                ],
                "filter": {
                    "name": "main",
                    "kind": "bin"
                }
            },
            "args": [],
            "cwd": "${workspaceFolder}"
        }
    ]
}
kutokuto

(memo) debuggerで標準入力が受け取れない場合の対処法

通常のRustの実行であれば準備はこれだけで良い。
競プロで利用する場合、標準入力を読み込む必要があるためそこについて補足する。

rustで標準入力を受け取る場合以下のようにコマンドライン引数でファイルを渡す。
cargo run --bin=main < ./input/0000.txt
そのためlaunch.jsonファイルのargs部分を修正すればできそうな気がするのだがうまくいかなかった。

Rustのdebuggerで標準入力を受け取る方法がわかった。これの下のスクラップに方法を記載しているのでそっちの方が簡単に実現できる。こちらはメモとして残しておく

ここではコマンドライン引数による標準入力は使わずコード側で入力ファイルを直接読み込む方法を取っている。
具体的には以下の変更をする。

1. コード側の変更

通常時とdebug時でコードを分岐することをやりたいのでcfg!マクロを利用する。
https://doc.rust-jp.rs/rust-by-example-ja/attribute/cfg.html

まずCargo.tomlに以下の設定を追加することで"debug"というフラグをコード中で使えるようにする。この文字列はなんでも良い。

[features]
debug = []

コード中で以下のようにcfgマクロを利用することで"debug"というフラグがコマンドライン引数で付与されている場合には処理を分岐することができる。

use proconio::input;

fn main() {
    let input = if cfg!(feature = "debug") {
        local_parse_input("./input/0000.txt")
    } else {
        parse_input()
    };
}

通常時はコマンドライン引数から標準入力を受け付けるためinput!でそのまま受け取り、debug時は指定したファイルパスからファイルの中身を直接読み込むようにしている。

pub fn local_parse_input(file_path: &str) -> usize {
    // 以下はdebug時に使用
    let input = std::fs::read_to_string(file_path).unwrap_or_else(|_| {
        eprintln!("no such file: {}", file_path);
        std::process::exit(1)
    });
    let f = proconio::source::once::OnceSource::from(&input[..]);
    // ここはファイル内容による
    input! {
        from f,
        N: usize
    }
    N
}
pub fn parse_input() -> usize {
    // ここはファイル内容による
    input! {
        N: usize,
    }
    N
}

2. launch.jsonファイルの変更

cfgマクロはコマンドライン引数で--features=debugのように渡された場合のみ有効となる。
VSCodeでdebugをする際は常にdebugモードで実行したいため、あらかじめlaunch.jsonファイルのargsに引数として--feature=debugを渡しておく。こうしておくことでdebuggerを利用する際は常にfeature="debug"のコードが自動で選択され実行される。

"cargo": {
    "args": [
        "build",
        "--bin=main",
        "--package=ahc-template"
        "--features=debug"  // debug mode これを追加
    ],
},
kutokuto

3. debuggerで標準入力を受け取る(オプション)

標準入力をdebug時に受け取る方法がわかったのでメモ
CodeLLDBのドキュメントに記載があった。
https://github.com/vadimcn/codelldb/blob/master/MANUAL.md#stdio-redirection

結論としてlaunch.jsonファイルにstdioを使って以下のように入力ファイルを指定してやればいい。
これをすれば上記のcfgマクロを使う方法は不要。こっちが本来やりたかったことなのでこちらを採用する。

    "configurations": [
        {
            "type": "lldb",
            "request": "launch",
            "name": "Debug executable 'main'",
            "cargo": {
                "args": [
                    "build",
                    "--bin=main",
                    "--package=ahc-template",
                    // "--features=debug"  // debug mode
                ],
                "filter": {
                    "name": "main",
                    "kind": "bin"
                },
            },
            "args": [],
            "cwd": "${workspaceFolder}",
            // これを追加
            // 標準入力をファイルから受け取るための設定
            "stdio": [
                "path/to/_input_file.txt",
                null,
            ]
        },
kutokuto

4. Debug実行

あとはdebugしたいファイルを開いてbraekpointなどを設定してdebug実行(F5)をすれば良い。
使用感はpython debuggerとおおよそ同じだが一点異なる点としてDEBUG CONSOLEの使い方がある。
DEBUG CONSOLEとはdebug実行時にターミナルの隣に出てくるタブである。

debug時にはDEBUG CONSOLEでなんらかの処理を記述してその結果を見たいケースがある。
pythonであれば処理をそのまま書けばその結果が表示されるが、LLDBを利用する場合は以下のようにprintを冒頭につける必要がある。

ちゃんと確認できていないが、Vec型の変数の中身をindexを指定して見ようとすると変数値が見れずポインタが表示されたので別の方法を取る必要があるかもしれない。