はじめに
Google App Engineではdev_appserver.pyというスクリプトを実行することで、開発環境が立ち上がります。
GAE/Goの環環境でデバッガを使いたいのですが、dev_appserver.pyでは、go build
する際のオプションを渡すことができず、必ず最適化された状態でコンパイルされてしまいます。デバッグする際には最適化しない状態で正しくソースコードとの対応を取りながらデバッグをしたいものです。(最適化により命令順序が変更されてしまうとデバッグしづらい)
この記事では、最適化オプションをオフにしてビルドする方法とデバッガの対応状況について説明します。
結論だけを見たい人は「最適化オプションをオフにする」を見てください。
最適化オプション
go build
のヘルプを確認してみると--gcflags
というオプションがあることがわかります。
$ go build --help
略
-gcflags 'arg list'
arguments to pass on each go tool compile invocation.
これだけだと詳細がわかりませんが、go build
は実際にコンパイルする際にはgo tool compile
コマンドを実行しているのでこちらのcompile - The Go Programming Languageを確認します。
すると以下の2つがデバッグの際には必要になりそうなことがわかります。最適化とインライン展開をやめることでソースコードと実行バイナリが正しく対応をとることができるようになります。
-N
Disable optimizations.
-l
Disable inlining.
つまりdev_appserver.pyでビルドする際に、以下のようなことができればよさそうです。
$ go build -gcflags '-N -l'
dev_appserver.pyによるビルド方法
続いては、どのようにdev_appserver.pyがビルドしているのかを確認したいと思います。
dev_appserver.pyを起動するとAPIサーバ、開発者が作成した各module、admin consoleのためののスレッドが立ち上がります。
ソースコードをビルドするのは、moduleのスレッドになります。またファイルの更新を監視しており、変更があった場合には自動的にビルドが実行されます。
ビルドはSDK内部にある$(SDK_PATH)/goroot/bin/go-app-builder
というツールを使って実現しています。基本的にはgo build
のようなものですが、GAE/Go専用にカスタマイズされています。
go-app-builder
の内部実装は$(SDK_PATH)/goroot/src/cmd/go-app-builder
に存在するgoのソースコードです。
go-app-builderのヘルプを読んでみましょう。
$ (SDK_PATH)/goroot/src/cmd/go-app-builder --help
略
-gcflags 'arg list'
arguments to pass on each go tool compile invocation.
go build
と同様に-gcflags
を渡せるようです。つまりgo-app-builder
のソースコードを改変する必要がないことがわかりました。そこでdev_appserver.pyがどのようにgo-app-builderを実行しているかさえわかれば対応できそうです。
go-app-builder
でgrepしてみると$(SDK_PATH)/google/appengine/tools/devappserver2/go_application.py
でgo-app-builderを実行していることがわかります。
最適化オプションをオフにする
$(SDK_PATH)/google/appengine/tools/devappserver2/go_application.pyの86行目あたりにgo-app-builderのオプションがあるので-gcflags
を追加します。
gab_args = [
_GAB_PATH,
'-app_base', application_root,
'-arch', arch,
'-dynamic',
'-goroot', GOROOT,
'-gopath', os.environ.get('GOPATH', GOPATH),
'-nobuild_files', '^' + str(nobuild_files),
'-incremental_rebuild',
'-unsafe',
+ '-gcflags', '-N -l',
]
これで実際に動かしてみると問題なくビルドできていることが確認できます。
またビルド時のログを出力してみるとコンパイル時にオプションが渡されていることまでは確認することができました。
しかし本当に最適化されずにビルドできたかどうかを確認するすべがわかりませんでした。バイナリが生成されればバイナリから最適化されているかどうか確認できるのですが・・・
dev_appserver.pyのコマンドラインオプションで最適化のオンオフを切り替える
先程は無理やりソースコードを改変しましたが、理想としてはdev_appserver.pyにオプションを渡して最適化のオンオフを切り替えたいところです。
GAE/PHPではこのようなオプションが用意されています。
$ dev_appserver.py --help
--php_remote_debugging [PHP_REMOTE_DEBUGGING]
enable XDebug remote debugging (default: False)
PHP同様の変更を加えればGoでもいけるのではないかと考えてソースコードを読み進めましたが、内部でProtocol Buffersが使われており、自動生成されたコードが存在するのですが、肝心の.proto
ファイルがSDK内に含まれていないため頓挫してしまいました。
おわりに
これらについてはGogland開発者がGoogleに提案しているのですが長い間動きがありません。もしかしたらGoogleでは専用の開発環境を持っていてdev_appserver.pyをあまり重要視していないのかもしれませんね・・・