いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

Goメモ-586 (デバッグビルドとリリースビルド時によく利用するフラグ)

関連記事

GitHub - devlights/blog-summary: ブログ「いろいろ備忘録日記」のまとめ

概要

以下、自分用のメモです。たまに、使いたいときに忘れているのでここにメモメモ。。。

似た内容を以前にも記載しているのかもしれませんが、、。

ガッチリとデバッグしたい場合は「最適化」と「インライン化」を無効にしてビルドするのが定石です。

ガッチリとリリースビルドしたい場合は、「シンボル」と「DWARF(デバッグ情報)」を除去してビルドするのが定石です。

試してみる

ソースコード

実装内容に意味はないです。

package main

import (
    "io"
    "log"
    "sync"
    "time"
)

func main() {
    log.SetFlags(0)
    log.SetOutput(io.Discard)

    if err := run(); err != nil {
        panic(err)
    }
}

// この関数は最適化が有効な場合、直接 v*2 になる可能性があり
// インライン化が有効な場合、インライン化される可能性がある
func calc(v int) int {
    v1 := v
    v2 := 2
    return v1 * v2
}

func run() error {
    const (
        COUNT   = 10000000
        WORKERS = 4
    )
    var (
        ch = make(chan int)
        wg sync.WaitGroup
    )

    // producer
    wg.Add(1)
    go func(ch chan<- int) {
        defer wg.Done()
        defer close(ch)

        for i := range COUNT {
            ch <- calc(i)
        }
    }(ch)

    time.Sleep(10 * time.Millisecond)

    // consumer
    for range WORKERS {
        wg.Add(1)
        go func(ch <-chan int) {
            for v := range ch {
                log.Println(v)
            }
        }(ch)
    }

    wg.Done()

    return nil
}

デバッグ

go build -gcflags "all=-N -l" -o debug main.go
オプションの意味
      # gcflags の all=-N -l の意味 (goコンパイラに対しての指示) (go tool compile -help)
      #   all= は全てのパッケージが対象という意味
      #   -N   は最適化無効という意味 (No optimization)
      #   -l   はインライン化無効という意味 (No inlining)

リリース

go build -ldflags "-s -w" -o release main.go
オプションの意味
      # ldflags の -s -w の意味 (リンカに対しての指示) (go tool link -help)
      #    -s   はシンボルテーブル削除という意味
      #    -w   はDWARF情報削除という意味(デバッグ情報)

Taskfile.yml

# https://taskfile.dev

version: '3'

vars:
  RE1: main\.go.*inlining call.*$

tasks:
  default:
    cmds:
      # gcflags の all=-m -N -l の意味 (goコンパイラに対しての指示) (go tool compile -help)
      #   all= は全てのパッケージが対象という意味
      #   -m   はビルド時のコンパイラの詳細情報を出力せよという意味
      #   -N   は最適化無効という意味 (No optimization)
      #   -l   はインライン化無効という意味 (No inlining)
      - cmd: go build -gcflags "all=-m -N -l" -o debug main.go 2>&1 | grep "{{.RE1}}"
        ignore_error: true
      - cmd: go build -gcflags "all=-m" -o normal main.go 2>&1 | grep "{{.RE1}}"
        ignore_error: true
      # ldflags の -s -w の意味 (リンカに対しての指示) (go tool link -help)
      #    -s   はシンボルテーブル削除という意味
      #    -w   はDWARF情報削除という意味(デバッグ情報)
      - cmd: go build -gcflags "all=-m" -ldflags "-s -w" -o release main.go 2>&1 | grep "{{.RE1}}"
        ignore_error: true
      - ls -l {normal,debug,release} | awk 'NF>1 {print $5, $NF}'

実行すると以下のような感じです。

task: [default] go build -gcflags "all=-m -N -l" -o debug main.go 2>&1 | grep "main\.go.*inlining call.*$"
task: [default] go build -gcflags "all=-m" -o normal main.go 2>&1 | grep "main\.go.*inlining call.*$"
./main.go:55:16: inlining call to log.Println
./main.go:60:9: inlining call to sync.(*WaitGroup).Done
./main.go:44:14: inlining call to calc
./main.go:40:16: inlining call to sync.(*WaitGroup).Done
./main.go:57:4: inlining call to run.func2
./main.go:57:4: inlining call to log.Println
./main.go:11:14: inlining call to log.SetFlags
./main.go:12:15: inlining call to log.SetOutput
./main.go:11:14: inlining call to log.(*Logger).SetFlags
./main.go:11:14: inlining call to atomic.(*Int32).Store
task: [default] go build -gcflags "all=-m" -ldflags "-s -w" -o release main.go 2>&1 | grep "main\.go.*inlining call.*$"
./main.go:55:16: inlining call to log.Println
./main.go:60:9: inlining call to sync.(*WaitGroup).Done
./main.go:44:14: inlining call to calc
./main.go:40:16: inlining call to sync.(*WaitGroup).Done
./main.go:57:4: inlining call to run.func2
./main.go:57:4: inlining call to log.Println
./main.go:11:14: inlining call to log.SetFlags
./main.go:12:15: inlining call to log.SetOutput
./main.go:11:14: inlining call to log.(*Logger).SetFlags
./main.go:11:14: inlining call to atomic.(*Int32).Store
task: [default] ls -l {normal,debug,release} | awk 'NF>1 {print $5, $NF}'
2279432 debug
2313124 normal
1503416 release

デバッグビルド用のフラグを設定した場合、インライン化が実施されていませんね。

何故か、通常時よりデバッグビルド用のフラグを設定した方が少しファイルサイズが減るのは謎。

参考情報

Goのおすすめ書籍


過去の記事については、以下のページからご参照下さい。

サンプルコードは、以下の場所で公開しています。