注目の記事

Visual Studio CodeによるGo言語のデバッグ

2016.04.05

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

藤本です。

最近、仕事じゃないことでGo言語を書く機会が増えています。
業務上、プログラムを触ることがそんなに多くないせいか、記憶力が弱いせいか、基本的にプログラミングはIDEがないと辛いです。
私がIDEに特に期待することは、以下となります。

  • 自動補完
  • デバッグ
  • ジャンプ(というのかな?EclipseでCtrl + Clickで飛ぶやつ)

IntelliJ IDEAやEclipseのGo言語Pluginを試してみましたが、EclipseによるJava開発やPyCharmによるPython開発のような感動は得られず、Atomエディタで開発していました。

そんな中、Visual Studio CodeでGo言語Extensionがあり、使い易いとの噂を聞いて、早速試してみました。結果、今のところはあまり不満ありません。

Visual Studio Codeについては下記記事をご参照ください。

概要

今回はVisual Studio Codeを利用して、Goプログラムをデバッグ実行するまでの手順をご紹介します。

環境

  • OS : OSX YOSEMITE (10.10.5)
  • Visual Studio Code : 0.10.11
  • Go : 1.6

やってみた

Visual Studio Codeのインストール手順は「Setting up Visual Studio Code」をご参照ください。

サンプルプロジェクト

環境変数GOPATH配下にプロジェクトディレクトリを作成します。

今回は以下のような構成とします。

$ tree $GOPATH
/Users/fujimoto.shinji/vscode
└── src
    └── github.com
        └── s-fujimoto
            └── project

Visual Studio Code起動

プロジェクトディレクトリへ移動し、Visual Studio Codeを起動します。

$ cd $GOPATH/src/github.com/s-fujimoto/project
$ code .

project

Visual Studio Codeが起動しました。

Go言語Extensionのインストール

MicrosoftのGithubリポジトリで提供されているvscode-goをインストールします。vscode-goは以下の機能を提供します。

  • カラー化
  • 自動補完 (using gocode)
  • Signature Help (using godoc)
  • スニペット
  • Quick Info (using godef)
  • 参照を開く (using godef)(私の中のジャンプ)
  • 参照検索 (using go-find-references)
  • アウトライン表示 (using go-outline)
  • ワークスペースシンボル検索 (using go-symbols)
  • 名称変更 (using gorename)
  • 保存 -> ビルド (using go build and go test)
  • フォーマット (using goreturns or goimports or gofmt)
  • インポートの追加 (using gopkgs)
  • デバッグ [partially implemented] (using delve)

[cmd+shift+p]でコマンドパレットを開き、[Extensions: Install Extension]を実行します。

project 3

候補に出てくる[Go]をインストールします。

project_4

インストール完了後、再起動を促されますので実施します。

これだけでインストールは完了です。

各種機能

簡単にいくつかの機能をご紹介します。

カラー化

白文字だったgoファイルのソースコードがカラフルになって見やすくなっています。

main_go_-_project_4

自動補完

文字入力すると、候補が表示され、選択すると自動補完されます。

main_go_-_project_2

クイックインフォ

マウスオーバーすると、使い方が表示されます。

screenshot_2016-04-05_9_15_06(2)

ジャンプ

Commandキーを押しながら、クリックするとその実装箇所へ移動します。

screenshot_2016-04-05_9_16_09(2)

(キャプチャから抜けていますが、マウスカーソルが指アイコンになっています)

print_go_-_project

インポートを追加

importを書き忘れても、、、

main_go_-_project_6

補完してくれます。

空白_Skitch_キャンバス

Goの実行

[Command + n]で新規ファイルを作成します。

main.go
package main

import (
	"fmt"
)

func main()  {
    fmt.Println("Go!!!")
}

[F5]、もしくはコマンドパレットから[Debug: Start]を実行します。

最初に実行のConfigurationを定義するlaunch.jsonというJSONファイルが生成されます。

launch_json_-_project 2

