Windows10+VSCodeでVisualStudio2019のcl.exeを使ってC＋＋デバッグ

#動機
普段はgccを用いてビルド＆デバッグしていたが、ふとVisual Studioで使われているcl.exeでデバッグ作業がしたくなってきたから。

#注意
- Visual Studio 2019 が既にインストールされていて、C++ のコードが実行できるように設定済みであること
- Visual Studio Code が既にインストールされていて、C++の設定などをされていること
- 迷走した経緯も記されているため、答えだけ知りたければ[一番最後](#4-結果)まで飛んでほしい

ここらの設定については記事が長くなってしまうので割愛させていただく。詳しくは、
[C言語 VisualStudio【開発環境の構築手順を優しく図解】](https://monozukuri-c.com/langc-environment)
[Visual Studio Code のインストールと日本語化まとめ](https://tech-blog.rakus.co.jp/entry/20201009/vscode)
[Visual Studio Code を使った C++ のビルド＆デバッグ方法](https://daily-tech.hatenablog.com/entry/2018/11/17/012113)
などのサイトを参考にしてほしい。

#1. tasks.json の設定
##1.1 とりあえず実行
[Configure VS Code for Microsoft C++](https://code.visualstudio.com/docs/cpp/config-msvc)より、

```jsonc:tasks.json
{
  "version": "2.0.0",
  "tasks": [
    {
      "type": "shell",
      "label": "cl.exe build active file", // ビルド時の選択肢
      "command": "cl.exe",
      "args": [
        "/Zi",
        "/EHsc",
        "/Fe:",
        "${fileDirname}\\${fileBasenameNoExtension}.exe",
        "${file}"
      ],
      "problemMatcher": ["$msCompile"],
      "group": "build", //サイトのままだとビルド時にこれが自動で選択される
    },
    // 他のタスクがあれば...
  ]
}
```
/EHscは[アンワインド セマンティクス って何？](https://mzex.blog/2017/04/10/c4530/) や http://myoga.web.fc2.com/prog/cpp/intro03.htm より、
>/EHsc は、「C++ 例外処理を利用します」という意味です。 何も指定しないと iostream が c++ の例外処理を使おうとして(?)コンパイル出来なくなってしまいます。

コンパイラへのパスの設定をしていないので動きそうもないがひとまず実行してみよう。
プログラムの画面でctrl+shift+bで画面上部に表示されるものの中から「cl.exe build active file」を選ぶとコンパイルが行われる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1120826/4e4bc090-e7e8-20a8-e1bb-6d42261b60c6.png)
>'cl.exe' は、内部コマンドまたは外部コマンド、
>操作可能なプログラムまたはバッチ ファイルとして認識されていません。

まあ予想通りの結果となってしまった。
`"command": "cl.exe",` ではパスを通していないので当たり前であろう。
ではcl.exeがどこにあるのか調べなければならない。

各々によって異なるだろうが、私の場合は
D:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.24.28314/bin/Hostx64/x64/cl.exe
にあったので、
`"command": "D:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.24.28314/bin/Hostx64/x64/cl.exe",`
に書き換えて実行してみる。

>helloworld.cpp
>D:\VScode\C\helloworld.cpp(1): fatal error C1034: iostream: インクルード パスが設定されていません。

自動でインクルードディレクトリを探してくれないようである。
##1.2 インクルードディレクトリの指定
[(2019年版)コマンドラインからclを使ってコンパイルできるようにしたので共有する](https://qiita.com/asana_yui/items/d545b5eccd994c0cdaab)
より、「x64 Native Tools Command Prompt for VS 2019」を起動して、
`echo %INCLUDE%` と打ち込む。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1120826/663a5225-e83f-140b-3cb5-a90300c344cc.png)

```
D:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.24.28314\ATLMFC\include;
D:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.24.28314\include;
C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\include\um;
C:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\ucrt;
C:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\shared;
C:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\um;
C:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\winrt;
C:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\cppwinrt
```
これらを環境変数に登録するのもいいが、せっかくだからコンパイラオプションで指定してみたい。
[/I (追加のインクルードディレクトリ)](https://docs.microsoft.com/ja-jp/cpp/build/reference/i-additional-include-directories?view=msvc-160) より、`/I directory` の形式で書けば良いようなので、"args"の中身を

```jsonc
"args": [
  "/Zi",
  "/EHsc",
  "/I",
  "D:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.24.28314\\ATLMFC\\include",
  "/I",
  "D:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.24.28314\\include",
  "/I",
  "C:\\Program Files (x86)\\Windows Kits\\NETFXSDK\\4.8\\include\\um",
  "/I",
  "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\ucrt",
  "/I",
  "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\shared",
  "/I",
  "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\um",
  "/I",
  "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\winrt",
  "/I",
  "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\cppwinrt",
  "/Fe:",
  "${fileDirname}\\${fileBasenameNoExtension}.exe",
  "${file}"
],
```
に変更して再実行
LIBとLIBPATHの指定はしていないので、エラーになるのだろう。

>helloworld.obj
>LINK : fatal error LNK1104: ファイル 'libcpmt.lib' を開くことができません。

やはりか...

##1.3 Libディレクトリの指定
[リンカ ツール エラー LNK1104](https://docs.microsoft.com/ja-jp/cpp/error-messages/tool-errors/linker-tools-error-lnk1104?view=msvc-160) より、

>ファイル 'C:\Program.obj' を開くことができません
>>コマンドラインビルドのこの問題を解決するには、 /LIBPATH オプションのパラメーターを確認します。 また、LIB 環境変数で指定されたパスと、コマンドラインで指定されたパスも確認します。 スペースを含むパスは必ず二重引用符で囲んでください。

なるほど、これもオプションで指定できそうだ。
[/LIBPATH (追加ライブラリのパス)](https://docs.microsoft.com/ja-jp/cpp/build/reference/libpath-additional-libpath?view=msvc-160)より、`/LIBPATH:dir`の形式で書けば良いようである。
ということで、さっきの「x64 Native Tools Command Prompt for VS 2019」に、
`echo %LIB%` と打ち込む。

```
D:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.24.28314\ATLMFC\lib\x64;
D:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.24.28314\lib\x64;
C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\lib\um\x64;
C:\Program Files (x86)\Windows Kits\10\lib\10.0.18362.0\ucrt\x64;
C:\Program Files (x86)\Windows Kits\10\lib\10.0.18362.0\um\x64;
```

なので"args"の中身を、

```jsonc
"args": [
  "/Zi",
  "/EHsc",
  "/I",
  "D:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.24.28314\\ATLMFC\\include",
  "/I",
  "D:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.24.28314\\include",
  "/I",
  "C:\\Program Files (x86)\\Windows Kits\\NETFXSDK\\4.8\\include\\um",
  "/I",
  "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\ucrt",
  "/I",
  "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\shared",
  "/I",
  "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\um",
  "/I",
  "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\winrt",
  "/I",
  "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\cppwinrt",
  "/Fe:",
  "${fileDirname}\\${fileBasenameNoExtension}.exe",
  "${file}",
  "/LIBPATH:D:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.24.28314\\ATLMFC\\lib\\x64",
  "/LIBPATH:D:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.24.28314\\lib\\x64",
  "/LIBPATH:C:\\Program Files (x86)\\Windows Kits\\NETFXSDK\\4.8\\lib\\um\\x64",
  "/LIBPATH:C:\\Program Files (x86)\\Windows Kits\\10\\lib\\10.0.18362.0\\ucrt\\x64",
  "/LIBPATH:C:\\Program Files (x86)\\Windows Kits\\10\\lib\\10.0.18362.0\\um\\x64",
],
```

これで実行してみる。

>cl : コマンド ライン warning D9002 : 不明なオプション '/LIBPATH:D:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.24.28314\ATLMFC\lib\x64' を無視します。
>cl : コマンド ライン warning D9002 : 不明なオプション '/LIBPATH:D:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.24.28314\lib\x64' を無視します。
>cl : コマンド ライン warning D9002 : 不明なオプション '/LIBPATH:C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\lib\um\x64' を無視します。
>cl : コマンド ライン warning D9002 : 不明なオプション '/LIBPATH:C:\Program Files (x86)\Windows Kits\10\lib\10.0.18362.0\ucrt\x64' を無視します。
>cl : コマンド ライン warning D9002 : 不明なオプション '/LIBPATH:C:\Program Files (x86)\Windows Kits\10\lib\10.0.18362.0\um\x64' を無視します。 

調べたところ、`/LIBPATH` はリンカオプションであり、
リンカにオプションを渡すためには、[Compiler-Controlled LINK Options](https://docs.microsoft.com/ja-jp/cpp/build/reference/compiler-controlled-link-options?view=msvc-160) より、`/link` の後に書かなければいけないのだとか。
よって"args"の中身を、

```jsonc
"args": [
  "/Zi",
  "/EHsc",
  "/I",
  "D:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.24.28314\\ATLMFC\\include",
  "/I",
  "D:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.24.28314\\include",
  "/I",
  "C:\\Program Files (x86)\\Windows Kits\\NETFXSDK\\4.8\\include\\um",
  "/I",
  "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\ucrt",
  "/I",
  "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\shared",
  "/I",
  "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\um",
  "/I",
  "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\winrt",
  "/I",
  "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\cppwinrt",
  "/Fe:",
  "${fileDirname}\\${fileBasenameNoExtension}.exe",
  "${file}",
  "/link",
  "/LIBPATH:D:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.24.28314\\ATLMFC\\lib\\x64",
  "/LIBPATH:D:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.24.28314\\lib\\x64",
  "/LIBPATH:C:\\Program Files (x86)\\Windows Kits\\NETFXSDK\\4.8\\lib\\um\\x64",
  "/LIBPATH:C:\\Program Files (x86)\\Windows Kits\\10\\lib\\10.0.18362.0\\ucrt\\x64",
  "/LIBPATH:C:\\Program Files (x86)\\Windows Kits\\10\\lib\\10.0.18362.0\\um\\x64",
],
```

として実行したところ、エラー無くビルドできた。

#2. launch.json の設定

[Configure VS Code for Microsoft C++](https://code.visualstudio.com/docs/cpp/config-msvc)より、

```jsonc:launch.json
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "cl.exe build and debug active file", // デバッグ時の選択肢
      "type": "cppvsdbg",
      "request": "launch",
      "program": "${fileDirname}\\${fileBasenameNoExtension}.exe",
      "args": [],
      "stopAtEntry": false,
      "cwd": "${workspaceFolder}",
      "environment": [],
      //"console": "newExternalWindow", //外部タイミナル上で出力
      "console": "integratedTerminal", //内部ターミナル上で出力
      //"externalConsole": false, //非推奨
      "preLaunchTask": "cl.exe build active file"
    },
    // 他の構成があれば...
  ]
}
```

実行するにはctrl+shift+dで出てきた画面から選択すればいいので、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1120826/74be75fc-3c9d-ff40-82c4-166939f13e4f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1120826/bb6eb6ab-1dd0-772d-1889-6bfff6d5a6e5.png)

これでデバッグができるようになった。

#3. tasks.json の設定(改)

ここまでの設定でデバッグができるようになったのだが、
[【VSCode tips】VSCode で go buildする設定 【#1】](https://qiita.com/professor/items/676ccb669d6e6102117b)より、
optionディレクティブ及びenvディレクティブを用いて環境変数の指定を行えるようである。よって、

```jsonc
"options": {
  "env": {
    "INCLUDE": "D:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.24.28314\\ATLMFC\\include;D:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.24.28314\\include;C:\\Program Files (x86)\\Windows Kits\\NETFXSDK\\4.8\\include\\um;C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\ucrt;C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\shared;C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\um;C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\winrt;C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\cppwinrt",
    "LIB": "D:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.24.28314\\ATLMFC\\lib\\x64;D:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.24.28314\\lib\\x64;C:\\Program Files (x86)\\Windows Kits\\NETFXSDK\\4.8\\lib\\um\\x64;C:\\Program Files (x86)\\Windows Kits\\10\\lib\\10.0.18362.0\\ucrt\\x64;C:\\Program Files (x86)\\Windows Kits\\10\\lib\\10.0.18362.0\\um\\x64;",
  }
},
```

を追加し、/I オプションと、/LIBPATH オプションを削除すれば "args" の中身が見やすくなるであろう。

#4. 結果

```jsonc:tasks.json
{
  "version": "2.0.0",
  "tasks": [
    {
      "type": "shell",
      "label": "cl.exe build active file",
      "command": "D:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.24.28314/bin/Hostx64/x64/cl.exe",
      "args": [
        "/Zi",
        "/EHsc",
        "/source-charset:utf-8", //日本語文字化け対策 https://torakichi.hateblo.jp/entry/2017/03/04/152827 より
        "/std:c++17",
        "/Od", //最適化無効
        "/Fe:",
        "${fileDirname}\\${fileBasenameNoExtension}.exe",
        "${file}"
      ],
      "options": {
        "env": {
          "INCLUDE": "D:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.24.28314\\ATLMFC\\include;D:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.24.28314\\include;C:\\Program Files (x86)\\Windows Kits\\NETFXSDK\\4.8\\include\\um;C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\ucrt;C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\shared;C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\um;C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\winrt;C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\cppwinrt",
          "LIB": "D:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.24.28314\\ATLMFC\\lib\\x64;D:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.24.28314\\lib\\x64;C:\\Program Files (x86)\\Windows Kits\\NETFXSDK\\4.8\\lib\\um\\x64;C:\\Program Files (x86)\\Windows Kits\\10\\lib\\10.0.18362.0\\ucrt\\x64;C:\\Program Files (x86)\\Windows Kits\\10\\lib\\10.0.18362.0\\um\\x64;",
        }
      },
      "problemMatcher": ["$msCompile"],
      "group": "build",
    },
    // 他のタスクがあれば...
  ]
}
```
- [Visual Studio Code（CL.exe）を使って、コンソールアプリ（C,CPPファイル）をデバッグ](https://tm-b.hatenablog.com/entry/2020/09/29/013729)
- [/Oオプション (コードの最適化)](https://docs.microsoft.com/ja-jp/cpp/build/reference/o-options-optimize-code?view=msvc-160)
- [/std (言語の標準バージョンの指定)](https://docs.microsoft.com/ja-jp/cpp/build/reference/std-specify-language-standard-version?view=msvc-160)

```jsonc:launch.json
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "cl.exe build and debug active file", // デバッグ時の選択肢
      "type": "cppvsdbg",
      "request": "launch",
      "program": "${fileDirname}\\${fileBasenameNoExtension}.exe",
      "args": [],
      "stopAtEntry": false,
      "cwd": "${workspaceFolder}",
      "environment": [],
      //"console": "newExternalWindow", //外部タイミナル上で出力
      "console": "integratedTerminal", //内部ターミナル上で出力
      //"externalConsole": false, //非推奨
      "preLaunchTask": "cl.exe build active file"
    },
    // 他の構成があれば...
  ]
}
```