【VScode＋WSLで始める】競プロ用C++デバッグ環境構築

# はじめに

`VScode`と`WSL`での`C++`のデバッグ環境を整えます．
とりあえずスタートラインに立ちたい方やVScodeのデバッグ機能を使って競プロをやりたいという人向けの記事です．

競プロを始めるための最小構成の紹介となります．
デバッガがなくても始められますが，これがあるとないで全然違ってきます．導入していない人はぜひ試してみてください．

これから`C++`で競プロを始める人の参考になれば幸いです．
デバッグは環境構築と簡単な使い方について説明します．

## 目標

`AtCoder`で`C++`を使って競技プログラミングを行うことを想定しています．

基本動作は，
1. `Ctrl+Shift+B`で自動コンパイル．
2. 統合ターミナルより手動で実行．入力を与え，出力結果を確認．
3. 必要になったらVScodeのデバッグ機能(`F5`)を使用してデバッグ．

最終的にフォルダの構成は以下のようになります．
![t.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427721/ce23e753-9aee-d515-f1dc-52173fec60f0.png)


- 各コンテスト毎にフォルダを作成し，その中にA問題だったら`a.cpp`のようなファイル名でどんどん作成していきます．
- プログラムの実行ファイルはディレクトリ直下に生成されるようにします(コンテスト毎にカレントディレクトリを移動しなくても済むようにするため)．
- `Vscode`のデバッグ機能を使用してデバッグを行う際，統合ターミナルからの入力を受け付けて貰えないため，リダイレクトで標準入力として与えます．そのため`problem.in`というファイルを用意し，そこに問題の入力を入れておきます．

# 前提

`VScode`と`WSL`に関してはインストール済みであるとします．
以下は自分の環境です．

||Version|
|:--:|:--:|
| Windows| Windows 10 Home(1903)|
| VScode | 1.36.1|
|WSL|Ubuntu 16.04.6 LTS|

`WSL`では現在多くのLinuxディストリビューションに対応しています．
C++のコンパイル・デバッグに関して言えばほとんどのディストリビューションで可能なので自由に好きなものを選んで頂いて構いません．

# C++実行環境構築

初めに`VScode`上でC++ファイルのコンパイルと実行を行えるようにしていきます．

## WSL環境

WSL端末を開き，以下のコマンドで`g++`と`gdb`をインストールします．

```bash:WSL
$ sudo apt install build-essential -y
$ sudo apt install gdb -y
```
<!--
バージョンの確認

```:g++バージョン
$ g++ --version
g++ (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
```

```:gdbバージョン
$ gdb --version
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
```
-->

## VScode環境

### 拡張機能のインストール

C/C++用の拡張機能をインストールします．
赤枠で囲った拡張機能のところで検索欄に「C++」と検索して出てくる次の2つをインストールしてください．
以下のURLからでもインストールすることができます．

[C/C++](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools)
![2019-07-02_16h51_09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427721/ca29b69d-f3c7-be98-a719-7f3e12a40564.png)

