go run はプログラムのコンパイルと実行を一度に行い、バイナリを残しません。go build はコンパイルして、カレントディレクトリに実行ファイルを残します。go install はコンパイルして、実行ファイルを $HOME/go/bin に置きます。3つともネイティブのマシンコードにコンパイルし、何かを解釈実行するものはありません。
| コマンド | コンパイル | 実行 | バイナリを残す | バイナリの置き場所 |
|---|---|---|---|---|
go run . | する | する | 残さない | 一時ディレクトリ、実行後に削除 |
go build | する | しない | 残す | カレントディレクトリ(または -o path) |
go install | する | しない | 残す | $GOBIN、なければ $GOPATH/bin |
以下のプログラムは、このページの例で使うものです。エディタは go run と同じように実行します。
go run
go run はパッケージ(通常はカレントディレクトリを表す .)か、.go ファイルのリストを受け取ります。
go run .
go run main.go
go run ./cmd/server
パッケージより後ろに書いたものはすべて、引数としてプログラムに渡されます。
go run . --port 8080 verbose
version: dev
built for: linux/amd64
args: [--port 8080 verbose]
go run main.go より go run . を使いましょう。ファイル名を指定するとそのファイルだけがコンパイルされるので、パッケージに2つ目のファイルができた途端、そちらで定義した関数が undefined と報告されます。このエラーはパッケージとインポートのページで詳しく扱っています。
go run は、リモートのプログラムを特定のバージョンでインストールせずに実行することもできます。コード生成ツールで便利です。
go run golang.org/x/tools/cmd/stringer@v0.30.0 -type=Color
go build
go build はカレントディレクトリのパッケージをコンパイルします。main パッケージなら実行ファイルを書き出し、ライブラリのパッケージならコンパイルしてエラーを報告し、結果を捨てます。
go mod init example.com/hello
go build
ls
go.mod hello main.go
バイナリの名前は次のルールで決まります。
| 実行したコマンド | バイナリ名 |
|---|---|
モジュール example.com/hello で go build | hello |
go build ./cmd/server | server |
go build main.go | main(最初のファイル名から) |
go build -o bin/app . | bin/app |
上記いずれかを GOOS=windows で | 同じ名前に .exe を付けたもの |
いつも使うことになる形があと2つあります。
go build ./... # compile every package in the module
go vet ./... # static checks, covered below
./... は「このディレクトリとその下のすべてのディレクトリ」という意味です。main パッケージが複数ある状態で go build ./... を実行してもバイナリは書き出されません。「全部コンパイルできるか」をすばやく確認する用途になります。
便利なビルドフラグ
| フラグ | 効果 |
|---|---|
-o name | 出力ファイルまたはディレクトリ |
-v | コンパイル中のパッケージ名を表示 |
-race | データ競合検出器付きでビルド(遅く、バイナリも大きくなる。テスト用) |
-trimpath | 再現可能なビルドのため、ローカルのファイルシステムのパスをバイナリから除く |
-ldflags "-s -w" | シンボルテーブルとDWARFのデバッグ情報を除き、バイナリを小さくする |
-ldflags "-X main.version=1.4.0" | リンク時に文字列変数を設定する |
-tags name | //go:build name 制約で守られたファイルを含める |
多くのGoプロジェクトは、この -X フラグでバイナリにバージョンを埋め込みます。使えるのはパッケージレベルの string 変数だけです(定数には使えません)。
go build -o app -ldflags "-X main.version=1.4.0" .
./app
version: 1.4.0
built for: linux/amd64
args: []
バイナリには、モジュールのバージョンと、Go 1.18以降はビルド元のVCSのコミットも記録されます。go version -m ./app でそれらを表示でき、プログラムからは runtime/debug.ReadBuildInfo で読み取れます。
go install
go install は go build とまったく同じようにビルドし、実行ファイルを $GOBIN に移動します。GOBIN が設定されていなければ $GOPATH/bin(デフォルトは $HOME/go/bin)です。
go install .
go env GOPATH
最もよくある用途は、Goで書かれたツールのインストールです。@version を付けると、go.mod に触れずにプログラムをインストールできます。
go install golang.org/x/tools/gopls@latest
go install honnef.co/go/tools/cmd/staticcheck@latest
インストール後にシェルがツールを見つけられない場合は、$HOME/go/bin が PATH に入っていません。シェルのプロファイルに export PATH=$PATH:$(go env GOPATH)/bin を追加してください。
GOOSとGOARCHでクロスコンパイルする
Goは、どのマシンからでも、追加のツールチェーンなしで別のOSやCPU向けにビルドできます。ビルドコマンドに2つの環境変数を設定します。
GOOS=linux GOARCH=amd64 go build -o app-linux-amd64 .
GOOS=linux GOARCH=arm64 go build -o app-linux-arm64 .
GOOS=darwin GOARCH=arm64 go build -o app-macos .
GOOS=windows GOARCH=amd64 go build -o app.exe .
PowerShellでは環境変数の設定方法が異なります。
$env:GOOS = "linux"; $env:GOARCH = "amd64"; go build -o app-linux .
よく使う組み合わせは次のとおりです。
| GOOS | GOARCH | 対象 |
|---|---|---|
linux | amd64 | 大半のサーバーとコンテナ |
linux | arm64 | AWS Graviton、64ビットOSのRaspberry Pi |
darwin | arm64 | AppleシリコンのMac |
darwin | amd64 | IntelのMac |
windows | amd64 | 64ビットWindows |
js | wasm | ブラウザで動くWebAssembly |
go tool dist list はサポートされている組み合わせをすべて表示します(Go 1.24では48個)。
クロスコンパイルがこれほど簡単なのは、純粋なGoのコードの場合だけです。cgoを使うパッケージ(Cのコード、たとえば一部のSQLiteドライバ)には、対象向けのCクロスコンパイラが必要です。クロスコンパイル時はcgoがデフォルトで無効になり、CGO_ENABLED=0 を明示的に設定すると完全に静的なLinuxバイナリも得られます。最小限の scratch やdistrolessのコンテナイメージではこれが欲しいところです。
go fmtとgo vet
どのワークフローにも、そしてCIにも入れておきたいチェックが2つあります。
go fmt はファイルを公式の唯一のスタイルに書き換えます。タブ、そろえたフィールド、正規化された空白です。これは gofmt -l -w のラッパーです。
go fmt ./...
gofmt -l . # list files that are not formatted; empty output means clean
go vet は、コンパイルは通るもののほぼ確実に間違っているコードを報告します。Printfの書式の不一致が典型例です。
package main
import "fmt"
func main() {
count := 3
fmt.Printf("%s items\n", count)
}
go vet ./...
# example.com/hello
# [example.com/hello]
./main.go:7:2: fmt.Printf format %s has arg count of wrong type int
このプログラムはコンパイルでき、%!s(int=3) items と表示します。vetが捕まえるためにあるのは、まさにこの種のバグです。他にも、sync.Mutex の値コピー、到達不能なコード、構文が間違った構造体タグ、呼ばれない context.CancelFunc などをチェックします。go test はこれらのチェックの一部を自動で実行しますが、go build は何も実行しません。
その他のgoサブコマンド
| コマンド | 用途 |
|---|---|
go test ./... | テストを実行する |
go mod tidy | 足りない依存関係を追加し、使っていないものを削除する |
go get pkg@version | 依存関係を追加または変更する |
go clean -cache | ビルドキャッシュを空にする |
go env | Goの設定を表示する |
go doc fmt.Println | ターミナルでドキュメントを表示する |
go list -m all | ビルドに含まれるすべてのモジュールを一覧表示する |
2回目のビルドが速い理由
Goはコンパイル済みのパッケージをビルドキャッシュ(go env GOCACHE)に保存します。再ビルドでは、ソースか依存関係が変わったパッケージだけを再コンパイルするので、変更のないプロジェクトで go run . を実行するとほぼ即座に始まります。Goのバージョンや環境変数を変えた後にビルドの挙動がおかしくなったら、go clean -cache でキャッシュを消せます。必要になることはめったにありません。
よくある質問
go runとgo buildの違いは何ですか?
go run はプログラムを一時ディレクトリにコンパイルして実行し、バイナリを捨てます。go build はプログラムをコンパイルしてカレントディレクトリにバイナリを書き出すので、もう一度実行したり別の場所にコピーしたりできます。開発中は go run、実行ファイルが必要なときは go build を使います。
go buildの出力ファイル名はどう指定しますか?
-o を使います。go build -o myapp . は myapp を書き出します(Windowsでは -o myapp.exe と自分で書きます)。-o がない場合、go build はパッケージのインポートパスの最後の要素か、.go ファイルを渡したときは最初のファイルの名前をバイナリ名にし、Windows向けのビルドでは .exe を付けます。
GoをLinuxやWindows向けにクロスコンパイルするには?
ビルド時に GOOS と GOARCH を設定します:GOOS=linux GOARCH=amd64 go build -o app-linux . や GOOS=windows GOARCH=amd64 go build .(こちらは .exe を生成します)。純粋なGoのコードなら追加のツールチェーンは不要です。go tool dist list でサポートされている組み合わせがすべて表示されます。
go installはバイナリをどこに置きますか?
設定されていれば $GOBIN に、そうでなければ $GOPATH/bin(デフォルトは $HOME/go/bin)に置きます。インストールしたツールを名前で実行するには、そのディレクトリを PATH に追加します。go install example.com/tool@latest なら、モジュールに追加せずにツールをインストールできます。
go buildはgo vetを実行しますか?
しません。go build はコンパイルするだけです。go test は go vet のチェックの一部を自動で実行しますが、すべてのチェックを行うには go vet ./... を自分で実行します。一般的にはCIで gofmt -l . と並べて実行します。