Help us understand the problem. What is going on with this article?

Google App Engine Goの開発環境dev_appserver.pyで最適化オプションをオフにする

More than 3 years have passed since last update.

はじめに

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をあまり重要視していないのかもしれませんね・・・

参考

sonatard
組み込みC言語ネットワークスタック開発者からGoバックエンドエンジニアにジョブチェンジしました。 最近はTypeScript, React(Hooks), GraphQL, SwiftUIに夢中。
https://github.com/sonatard/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away