[C++ Intellisense](https://marketplace.visualstudio.com/items?itemName=austin.code-gnu-global)
![2019-07-02_16h51_17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427721/290a4184-2854-6a88-ebb9-1f3a5c1a62e0.png)

### 統合ターミナルの設定

標準で使うターミナルを`WSL`に設定します．
`Ctrl+Shift+P`を押してコマンドパレットを表示させ，**「shell」**と入力し，**Select Default Shell**を選択します．
![2019-07-02_16h56_50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427721/111d30ec-6073-a81f-1ecf-cead6e055052.png)


すると何種類からかシェルを選ぶことができるのでそこから**WSL Bash**を選択します．

![2019-07-02_16h57_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427721/7756ebaf-14a2-6ad4-618f-3fa4a0972cd6.png)

ツールバーの`Terminal -> New Terminal`を選択するか，`Ctrl+Shift+@`を押すことによってターミナルを開きます．
次の矢印のようにWSLターミナルが開かれていることを確認してください．

![2019-07-02_17h05_16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427721/bc06e8ca-bff3-e5a9-dd3e-c51ee7dc15c2.png)


### tasks.jsonの設定

`Ctrl+Shift+B`で現在開いているファイルをビルドする設定を行います．
なにも設定を行っていない状態で`Ctrl+Shift+B`を押すと次のような表示が出てくると思うのでとりあえず指示にしたがってクリックしていきます．
![2019-07-02_17h18_00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427721/95791d61-cb95-4271-57f0-6609e71a0e5d.png)

![2019-07-02_17h18_07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427721/2d6998d9-8dfd-0b33-d087-ae0c2b49bd2f.png)

ここで選択肢が4つ出てくるので**Others**を選択します．
![2019-07-02_17h18_20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427721/828c4bd6-b27f-4c92-c792-dac5d9e8ef0d.png)

`.vscode`内に次のような`tasks.json`が生成されればOKです．
![2019-07-02_17h18_40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427721/3f228216-f1fd-15c9-f1ae-11eb5846744b.png)

そして生成された`tasks.json`を次のように書き換えます．

```json:tasks.json
{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "build",
            "type": "shell",
            "options": {
                "shell": {
                    "executable": "C:\\Windows\\System32\\wsl.exe",
                }
            },
            "command": "g++",
            "args": [
                "-std=gnu++1y",
                "-g",
                "-O0",
                "-I/opt/boost/gcc/include",
                "-L/opt/boost/gcc/lib",
                "-o",
                "`wslpath",
                "'${workspaceFolder}\\problem.exe'`",
                "`wslpath",
                "'${file}'`",
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            }
        }
    ]
}
```
ここで簡単にコンパイルオプションについて解説します．
AtCoder側でのコンパイルオプションは[このサイト](https://language-test-201603.contest.atcoder.jp/)で確認することができます．

今回は**C++14 (GCC 5.4.1)**を選択するので，それためのコンパイルオプションをそのまま使用したいのですが，デバッグの関係上少しいじります．サイトのオプションと比較するとわかると思いますが，`-O2`ところを`-O0`としています．これは最適化オプションといって最適化の具合を指定することができ，`-O0`とすることによって最適化を無効とします．
最適化を行うことによって処理の順番が変わったり，コンテナの中身が見れなくなったりするのでデバッグを使用する際は最適化を無効にしましょう．

また，ファイルパスの前についている`wslpath`というのはWindows環境のパスをWSL環境のパスに変換するコマンドです．



### IntelliSenseの設定
次にIntelliSenseの設定を行います．
先ほどと同じように`Ctrl+Shift+P`をタイプしてコマンドパレットを出します．
**C/C++:Edit Configurations(JSON)**を探して選択してください．
![2019-07-02_17h38_19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427721/cd2e7dba-2340-db07-e9fa-0effbc0fdfc1.png)
すると次のように`c_cpp_properties.json`が生成されます．
![2019-07-02_17h38_46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427721/f897e3f2-3a56-cb17-b1c0-1595d67ea44c.png)
`c_cpp_properties.json`の中身を次のように書き換えてください．

```json:c_cpp_properties.json
{
    "configurations": [
      {
        "name": "WSL",
        "intelliSenseMode": "gcc-x64",
        "compilerPath": "/usr/bin/gcc",
        "includePath": ["${workspaceFolder}/**"],
        "defines": [],
        "cStandard": "c11",
        "cppStandard": "c++17"
      }
    ],
    "version": 4
}
```

## C++実行環境の確認

ここまででコンパイルから実行までできる環境が整いました．
それの確認を実際のAtCoderの問題を使用して行いたいと思います．
問題は初心者向けということで[**ABC 086 A - Product**](https://atcoder.jp/contests/abc086/tasks/abc086_a)(奇数偶数判定)をやっていきます．

初めに次のような階層にファイルを作成し，実装を行います．
![2019-07-02_18h19_05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427721/d7524621-1c26-0c81-1c0b-5619f4f4de9e.png)

```cpp:a.cpp
#include <bits/stdc++.h>
using namespace std;