もう一度、[F5]、もしくはコマンドパレットから[Debug: Start]を実行します。

launch_json_-_project

DEBUG CONSOLEに「Go!!!」と表示され、実行を確認できます。

デバッグ

ようやく、本題。Go言語のデバッグです。

デバッグにはGo言語のデバッガーであるDELVEを利用します。Visual Studio Codeが裏でDELVEを実行し、デバッグポイントで止めてくれたり、ステップ実行といった機能を提供してくれます。

DELVEを使ったデバッグをOSXで利用する場合、コードサイニング証明書を使ってビルドする必要があります。OSXの標準ユーザーではセキュリティレベルの問題で実行することができません。

コードサイニング証明証作成

OSXはKeychain Accessで自己証明書を作成できます。
Keychain Accessを起動します。

キーチェーンアクセス

メニューの[キーチェーンアクセス] -> [証明書アシスタント] -> [証明書を作成...]を選択し、証明書作成ウィザードを起動します。

下記を設定し、[続ける]を選択します。
名前:delve(任意)
固有名のタイプ:自己署名ルート
証明書のタイプ:コード署名
デフォルトを無効化:on

証明書アシスタント

有効期限は適当に伸ばしておきます。

証明書アシスタント 2

そのままウィザードを進めます

証明書アシスタント 3

証明書アシスタント 4

証明書アシスタント 5

証明書アシスタント 6

証明書アシスタント 7

証明書アシスタント 8

証明書の場所のキーチェーンにシステムを指定します。

証明書アシスタント 9

自己署名コードサイニング証明書が作成されました。

キーチェーンアクセス

コードサイニング証明書にアクセスするたびに確認が出るのが面倒なので、証明書のアクセス権限に信頼を与えます。変な証明書を信頼しないように気をつけてください。

証明書を右クリックし、「情報を見る」を選択します。
「信頼」を展開し、この証明書を使用するときを「常に信頼」を設定します。

delve

DELVEインストール

まずはDELVEをGithubリポジトリからダウンロードします。

$ git clone https://github.com/derekparker/delve
Cloning into 'delve'...
remote: Counting objects: 6420, done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 6420 (delta 0), reused 0 (delta 0), pack-reused 6414
Receiving objects: 100% (6420/6420), 10.18 MiB | 2.42 MiB/s, done.
Resolving deltas: 100% (3758/3758), done.
Checking connectivity... done.

環境変数CERTに作成したコードサイニング証明書の名前を指定し、make installを実行します。

$ cd delve

$ CERT=delve make install
go install -ldflags="-s -X main.Build=a20bdf4b3b884122ec665b8638c1ff337afd008d" github.com/derekparker/delve/cmd/dlv
# github.com/derekparker/delve/proc
clang: warning: argument unused during compilation: '-pthread'
# github.com/derekparker/delve/proc
clang: warning: argument unused during compilation: '-pthread'
codesign -s "delve" /Users/fujimoto.shinji/vscode/bin/dlv

GOPATH/bin配下にdlvが作成されていることを確認します。

$ ls -l $GOPATH/bin/dlv
-rwxr-xr-x  1 fujimoto.shinji  staff  10758240  4  5 11:47 /Users/fujimoto.shinji/vscode/bin/dlv

簡単に動作確認。

$ cd $GOPATH/src/github.com/s-fujimoto/project

$ $GOPATH/bin/dlv debug main.go
could not launch process: could not fork/exec

Oh...forkできない。

調べたところ、Keychainの変更を有効にするためにはtaskgatedを再起動しなくてはいけないようです。

$ sudo kill `pgrep taskgated`

$ $GOPATH/bin/dlv debug main.go
Type 'help' for list of commands.
(dlv)

実行できました。

