WSL&VScodeでデバッガを使った話(C++)

<a id="mokuji"></a>
## 目次
- [使ってみた結果](#使ってみた結果)
- [gdbをインストールしよう！](#gdbをインストールしよう)
- [VScodeで遊んでみよう！](#vscodeで遊んでみよう)
- [STLの表示](#stlの表示)

<br>

### 使ってみた結果

デバッガの機能で変数が目に見えてわかるので、丁寧にデバッグしたいときに良い効果を発揮すると思います。

<br>

### gdbをインストールしよう！
僕はgdbはなんぞや？ってなったのでそこから話していこうと思います。

- [はじめてのgdb](https://qiita.com/arene-calix/items/a08363db88f21c81d351)

実はこちらのサイト↑に載っているんですが、簡単に言うとgccがコンパイラでgdbがデバッガです。gdbにはいろんな機能があって、例えばステップ実行とか関数の呼び出しがどうなっているかとかいろんなことが分かります。便利ですね。

僕のWSLでは`find /* -name *gdb*`をしてもめぼしいものが見当たらなかったので、gdbをインストールするところから始めました。

実は2通りの手順があって、

```bash
$ sudo apt-get install gdb
```
とするのと以下に書く`make`コマンドを使ったやり方があります。個人的には上記のやり方のほうがかかる時間が短いのでおすすめです。

- [gdbを使ってCのデバッグを行うメモ](https://qiita.com/edo_m18/items/fee0ab976bf9181f5712)

`make`コマンドを使ったやり方はこちらのサイト↑に載っています。  
実際に私が実行した手順だけ書くと

```bash
$ sudo -i
```
これでroot権限になったあとに

```bash
$ grep '^deb ' /etc/apt/sources.list | sed 's/^deb/deb-src/g' > /etc/apt/sources.list.d/deb-src.list
```

```bash
$ sudo apt update -y
```
上記のコマンドでapt sourceでソースコードをインストールする準備ができました。
続いて、以下のコマンド達を実行します。 __`#`以降の文はコメントを表しています。__

```bash
$ sudo apt-get build-dep gdb
$ sudo apt-get source gdb #rootディレクトリにインストールされてたら好きなディレクトリに移動させましょう
$ cd gdb-9.2 # 適宜、DLされたバージョンに置き換えてください
$ mkdir build
$ cd build
$ ../configure --enable-tui=yes
$ make
# grab a coffee
$ sudo make install
```
`make`中とても長い待ち時間だったと思います。
参考になったサイトでもおっしゃってたんですけど、`# grab a coffee` みたいな遊び心は僕もとても好きです。

ひとまず、長いインストールお疲れ様でした。これでgdbがインストールできていると思います。

<br>

### VScodeで遊んでみよう！
さて、お手元のVScodeを起動してください。環境はVScodeのWSLでリモート接続してあることを想定しています。
試しに次のようなsample.cppをデバッグしてみます。

```cpp:sample.cpp
#include<iostream>
int main(void){
    std::cout << "Hello";
    std::cout << "World" << std::endl;
}
```
`sample.cpp`を作り終わったら、`tasks.json`と`launch.json`を作ります。`.vscode`という名前のフォルダが今作業しているディレクトリにあればその中に`.vscode/tasks.json`と`.vscode/launch.json`を作ります。もしすでに作られているようだったら、改めて作らなくても大丈夫です。

一応、僕の設定の `tasks.json` と `launch.json` を載せておきます。

```json:tasks.json
{
  // See https://go.microsoft.com/fwlink/?LinkId=733558
  // for the documentation about the tasks.json format
  "version": "2.0.0",
  "tasks": [
    {
      "label": "g++ compile",
      "type": "shell",
      "command": "/usr/bin/g++",
      "args": [
        "-g",
        "-o",
        "${fileDirname}/a.out",
        "${file}"
      ],
      "group": {
        "kind": "build",
        "isDefault": true
      }
    }
  ]
}
```

**`tasks.json`ファイルの内訳**

- "tasks" : 実行するコマンド達を表しています。この中にデバッガ起動時に実行するコマンドを書きます。
- "label" : 実行するコマンド達のラベルです。好きなように変更してください。
- "type" : どんな言語かを選びます。今回`tasks.json`ではg++コマンドを実行するので`shell`です。
- "command" : 実行するコマンド部分です。`/usr/bin/g++`としていますが、自分のg++へのパスを書いてください。
- "args" : コマンドに対する引数が入ります。
  - `${fileDirname}`は置換される変数で、`/home/hogehoge/sample.cpp`を選んでいるときには`${fileDirname}`には`/home/hogehoge`が入ります。`${file}`だと`/home/hogehoge/sample.cpp`が入ります。僕の設定では、コンパイルしたファイルのあるディレクトリに`a.out`ファイルが出てくるようにしてます。例えば、`/home/hogehoge/a.out`のようになります。
- "group" : ビルドタスクとして認識させています。これにより`Ctrl + Shift + B`でテスト実行することができます。

<br>

```json:launch.json
{
  // IntelliSense を使用して利用可能な属性を学べます。
  // 既存の属性の説明をホバーして表示します。
  // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
  "version": "0.2.0",
  "configurations": [
    {
      "name": "(gdb) 起動",
      "type": "cppdbg",
      "request": "launch",
      "program": "${fileDirname}/a.out",
      "args": [],
      "stopAtEntry": true,
      "cwd": "${workspaceFolder}",
      "environment": [],
      //"console": "externalTerminal",
      "MIMode": "gdb",
      "miDebuggerPath": "/usr/bin/gdb",
      "setupCommands": [
        {
          "description": "gdb の再フォーマットを有効にする",
          "text": "-enable-pretty-printing",
          "ignoreFailures": true
        }
      ],
      "preLaunchTask": "g++ compile"
    }
  ]
}
```

**`launch.json`ファイルの内訳**

実は僕も全部はわからないので、わかる範囲でだけ書いていこうと思います。

- "name" : 先ほどのラベルと同様です。好きな名前に変更しましょう。
- "program" : デバッグをする対象の実行ファイルです。`${fileDirname}/a.out`をデバッグしてくれます。
- "args" : gdbを使うときの引数です。
- "stopAtEntry" : main関数に来た時点でデバッグを一旦ストップしてくれます。これでブレークポイントを付けるのを忘れても一手順ごとにステップ実行していけます。
- "cwd" : CurrentWorkingDirectoryの略です。コマンドを実行する作業ディレクトリを設定します。
- "environment" : 環境変数を設定します。使いたい環境変数をこの中に入れます。
- "miDebuggerPath" : デバッガのパスを設定します。dbgの実行ファイルへのパスを設定しましょう。
- "setupCommands" : デバッグを使用する際に毎回自動的に実行してくれるコマンド達を設定します。
    - "description" : コマンドの説明です。自分なりにわかりやすいコメントを残しましょう。
    - "text" : 実行するコマンドです。今回は`-enable-pretty-printing`をtrueに設定しています。
    - "ignoreFailures" : コマンドの値を設定します。
    - "preLaunchTask" : 事前に実行するタスクを設定します。これで`tasks.json`にあるラベルが`g++ compile`となっているタスクをデバッグ時に実行できるようになります。

`F5`でデバッグできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/708997/a6b0e8b3-b753-0711-45a7-85a8ec995eef.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/708997/548b3afe-6d9e-af38-6b51-7dbd8c00ba1c.png)


<br><br>

### STLの表示

#### STLって？
Standard Template Libraryのことで、C++に標準で用意されているライブラリのことを指します。
`std::vector`などがSTLです。
設定を行わないとSTLの変数の中身が見れなかったので見れるように設定を行います。

いろいろ調べた結果、**pretty-printers** を使うことにしました。
参考は以下の記事です。

- [GDBでC++デバッグするときはpretty-printersが便利](http://techtipshoge.blogspot.com/2013/11/gdbcpretty-printers.html)

pretty-printers をまず探しましょう。`whereis` コマンドで探します。

```bash
$ whereis pretty-printers
```
もし、pretty-printers が自分のパソコンに無ければ、**SVN(SubVersioN)**を使ってインストールします。SVNとは、Gitみたいにソースコードの管理をインターネット上でするものです。Gitが普及した今では、利用率がかなり低くなっているらしいです。

さて、そんなsvnですが、インストールしていこうと思います。

```bash
$ sudo apt-get install subversion
```

インストールしたら、次のコマンドを実行してpythonで書かれたpretty-printersをダウンロードします。

```bash
$ svn co svn://gcc.gnu.org/svn/gcc/trunk/libstdc++-v3/python
```

次に

```bash
$ cd ~/
```

としてホームディレクトリに移動します。
そこに`.gdbinit`というファイルを作り、次の内容を記述します。

```python:.gdbinit
python
import sys
sys.path.insert(0, '{ここには先ほどsvnからダウンロードしたpythonファイルへのパスを書きます。}/python')
from libstdcxx.v6.printers import register_libstdcxx_printers
register_libstdcxx_printers (None)
end
```

これで、設定完了です。おつかれさまでした。

<br>


[目次に戻る](#mokuji)