Visual Studio Code のデバッグ環境構築

* Visual Studio Code における色々な言語のデバッグ構成のまとめ。
* ネット上で書かれている手法なども参考にしながらデバッグ環境を構築。その作業手順を記した。
* 起動しているプロセスへアタッチした上でのデバッグやリモート環境のデバッグなど他にも色々なデバッグの方法があるだろうけど、それは後でここに書き足す。
* 他にも内容の不足したところが色々あるだろうから、後で書き足していく。
* 普通にやってうまくいかなかったものは、自分なりの解決手段を記した。

## デバッグの基本

以下の形式のJSONを `${workspaceRoot}/.vscode/launch.json` に記述する

```jsonc
{
	"version": "0.2.0",
	"configurations": [
		// 構成を記述する
	]
}
```

## Node.js

1. `settings.json` への記述

	```jsonc
	"debug.javascript.usePreview": true // 組み込みの拡張機能 ms-vscode.js-debug を有効にする
	```

2. デバッグ構成の記述

	```jsonc
	{
		"name": "Node debugging",
		"type": "node",
		"request": "launch",
		"program": "${workspaceRoot}/path/to/source.js",
		"outputCapture": "std",
		"stopOnEntry": true,
		"args": ["arg1","arg2","arg3"]
	}
	```

* コード中の `debugger;` でもブレークポイントが作動する。

* 通常通り行番号横でブレークポイントを指定しても**作動しないことがある**。この場合、次の方法でうまくいくことがある。
	1. コード中のどこかに `debugger;` を追加する。
	2. 実行して `debugger;` に引っかかってみる。このとき、行番号横のブレークポイントは**消される**。
	3. 実行を停止して `debugger;` をコードから取り除く。
	4. 行番号横にブレークポイントを置くともうちゃんと引っかかってくれると思う。

* 行番号でのブレークポイントに引っ掛からない問題に遭遇しても `debugger;` なら多分いつでも引っかかる。
* `.js` ファイルごとにこの作業を行わなければならない。

## Python

1. 必要なものをインストール

	```sh
	code --install-extension ms-python.python
	code --install-extension ms-python.vscode-pylance # Pylance LS を使う場合
	```

2. `settings.json` への記述

	```jsonc
	"python.pythonPath": "/usr/local/bin/python3",
	"python.languageServer": "Microsoft", // or Pylance
	```

3. デバッグ構成の記述

	```jsonc
	{
		"name": "Python debugging",
		"type": "python",
		"request": "launch",
		"program": "${workspaceRoot}/path/to/source.py",
		"args": ["arg1","arg2","arg3"]
	}
	```

## Ruby

1. 必要なものをインストール

	```sh
	gem install rubocop # for linting
	gem solargraph # for intellisense
	gem install rake debase ruby-debug-ide # for debug
	
	export GEM_PATH="..." # gem environment から取得

	code --install-extension rebornix.Ruby       # for debugging
	code --install-extension castwide.solargraph # for intellisense
	```

2. `settings.json` への記述

	```jsonc
	"ruby.interpreter.commandPath": "/usr/local/bin/ruby",
	"ruby.useLanguageServer": true,
	"ruby.codeCompletion": "rcodetools",
	"ruby.format": "rubocop"
	```

3. デバッグ構成の記述

	```jsonc
	{
		"name": "Ruby debugging",
		"type": "Ruby",
		"request": "launch",
		"program": "${workspaceRoot}/path/to/main.rb",
		"args": ["arg1","arg2","arg3"]
	}
	```

## PHP

1. 必要なものをインストール

	```sh
	pecl install xdebug # composer にはない

	code --install-extension felixfbecker.php-intellisense # for intellisense
	code --install-extension felixfbecker.php-debug        # for debugging
	```

2. `settings.json` への記述

	```jsonc
	"php.executablePath": "/usr/local/bin/php",
	"php.validate.executablePath": "/usr/local/bin/php"
	```

3. デバッグ構成の記述

	```jsonc
	{
		"name": "PHP debugging",
		"type": "php",
		"request": "launch",
		"program": "${workspaceRoot}/path/to/source.php", // 絶対パスが必須か
		"args": ["arg1","arg2","arg3"]
	}
	```

## Go

1. 必要なものをインストール

	```sh
	go get -u github.com/derekparker/delve/cmd/dlv # Delve

	code --install-extension golang.Go
	```

2. デバッグ構成の記述

	1. シングルファイル

		```jsonc
		{
			"name": "Go debugging",
			"type": "go",
			"request": "launch",
			"program": "${workspaceRoot}/path/to/source.go",
			"mode": "debug",
			"args": ["arg1","arg2","arg3"]
		}
		```

	2. `${workspaceRoot}` 以下のソースファイル全体の場合

		```jsonc
		{
			"name": "Go debugging",
			"type": "go",
			"request": "launch",
			"program": "${workspaceRoot}",
			"args": ["arg1","arg2","arg3"]
		}
		```

