Visual Studio CodeでGo言語のデバッグ環境を整える

# はじめに

Visual Studio Code(以下VSCode)にてGo言語開発のデバッグができるようにするまでを示します。

# 前提条件

__追記 2023年3月7日更新 以下の環境で動作確認済み__

* MacOS
  * OS version: 12.6 Monterey
  * Chip: Apple M1
* Goをインストール済み
  * go version go1.20.1 darwin/arm64
* `$GOPATH`を設定済み
* `$GOPATH/bin`を環境変数`$PATH`へ追加済み
* VSCodeをインストール済み
  * Version: 1.76.0

# 設定内容

## delveをインストール

VSCodeでGoのデバッグをするには[delve](https://github.com/go-delve/delve)というデバッガツールをインストールする必要があります。delve自体は単独のコマンドラインで利用するGo言語用のデバッガでGo言語VSCode拡張機能がそれを利用しています。

https://github.com/go-delve/delve

Xcodeにて必要なツールをインストール

```terminal
xcode-select --install
```

既にインストール済みの場合は下記のエラーが出ます。(問題無し)

```
xcode-select: error: command line tools are already installed, use "Software Update" to install updates
```

delveをインストール

```terminal
go install github.com/go-delve/delve/cmd/dlv@latest
```

利用するXCodeのDeveloperモードをEnableにしない場合、デバッグを実行するたびに許可を求められることになります。ので、以下のコマンドで事前にEnableにしておきます。

```terminal
sudo /usr/sbin/DevToolsSecurity -enable
```

上記の課程で問題が発生してしまう場合は、[こちらの公式ページ](https://github.com/go-delve/delve/blob/master/Documentation/installation/README.md)を確認してみてください。

※ ~~MacOSへのインストールでは`brew`を利用してOSへインストールも可能ですが、証明書取得の手間が出るので`$GOPATH\bin`を環境変数`$PATH`へ追加し、`go get`でdelveのバイナリを`$GOPATH\bin`へインストールした方がやりやすいです。~~
【追記 2020年11月15日 時点】 [公式ドキュメント](https://github.com/go-delve/delve/blob/master/Documentation/installation/linux/install.md)にはMacOSにてHomebrewでのインストールはサポートされなくなり記載はなくなっています。

dlvコマンドがインストールされたか確認

```terminal
$ which dlv
YOUR_GOPATH/bin/dlv
$ dlv version
Delve Debugger
Version: 1.20.1
Build: $Id: 96e65b6c615845d42e0e31d903f6475b0e4ece6e $
```

## VSCodeにGo言語の拡張機能をインストール

VSCodeにて下記のGo言語用の拡張機能(以降vscode-goと表記)をインストールしていなければしましょう。

https://marketplace.visualstudio.com/items?itemName=ms-vscode.Go

## VSCodeの`$GOPATH`を確認

SHELL設定の関係などで`$GOPATH`が普段のターミナルとVSCodeでは異なる場合があるので確認します。

統合ターミナルを開く(ショートカット control+` または Command+J)

```terminal
$ go env GOPATH
```

出力が、想定した`$GOPATH`であることを確認します。

### $GOPATHが想定したものでない場合

vscode-goではデフォルトでは`$GOPTH`は`$HOME/go`です。

これを変更するには[VSCodeのユーザーまたはWorkSpace設定](https://code.visualstudio.com/docs/getstarted/settings)である`settings.json`にて下記の項目を修正する必要があります。

`go.gopath` => デフォルトを上書きする$GOPATHを記載する。

```json
  "go.gopath": "/home/user/examplepath/go",
```

* 公式ドキュメントページ
  * https://github.com/golang/vscode-go/blob/master/docs/gopath.md#gopath
  * https://github.com/golang/vscode-go/blob/master/docs/settings.md#go.gopath

## デバッグ

デバッグ対象のプログラムがあるディレクトリを開きデバッグビューを開きます。

ブレークポイントを指定しデバッグ対象のファイルを開いた状態で下記スクショのようにデバッグタブから"Run and Debug"をクリックするとdlvが起動されデバッグが開始されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91562/9648447d-f162-2af9-865b-931d714d56d2.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91562/2012c13c-ebf2-5e9b-9244-4dbae5631581.png)

~~このとき以下の`launch.json`ファイルがVSCode上で開いているディレクトリに作成されます。~~

【追記 2021年6月6日時点】 遅くともvscode-goのバージョンv0.25.1ではLaunchした段階で自動的に`launch.json`は作成されず失敗時に選択で作成する仕様になっています。`launch.json`を作成せずに実行できている場合は下記の内容をデフォルト値として実行されています。

デバッグがエラーになる場合は指定ファイル(`${fileDirname}`)としての開いているファイルを確認し変更するか、`launch.json`を修正する必要があります。

```..vscode/launch.json
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Launch",
            "type": "go",
            "request": "launch",
            "mode": "auto",
            "program": "${fileDirname}",
            "env": {},
            "args": []
        }
    ]
}
```

### `launch.json`にて重要なフィールド

#### `"program"`
  
デバッグ対象の実行ファイルまたはエントリポイントのファイルが存在するディレクトリのPathを指定します。
デフォルトでは`${fileDirname}`という予約語が設定されており、これは「現在開いているファイルのディレクトリ名」を意味しています。

下記はVSCodeでの`program`に対する予約語の一覧です。

|予約語|意味|
|:------------------|:-------------------|
| `${workspaceFolder}`&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| VSコードで開いたディレクトリのパス |
| `${workspaceFolderBasename}` | スラッシュのないVSコードで開いたフォルダの名前|
| `${file}` | 現在開いているファイル |
| `${relativeFile}` | workspaceFolderを基準とした現在開いているファイル |
| `${fileBasename}` | 現在開いているファイルのベース名 |
| `${fileBasenameNoExtension}` | ファイル拡張子を持たない現在開いているファイルのベース名 |
| `${fileDirname}` | 現在開いているファイルのディレクトリ名 |
| `${fileExtname}` | 現在開いているファイルの拡張子 |
| `${cwd}` | 起動時のタスクランナーの現在の作業ディレクトリ |
| `${lineNumber}` | 現在開いているファイル内にて選択されている行番号 |

#### `"mode"`

デフォルトは`auto`モード。上記実行では`debug`モードで起動しており、`program`で指定したプログラムをコンパイルしデバッガー配下で実行します。

以下は`"mode"`タグの一覧です。

|mode名 |意味|
|:-------|:------|
| `auto`   &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  | 起動時に自動で判断して下記のモードのいづれかになる。 [デフォルト] |
| `debug`   | プログラムフォルダの内容をコンパイルし、デバッガの下で起動する。 |
| `test`    | プログラムフォルダ内のテストをデバッグする。 単一のテストをデバッグするには、`test.run`とTest名を`args`として渡す。 さらに、`-test.v`を渡すと冗長出力も得られる。 |
| `exec`   | プログラムで指定されたビルドされたバイナリを実行する。 |
| `remote`   | 遠隔のヘッドレスDelveサーバに接続する。 リモートマシンでDelveを手動で実行し、リモートマシンを指す追加のremotePath、host、portデバッグ設定オプションを指定する必要がある。"request"は`attach`にする。 |
| `local`    | ローカルマシンですでに動いているプロセスのデバッグを行う。"request"は`attach`にする。 |

`debug`, `test`, `exec`モードはデバッガをきっかけに起動するため`"request"`タグは`launch`ですが、`remote`、`local`モードはすでに起動しているプロセスに対してデバッグをするためのモードなので`"request"`タグは`attach`に指定します。

詳細は下記の公式ドキュメントを参照
https://github.com/Microsoft/vscode-go/wiki/Debugging-Go-code-using-VS-Code

# Goのユニットテストのコードをデバッグするには

下記リンクの別記事を作りました。

[VSCodeでGoのユニットテストをデバッグしよう](https://qiita.com/momotaro98/items/10ae87b21903dd54601c)

# 参考

* https://code.visualstudio.com/docs/editor/debugging
* https://stackoverflow.com/a/39062734
* https://code.visualstudio.com/docs/editor/variables-reference
* https://github.com/Microsoft/vscode-go/wiki/Debugging-Go-code-using-VS-Code
* http://hara-yuki.com/how-to-build-go-development-environment-with-a-debugger.html