int main(void)
{
    int a, b;
    cin >> a >> b;
    if ((a * b) % 2 == 0) cout << "Even" << endl;
    else cout << "Odd" << endl;    
}
```

ソースが完成したら`Ctrl+Shift+B`でコンパイルを行います．
コンパイルしてできた実行ファイルはディレクトリ直下に`problem.exe`で生成されます．
![2019-07-02_18h22_06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427721/52924c8f-272d-d29b-6497-5b53849da99b.png)

ターミナルに戻ったら，`./problem.exe`を実行して下さい．
入力を与えて所望の出力を得ることができたらC++実行環境の構築は成功です．
![2019-07-02_18h36_46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427721/e93959c6-fed3-4a6a-cbc2-a67c823b6994.png)

# デバッグ環境構築

次にデバッグをするための設定を行っていきます．

## launch.jsonの設定

`tasks.json`と同じように何も設定していない状態で`F5`を押すと，上から選択画面が出てくるので`C++(GDB/LLDB)`を選択してください．
![2019-07-03_04h49_57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427721/c883135c-fa0c-33af-597e-cceeede1758a.png)
すると次のような`launch.json`というファイルが`.vscode`内に生成されます．
![2019-07-03_04h50_30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427721/e308dcad-9c3a-6f53-baeb-ca91b0080ea8.png)

先ほどと同じようにこちらも書き換えてください．

```json:launch.json
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "(gdb) Bash on Windows Launch",
            "type": "cppdbg",
            "request": "launch",
            "program": "${command:extension.vscode-wsl-workspaceFolder}/problem.exe",
            "args": ["<", "${command:extension.vscode-wsl-workspaceFolder}/problem.in"],
            "stopAtEntry": false,
            "cwd": "${command:extension.vscode-wsl-workspaceFolder}",
            "environment": [],
            "externalConsole": true,
            "pipeTransport": {
                "debuggerPath": "/usr/bin/gdb",
                "pipeProgram": "${env:windir}\\system32\\bash.exe",
                "pipeArgs": ["-c"],
                "pipeCwd": "/"
            },
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ],
            "sourceFileMap": {
                "${command:extension.vscode-wsl-workspaceFolder}": "${workspaceFolder}"
            },
            
        }
    ]
}
```

`${command:extension.vscode-wsl-workspaceFolder}`部分でエラーが発生すると思うので，次のVScode拡張をインストールしてください．

[WSL workspaceFolder](https://marketplace.visualstudio.com/items?itemName=lfurzewaddock.vscode-wsl-workspacefolder)
![2019-07-03_05h01_49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427721/a15c1e33-3f81-2732-9607-a657fba014be.png)

この拡張ではワークスペースフォルダのパスをWSL環境のパスに変換します．
これがなくてもできないことはないですが，汎用性を上げるために使用しています．

## デバッグ環境の確認

ここまでくれば(おそらく)デバッグ環境の構築はできていると思います．
先ほどと同じように確認していきましょう．

この環境でデバッグを行う際には，まずソースファイルの任意の行にブレークポイントを設定します．
ブレークポイントとは処理を一旦そこで止めるポイントです．
下の図のように**ソースファイルの左側をクリックすることで赤い丸をつけること**が出来ます．これがブレークポイントです．

次に入力する値を入れます．AtCoderのコンテストサイトからテストケースなどをコピーして，`problem.in`に貼り付けます．
![2019-07-03_12h10_30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427721/0a3a3cdf-d197-4766-85fa-db552036aded.png)
`F5`を押すと左側の画面が遷移し，デバッグの結果を見ることが出来ます．
デバッグ中だと下のバーがオレンジ色になり，上にツールバーが表示されます．
`VARIABLES`の欄に変数一覧とその値が表示されたら成功です．
![2019-07-03_12h20_16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427721/9009671c-fc99-845c-9fa6-a96c2645615e.png)

## VScodeのデバッグ機能の使い方

VScodeのデバッグ機能の使い方について簡単に説明します．

### ツールバー

上に表示されるツールバーでプログラムの流れを制御することが出来ます．
(`i`の値に注目)
![2019-07-03_16h25_19.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427721/c7360f4e-6df2-3fdf-c324-c2e0b4a698c4.gif)

ツールバーの各ボタンについて見ていきます．
![2019-07-03_12h45_09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427721/6f2c9cac-4896-1507-5629-79a36e349a43.png)

||要素|ショートカット| 機能 |
|:--:|:--:|:--:|:--|
|①|Continue/Pause|F5|次のブレークポイントまで進める/プログラムを止める|
|②|Step Over|F10|現在行を実行する．その行に関数呼び出しが含まれる場合は，その関数を呼び出して実行した後，次の行へ移動する．|
|③|Step Into|F11|現在行を実行する．その行に関数呼び出しが含まれる場合は，その関数の先頭行へ移動する．**std::sort()など組み込み関数を呼び出すとエラーになる．**|
|④|Step Out|Shift+F11|現在実行中の関数を抜けるまで処理を進める．|
|⑤|Restart|Ctrl+Shift+F5|プログラムを最初からやり直す．|
|⑥|Stop|Shift+F5|デバッグを終了する．|

### VARIABLES

ここでは変数の現在の値を確認することが出来ます．
配列はもちろん，コンテナクラスや`pair`の値も覗くことができます．
下のGIFでは`vector`の中身をソートして，その変化をデバッグ画面から確認する例です．
![2019-07-03_16h09_39.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427721/202bfdb3-52a6-4f28-16a9-f05a4390425b.gif)


### WATCH

`WATCH`欄では変数以外にも`a+b`や`a[i]`などの式の値も見ることが出来ます．
下のGIFではちょっと分かりづらいですが，`vector`のi番目の要素とその和と積をリアルタイムで確認しています．
![2019-07-03_16h25_19.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427721/e6acf24d-05ef-f8ad-85f3-0a3c2107584e.gif)


### CALL STACK

呼び出し中の関数を確認することが出来ます．
フィボナッチ数列などの再帰関数を定義している場合はこんな感じで表示されます．
![2019-07-03_16h34_28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427721/cb42b6fe-226e-49eb-3e38-2b3b826e08d2.png)

他にも便利な機能があるようなので調べて見ると面白いかもです．

# 最後に

VScodeとWSLを用いたC++のデバッグ環境構築を行ってきました．
環境構築って大変ですがその後のモチベーションにも関わってくる部分なので案外大切です．
この記事以外にもVScodeを用いた競プロ環境構築関連の記事は多くあるので，その中から「これはいい！使える！」といった部分を見つけて，自分自身のプログラミング環境を整えていくといいと思います(自分でいろいろ試す，というのが一番成長につながります！)．
最初の頃はprintfでデバッグをしていましたが，デバッガが使えると競プロ以外でもかなり捗ります．おすすめです．

[2019/12/15追記]
コンパイル対象ファイルと同ディレクトリに実行ファイルを作成したい場合，コメント欄を参考に`tasks.json`と`launch.json`の記述を書き換えてください．

---

<!--
自分は競技プログラミングを始めたばかりで，アルゴリズムなどまだまだわからないことだらけです．
勉強を始めるにあたって，競プロ用の環境構築記事などたくさん読みました．
ところどころ参考になったりならなかったりで，試行錯誤して今の環境を作りました．
この記事も人によっては参考になったりならなかったりするところがあると思うので，他の記事と合わせつつ，良いところだけを集めて自分の環境を作っていくのがいいと思います．
最初の頃はprintfデバッグでしたがデバッガを使い始めると捗りますね．
モチベーションも爆上がりなので環境構築もほどほどに競プロの学習も頑張りたいと思います．
-->