* Go拡張機能は現在開いているルートディクレクトリ ( `${workspaceRoot}` ) まるごとGoパッケージだと認識するようで、そのためか色々とトラブルが発生する

	* どうやら `main` パッケージのソースファイルは `${workspaceRoot}` の直下にないとデバッガのブレークポイントが作動しない  
		つまり `${workspaceRoot}` 以下の適当なディレクトリにいくつかのGoソースファイルを詰め込んで、そのディレクトリ全体で1つのプログラム、というような使い方は想定していないようだ

	* 単一のGoソースファイルであれば `${workspaceRoot}` 以下のどこにあっても正常にデバッガが作動する

	* Goソースファイルと同じディレクトリにCやC++のソースファイルを置くとエラーが表示される (cgoでないので置いてはならない的な)  
		単一のGoソースファイルのつもりでも偶々横にあっただけで怒られるから迷惑。

## C/C++

* Clang/GCC の場合のみ

1. 必要なものをインストール

	```sh
	code --install-extension ms-vscode.cpptools
	```

2. デバッグ構成の記述 (`launch.json`)

	```jsonc
	{
		"name": "C++ debugging",
		"type": "cppdbg",
		"request": "launch",
		"program": "${workspaceFolder}/path/to/binary",
		"args": ["arg1","arg2","arg3"],
		"cwd": ".",
		"stopAtEntry": false,
		"externalConsole": false,
		"MIMode": "lldb",
		"preLaunchTask": "build c++ src for debug", // デバッグ用バイナリのビルド
		"postDebugTask": "clean debug files" // 必要であれば
	}
	```

3. デバッグ前後のタスクの登録 (`tasks.json`)

	```jsonc
	{
		"label": "build c++ src for debug",
		"type": "shell",
		"command": "make debug", // clang++ *.cpp -g -o path/to/binary …
		"group": "build",
		"presentation": {
			"reveal": "silent"
		}
	},
	// デバッグデータの消去とかに
	{
		"label": "clean debug files",
		"type": "shell",
		"command": "make clean", // rm -rf path/to/binary.dSYM
		"group": "build",
		"presentation": {
			"reveal": "silent"
		}
	}
	```

## C# (Mono)

1. 必要なものをインストール

	```sh
	code --install-extension ms-vscode.mono-debug
	```

2. デバッグ構成の記述 (`launch.json`)

	```jsonc
	{
		"name": "C# debugging",
		"type": "mono",
		"request": "launch",
		"program": "${workspaceFolder}/path/to/binary.exe",
		"args": ["arg1","arg2","arg3"],
		"preLaunchTask": "build c# src for debug", // デバッグ用バイナリのビルド
		"postDebugTask": "clean debug files" // 必要であれば
	}
	```

3. デバッグ前後のタスクの登録 (`tasks.json`)

	```jsonc
	{
		"label": "build c# src for debug",
		"type": "shell",
		"command": "make debug", // mcs path/to/source.cs -debug -out:path/to/binary.exe …
		"group": "build",
		"presentation": {
			"reveal": "silent"
		}
	},
	// デバッグデータの消去とかに
	{
		"label": "clean debug files",
		"type": "shell",
		"command": "make clean", // rm path/to/binary.exe
		"group": "build",
		"presentation": {
			"reveal": "silent"
		}
	}
	```

## Java

* `.java` のソースファイルのままでデバッグ可能だという説もあるが、うまく作動しないので `.class` にコンパイルする。シングルファイルならできるのかな。検証中。

1. 必要なものをインストール

	```sh
	code --install-extension redhat.java # Language Server
	code --install-extension vscjava.vscode-java-debug # Debugger
	```

2. デバッグ構成の記述 (`launch.json`)

	```jsonc
	{
		"name": "Java debugging",
		"type": "java",
		"request": "launch",
		"classPaths": ["${workspaceFolder}/path/to"],
		"mainClass": "someMainClass",
		"args": ["arg1","arg2","arg3"],
		"preLaunchTask": "build java src for debug",
		"postDebugTask": "clean debug files"
	}
	```

3. デバッグ前後のタスクの登録 (`tasks.json`)

	```jsonc
	{
		"label": "build java src for debug",
		"type": "shell",
		"command": "make build", // javac *.java
		"cwd": "${workspaceFolder}/path/to",
		"group": "build",
		"presentation": {
			"reveal": "silent"
		}
	},
	// デバッグデータの消去とかに
	{
		"label": "clean debug files",
		"type": "shell",
		"command": "make clean", // rm *.class
		"group": "build",
		"presentation": {
			"reveal": "silent"
		}
	}
	```

## Julia
1. 必要なものをインストール

	```sh
	code --install-extension julialang.language-julia
	```