(dlv) help
The following commands are available:
    help (alias: h) ------------- Prints the help message.
    break (alias: b) ------------ break [name] <linespec>
    trace (alias: t) ------------ Set tracepoint, takes the same arguments as break.
    restart (alias: r) ---------- Restart process.
    continue (alias: c) --------- Run until breakpoint or program termination.
    step (alias: s) ------------- Single step through program.
    step-instruction (alias: si)  Single step a single cpu instruction.
    next (alias: n) ------------- Step over to next source line.
    threads --------------------- Print out info for every traced thread.
    thread (alias: tr) ---------- Switch to the specified thread.
    clear ----------------------- Deletes breakpoint.
    clearall -------------------- clearall [<linespec>]. Deletes all breakpoints. If <linespec> is provided, only matching breakpoints will be deleted.
    goroutines ------------------ goroutines [-u (default: user location)|-r (runtime location)|-g (go statement location)] Print out info for every goroutine.
    goroutine ------------------- Sets current goroutine.
    breakpoints (alias: bp) ----- Print out info for active breakpoints.
    print (alias: p) ------------ Evaluate a variable.
    set ------------------------- Changes the value of a variable.
    sources --------------------- Print list of source files, optionally filtered by a regexp.
    funcs ----------------------- Print list of functions, optionally filtered by a regexp.
    types ----------------------- Print list of types, optionally filtered by a regexp.
    args ------------------------ Print function arguments, optionally filtered by a regexp.
    locals ---------------------- Print function locals, optionally filtered by a regexp.
    vars ------------------------ Print package variables, optionally filtered by a regexp.
    regs ------------------------ Print contents of CPU registers.
    exit (alias: quit | q) ------ Exit the debugger.
    list (alias: ls) ------------ list <linespec>.  Show source around current point or provided linespec.
    stack (alias: bt) ----------- stack [<depth>] [-full]. Prints stack.
    frame ----------------------- Sets current stack frame (0 is the top of the stack)
    source ---------------------- Executes a file containing a list of delve commands
    disassemble (alias: disass) - Displays disassembly of specific function or address range: disassemble [-a <start> <end>] [-l <locspec>]
    on -------------------------- on <breakpoint name or id> <command>. Executes command when the specified breakpoint is hit (supported commands: print <expression>, stack [<depth>] [-full] and goroutine)
    condition (alias: cond) ----- cond <breakpoint name or id> <boolean expression>. Specifies that the breakpoint or tracepoint should break only if the boolean expression is true.
(dlv) step
> _rt0_amd64_darwin() /usr/local/Cellar/go/1.6/libexec/src/runtime/rt0_darwin_amd64.s:8 (PC: 0x55de0)
     3:	// license that can be found in the LICENSE file.
     4:
     5:	#include "textflag.h"
     6:
     7:	TEXT _rt0_amd64_darwin(SB),NOSPLIT,$-8
=>   8:		LEAQ	8(SP), SI // argv
     9:		MOVQ	0(SP), DI // argc
    10:		MOVQ	$main(SB), AX
    11:		JMP	AX
    12:
    13:	// When linking with -shared, this symbol is called when the shared library
(dlv) continue
Go!!!
Process 23126 has exited with status 0

うん、Step実行もできますし、実行結果も確認できます。

Visual Studio Codeからのデバッグ

Visual Studio Codeに戻りまして、動作確認します。

まずはブレイクポイントを設定します。

main_go_-_project

[F5]キーでデバッグ実行します。

main_go_-_project 8

デバッグポイントで止まっています。
上のパネルでContinue、Step Over、Step In、Step Out、Restart、Stopが操作できます。
左ペインに変数の中身を確認できます。
他にもWatchで変数の遷移を追いかけたり、CALL STACKで追いかけたり、Exceptionで止めたりとIDEに求めるデバッグの機能は備わっています。

感想

これこれ!こういうのを求めてました。
まだサンプルコードしか書いていないですが良さ気!
地味ですが、code .でプロジェクトを開き、.vscodeディレクトリ内でプロジェクト固有の設定が簡単にできるところが好きです。
これからドシドシ使ってみて良い機能があればブログでまとめてレポートします。

参考URL