2. デバッグ構成の記述

	```jsonc
	{
		"name": "Julia debugging",
		"type": "julia",
		"request": "launch",
		"program": "${workspaceFolder}/path/to/source.jl",
		"args": []
	}
	```

## PowerShell
1. 必要なものをインストール

	```sh
	code --install-extension ms-vscode.powershell
	```

2. デバッグ構成の記述

	```jsonc
	{
		"name": "PowerShell debugging",
		"type": "PowerShell",
		"request": "launch",
		"script": "${workspaceFolder}/path/to/source.ps1",
		"args": ["arg1","arg2","arg3"]
	}
	```

## Bash
1. 必要なものをインストール

	```sh
	code --install-extension rogalmic.bash-debug
	```

2. デバッグ構成の記述

	```jsonc
	{
		"name": "Bash debugging",
		"type": "bashdb",
		"request": "launch",
		"program": "${workspaceRoot}/path/to/source.sh",
		"args": ["arg1","arg2","arg3"]
	}
	```

## ブラウザ
* 三大ブラウザ (Chrome,Edge,Firefox) に対応
* `"runtimeExecutable"` や `"firefoxExecutable"` は標準の場所 (macOS であれば `/Applications/***.app` かな) にブラウザが存在しない時にマニュアルで実行ファイルの場所を指定する。そうでなければ不要。
* かつては Chrome, Edge に拡張機能 (Debugger for Chrome, Debugger for Edge) が必要であったが、今は Visual Studio Code のビルトインの機能になった。従って、既にインストールしている場合は削除してよさそう。但し、デバッグ構成の `"type"` 属性が変わっていることに注意。
* Chromium 系の他のブラウザを `"runtimeExecutable"` で指定することも多分可能。

1. 必要なものをインストール

	```sh
	code --install-extension firefox-devtools.vscode-firefox-debug
	# 今や Firefox のみエクステンションが必要になった

	# 必要であれば
	code --install-extension ms-edgedevtools.vscode-edge-devtools
	code --install-extension ms-edgedevtools.network-edge-devtools
	```

2. デバッグ構成の記述

	1. Chrome

		```jsonc
		{
			"name": "debug in Chrome",
			"type": "pwa-chrome",
			"request": "launch",
			"url": "http://localhost:8000/path/to/index.html",
			"webRoot": "${workspaceFolder}",
			"userDataDir": true,
			"runtimeExecutable": "/path/to/Google Chrome.app/Contents/MacOS/Google Chrome"
		}
		```

	2. Edge

		```jsonc
		{
			"name": "debug in Edge",
			"type": "pwa-msedge",
			"request": "launch",
			"url": "http://localhost:8000/path/to/index.html",
			"webRoot": "${workspaceFolder}",
			"userDataDir": true,
			"runtimeExecutable": "/path/to/Microsoft Edge.app/Contents/MacOS/Microsoft Edge"
		}
		```

	3. Firefox

		```jsonc
		{
			"name": "debug in Firefox",
			"type": "firefox",
			"request": "launch",
			"reAttach": true,
			"url": "http://localhost:8000/path/to/index.html",
			"webRoot": "${workspaceFolder}",
			"firefoxExecutable": "/path/to/Firefox.app/Contents/MacOS/Firefox"
		}
		```

* デバッグ対象ファイルの指定の仕方
	* 何かしらの方法でサーバーを起動してアクセスする場合 (上の例と同じ)

		```jsonc
		"url": "http://localhost:8000/path/to/index.html",
		"webRoot": "${workspaceFolder}",
		```

	* 単純にローカルファイルとしてアクセスしたい場合 (絶対パス)

		```jsonc
		"file": "${workspaceFolder}/path/to/index.html",
		```

* Chrome/Edgeで `"userDataDir"` はユーザープロファイルの指定ができる
	* `true` を指定すればこのデバッグ用に一時的にプロファイルを作成する
	* `false` を指定すれば普段使っているプロファイルを利用する
	* あるいはプロファイルのディレクトリの場所を指定することもできる
	* `"userDataDir"` を指定しない場合の初期値がブラウザごとにマチマチなので、例のように明示するのが望ましい
	* Firefoxでは `"profile"` がこれに相当する設定だが、 `true` や `false` は受け付けない。多分標準は `true`

* Firefox ではデバッグ開始時にブレークポイントが作動しなかった。デバッグメニューから再読み込みしたらブレークポイントが作動するようになった。

## 結論

Visual Studio Code は普通にやってもブレークポイントが作動しないことがあって難しい。しかもその原因はどこで調べても見つからないことが多い。デバッガを使うのは簡単だとかあちこちに書いてあるけど、全然そんな風には思えなかった。  
そういえば昔 Visual Studio Code で LaTeX 環境をセットアップしようとしたらかなりてこずった記憶もある。設定をかなりいじらないと使えない。