コマンドライン

Go のコマンドにはツールチェーン一式が含まれており、これらのコマンドはドキュメント、フォーマット、コードチェック、コンパイル、テスト、依存関係管理など多岐にわたり、Go 開発のあらゆる側面をカバーしています。
bug バグ報告
build パッケージと依存関係のコンパイル
clean オブジェクトファイルのクリーンアップ
doc ソースコードのドキュメント表示
env Go 環境変数の表示
fix Go バージョン変更による API 互換性問題の修正
fmt ソースコードのフォーマット
generate コード生成
get 依存関係の追加
install パッケージのインストールとコンパイル
list パッケージ/モジュール一覧
mod モジュール管理
work ワークスペース管理
run コンパイルと実行
test テスト
tool 指定された Go ツールの実行
version Go バージョン情報の表示
vet ソースコードの潜在的な問題のスキャンと報告この記事では、それらの使用方法を簡単に紹介するだけです。すべての内容は公式ドキュメントを参考にしており、詳細については cmd/go をご覧ください。
help
最初に覚えるべきは help コマンドで、これを使用してコマンドの用法を読むことができます。2 つの用法があります。特定のコマンドの簡単な情報を取得したい場合は、コマンドの後に -h フラグを追加します。例えば
$ go env -h
usage: go env [-json] [-u] [-w] [var ...]
Run 'go help env' for details.go はコマンドの用法を簡潔に表示し、より詳細な情報を取得するには help コマンドを使用する必要があることを示しています
$ go help env
usage: go env [-json] [-u] [-w] [var ...]
Env prints Go environment information.
By default env prints information as a shell script
(on Windows, a batch file). If one or more variable
names is given as arguments, env prints the value of
each named variable on its own line.
The -json flag prints the environment in JSON format
instead of as a shell script.
The -u flag requires one or more arguments and unsets
the default setting for the named environment variables,
if one has been set with 'go env -w'.
The -w flag requires one or more arguments of the
form NAME=VALUE and changes the default settings
of the named environment variables to the given values.
For more about environment variables, see 'go help environment'.help コマンドをうまく活用することで、コマンドに関する多くの情報を取得できます。
doc
$ go doc -h
Usage of [go] doc:
go doc
go doc <pkg>
go doc <sym>[.<methodOrField>]
go doc [<pkg>.]<sym>[.<methodOrField>]
go doc [<pkg>.][<sym>.]<methodOrField>
go doc <pkg> <sym>[.<methodOrField>]
For more information run
go help doc
Flags:
-C dir
change to dir before running command
-all
show all documentation for package
-c symbol matching honors case (paths not affected)
-cmd
show symbols with package docs even if package is a command
-short
one-line representation for each symbol
-src
show source code for symbol
-u show unexported symbols as well as exporteddoc コマンドは、指定されたパッケージ、定数、関数、型、変数、メソッド、さらには構造体フィールドのドキュメントコメントを出力します。パラメータなしで実行すると、現在のパッケージのコメントを出力します
$ go doc特定のパッケージを参照することもできます。例えば runtime パッケージのドキュメントコメントを参照する場合
$ go doc runtime
package runtime // import "runtime"
Package runtime contains operations that interact with Go's runtime system,
such as functions to control goroutines. It also includes the low-level type
information used by the reflect package; see reflect's documentation for the
programmable interface to the run-time type system.
......または特定の型
$ go doc unsafe.Pointer
package unsafe // import "unsafe"
type Pointer *ArbitraryType
Pointer represents a pointer to an arbitrary type. There are four special
operations available for type Pointer that are not available for other
types:
- A pointer value of any type can be converted to a Pointer.
- A Pointer can be converted to a pointer value of any type.
- A uintptr can be converted to a Pointer.
- A Pointer can be converted to a uintptr.
...または特定の関数
$ go doc runtime.GC
package runtime // import "runtime"
func GC()
GC runs a garbage collection and blocks the caller until the garbage
collection is complete. It may also block the entire program.以下の一般的なフラグがあります
-u:プライベート型を表示-all:指定されたパッケージのすべてのドキュメントを表示-short:1 行の簡単な説明のみ表示-src:ソースコードを出力-cmd:go コマンドに属するパッケージのコードドキュメントも出力
例えば、runtime.inf 変数を参照する場合、これは外部に公開されていない変数です
$ go doc -u runtime.inf
package runtime // import "runtime"
var inf = float64frombits(0x7FF0000000000000)doc コマンドをうまく活用することで、ドキュメントをより便利に読むことができます。
コマンドドキュメントを読むもう一つの方法は、ソースコードを読むことです。一部のコマンドのドキュメントはそれほど詳細ではなく、ソースコードの方が詳しい説明がある場合があります。これらのコマンドはすべて Go で書かれているため、読むのも非常に便利です。これらのコマンドはすべて src/cmd パッケージ下にあり、各サブパッケージが個別のコマンドで、エントリーポイントは cmd/go/main.go ファイルにあります
func init() {
base.Go.Commands = []*base.Command{
bug.CmdBug,
work.CmdBuild,
clean.CmdClean,
doc.CmdDoc,
envcmd.CmdEnv,
fix.CmdFix,
fmtcmd.CmdFmt,
generate.CmdGenerate,
modget.CmdGet,
work.CmdInstall,
list.CmdList,
modcmd.CmdMod,
workcmd.CmdWork,
run.CmdRun,
test.CmdTest,
tool.CmdTool,
version.CmdVersion,
vet.CmdVet,
help.HelpBuildConstraint,
help.HelpBuildmode,
help.HelpC,
help.HelpCache,
help.HelpEnvironment,
help.HelpFileType,
modload.HelpGoMod,
help.HelpGopath,
get.HelpGopathGet,
modfetch.HelpGoproxy,
help.HelpImportPath,
modload.HelpModules,
modget.HelpModuleGet,
modfetch.HelpModuleAuth,
help.HelpPackages,
modfetch.HelpPrivate,
test.HelpTestflag,
test.HelpTestfunc,
modget.HelpVCS,
}
}ここで go のすべてのサブコマンドとそれらのヘルプドキュメント情報を見つけることができます。
bug
$ go help bug
usage: go bug
Bug opens the default browser and starts a new bug report.
The report includes useful system information.このコマンドにはパラメータやフラグはなく、デフォルトのブラウザで github.com/golang/go リポジトリの issue ページを開き、バグを報告しやすくするだけです。
version
version コマンドで現在の go のバージョン情報を確認できます。
$ go version -h
usage: go version [-m] [-v] [file ...]パラメータなしで実行すると、現在の go 言語のバージョンを出力します
$ go version
go version go1.21.0 windows/amd64ファイルパスをパラメータとして受け取ることもでき、そのパス下のすべての識別可能なバイナリファイルのコンパイル時に使用された go バージョンを出力します。
$ go version -v ./
buf.exe: go1.20.2
cobra-cli.exe: go1.21.0
dlv.exe: go1.20.2
goctl.exe: go1.20.2
goimports.exe: go1.20.2
golangci-lint.exe: go1.20.2
gopls.exe: go1.19.3
kratos.exe: go1.20.2
main.exe: go1.19.1
protoc-gen-go-grpc.exe: go1.20.2
protoc-gen-go-http.exe: go1.20.2
protoc-gen-go.exe: go1.20.2
protoc-gen-openapi.exe: go1.20.2
swag.exe: go1.21.0
wire.exe: go1.21.0-v パラメータは version コマンドに識別できないファイルの go バージョンを出力させ、-m パラメータはバイナリファイルのモジュール情報とコンパイルパラメータを出力します。以下は簡単な例です。
$ go version -v -m wire.exe
wire.exe: go1.21.0
path github.com/google/wire/cmd/wire
mod github.com/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8=
dep github.com/google/subcommands v1.0.1 h1:/eqq+otEXm5vhfBrbREPCSVQbvofip6kIz+mX5TUH7k=
dep github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
dep golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b h1:NVD8gBK33xpdqCaZVVtd6OFJp+3dxkXuz7+U7KaVN6s=
build -buildmode=exe
build -compiler=gc
build DefaultGODEBUG=panicnil=1
build CGO_ENABLED=1
build CGO_CFLAGS=
build CGO_CPPFLAGS=
build CGO_CXXFLAGS=
build CGO_LDFLAGS=
build GOARCH=amd64
build GOOS=windows
build GOAMD64=v1go 自体もバイナリファイルであり、実際にはパラメータなしで go version を実行すると、自身のバイナリファイルの go 言語バージョンを出力します。cmd/go のすべてのツールチェーンは go 言語自体によって実装されているためです。
env
env コマンドで go 環境変数のすべての情報を確認でき、これらの環境変数を変更すると go ツールチェーンの動作に影響します。
$ go env -h
usage: go env [-json] [-u] [-w] [var ...]
Run 'go help env' for details.パラメータなしで実行すると、go のすべての環境変数の値を出力します
$ go env
set GO111MODULE=on
set GOARCH=amd64
...環境変数名をパラメータとして指定すると、その変数の値のみを出力できます
$ go env GO111MODULE
on-json を追加すると JSON 形式で出力できます
$ go env -json
{
"AR": "ar",
"CC": "gcc",
......
}-w フラグを使用して、var=value 形式でパラメータを渡すと、特定の変数の値を永続的に変更できます
$ go env -w GO111MODULE=on-u フラグを使用して、特定の変数をデフォルト値に戻せます
$ go env -u GO111MODULEgo help environment を実行すると、各環境変数の説明を確認できます
$ go help environment
The go command and the tools it invokes consult environment variables
for configuration. If an environment variable is unset or empty, the go
command uses a sensible default setting. To see the effective setting of
the variable <NAME>, run 'go env <NAME>'. To change the default setting,
run 'go env -w <NAME>=<VALUE>'. Defaults changed using 'go env -w'
are recorded in a Go environment configuration file stored in the
per-user configuration directory, as reported by os.UserConfigDir.
The location of the configuration file can be changed by setting
the environment variable GOENV, and 'go env GOENV' prints the
effective location, but 'go env -w' cannot change the default location.
See 'go help env' for details.
General-purpose environment variables:
GO111MODULE
Controls whether the go command runs in module-aware mode or GOPATH mode.
May be "off", "on", or "auto".
See https://golang.org/ref/mod#mod-commands.
GCCGO
The gccgo command to run for 'go build -compiler=gccgo'.
GOARCH
The architecture, or processor, for which to compile code.
Examples are amd64, 386, arm, ppc64.
GOBIN
The directory where 'go install' will install a command.
GOCACHE
The directory where the go command will store cached
information for reuse in future builds.
......以下はいくつかの一般的な環境変数の紹介です
GOVERSION
この環境変数の値は go 言語のバージョンに依存し、バージョン番号は $GOROOT/VERSION ファイルから取得されます。このファイルには現在の go のバージョンとビルド時間が記録されています。
$ cat $GOROOT/VERSION
go1.21.3
time 2023-10-09T17:04:35Zruntime.Version 変数の値は GOVERSION の値と同じで、この環境変数は変更できません。
GOENV
$GOROOT ディレクトリには go.env というデフォルトの構成ファイルがあります
$ cat $GOROOT/go.env
# This file contains the initial defaults for go command configuration.
# Values set by 'go env -w' and written to the user's go/env file override these.
# The environment overrides everything else.
# Use the Go module mirror and checksum database by default.
# See https://proxy.golang.org for details.
GOPROXY=https://proxy.golang.org,direct
GOSUMDB=sum.golang.org
# Automatically download newer toolchains as directed by go.mod files.
# See https://go.dev/doc/toolchain for details.
GOTOOLCHAIN=auto形式は単純な key=value で、go env -w key=value コマンドで変更された環境変数の値は構成ファイルに書き込まれます。ただし、デフォルトの構成ファイルを使用しないこともでき、GOENV 環境変数で env 構成ファイルのアドレスを手動で指定できます。GOENV 環境変数の値はオペレーティングシステムの環境変数でのみ上書きでき、go env -w コマンドでは変更できません。
GOHOSTARCH
マシンの CPU アーキテクチャを表します。これは表示用だけで、この環境変数の値は構成ファイルから読み取られるものではなく、変更もできません。
GOHOSTOS
マシンのオペレーティングシステムを表します。これは表示用だけで、この環境変数の値は構成ファイルから読み取られるものではなく、変更もできません。
GOOS
コンパイル時、GOOS の値はソースコードをどのターゲットシステムのバイナリファイルにコンパイルするかを決定します。デフォルト値は GOHOSTOS、つまりマシンのオペレーティングシステムです。以下のオプションがあります
linuxdarwinwindowsnetbsdaixandroid
実際にサポートされているオペレーティングシステムはこれらだけではありません。go tool dist list コマンドを使用して、サポートされているすべての値を確認できます
$ go tool dist list | awk -F '/' '{print $1}' | awk '!seen[$0]++'
aix
android
darwin
dragonfly
freebsd
illumos
ios
js
linux
netbsd
openbsd
plan9
solaris
wasip1
windowsGOARCH
コンパイル時、GOARCH の値はコンパイル時にどの CPU アーキテクチャの命令を使用するかを決定します。デフォルト値は GOHOSTARCH、つまりマシンの CPU アーキテクチャです。以下のオプションがあります
amd64386armppc64
実際にサポートされているアーキテクチャはこれらだけではありません。go tool dist list コマンドを使用して、サポートされているすべての値を確認できます
$ go tool dist list | awk -F '/' '{print $2}' | awk '!seen[$0]++'
ppc64
386
amd64
arm
arm64
riscv64
wasm
loong64
mips
mips64
mips64le
mipsle
ppc64le
s390xGOOS と GOARCH は任意に組み合わせることはできず、一部のオペレーティングシステムは特定の CPU アーキテクチャのみをサポートしています。
GOROOT
GOROOT は go 言語インストール場所のルートディレクトリを表し、GOROOT の値は直接変更できず、オペレーティングシステムの環境変数でのみ上書きできます。
$ ls $GOROOT -1
api
bin
codereview.cfg
CONTRIBUTING.md
doc
go.env
lib
LICENSE
misc
PATENTS
pkg
README.md
SECURITY.md
src
test
VERSIONルートディレクトリには以下の重要なフォルダやファイルがあります
lib:依存関係が格納されています。現時点では世界各国のタイムゾーン情報を含むライブラリのみで、$GOROOT/lib/timeにあります。コンパイル後のバイナリファイルにはこれらのタイムゾーン情報は含まれません。pkg:ツールライブラリとヘッダーファイルが格納されています。例えばgo toolコマンドは$GOROOT/pkg/toolディレクトリで go ツールチェーンのバイナリファイルを検索しますbin:バイナリファイルが格納されています。デフォルトではgoとgofmtの 2 つの実行ファイルのみです。$GOROOT/binはシステム変数に追加する必要があります。そうしないと go コマンドを使用できません。src:go ソースコードが格納されていますVERSION:このファイルには go 言語のバージョン情報が格納されていますgo.env:このファイルはデフォルトのenv構成ファイルです
GOPATH
GOPATH のデフォルト値は $HOME/go で、この環境変数の値は import 文の解析時にインポートされたファイルを検索する場所を指定します。gomod がない初期の頃、GOPATH はサードパーティライブラリを格納するために使用されていました。その構造は以下の通りです
GOPATH=/home/user/go
/home/user/go/
src/
foo/
bar/ (go code in package bar)
x.go
quux/ (go code in package main)
y.go
bin/
quux (installed command)
pkg/
linux_amd64/
foo/
bar.a (installed package object)gomod が登場した後、GOPATH は go get でダウンロードされた依存関係を格納する場所、および go install でダウンロードおよびコンパイルされたバイナリファイルを格納する場所としてのみ使用されます。GOPATH の位置は GOROOT と同じであってはなりません。そうしないと機能しません。
$ go env GOBIN
warning: GOPATH set to GOROOT (/home/user/go) has no effectこの記事を書いている時点で、go 言語のバージョンはすでに go1.21.3 になっており、非常に古いプロジェクトを除いて、gopath を使用して依存関係を管理する人はほとんどいません。
GOBIN
GOBIN は go install でダウンロードおよびコンパイルされたサードパーティの実行バイナリファイルを格納するために使用され、デフォルト値は $GOPATH/bin です。$GOROOT/bin と同様に、このディレクトリもオペレーティングシステムの環境変数に追加する必要があります。そうしないと、GOBIN ディレクトリ下のバイナリファイルを使用できません。
GOMODCACHE
GOMODCACHE は go get でダウンロードされた依存関係が格納される場所を示し、デフォルト値は $GOPATH/pkg/mod です。格納形式は以下の通りです
$GOMODCACHE/domain/username/project@verion同じレベルのディレクトリには sumdb というフォルダもあり、依存関係のチェックサムデータベースに関する情報が格納されています。
GOCACHE
コンパイル用のキャッシュ情報を格納し、デフォルト値は $HOME/.cache/go-build です。このディレクトリには README ファイルが生成されます。
$ cat $(go env GOCACHE)/README
This directory holds cached build artifacts from the Go build system.
Run "go clean -cache" if the directory is getting too large.
Run "go clean -fuzzcache" to delete the fuzz cache.
See golang.org to learn more about Go.build するたびに多くのファイルが生成され、go はこれらのファイルをキャッシュして、次のコンパイル時に再利用します。
GOTEMPDIR
コンパイル時に生成される一時ファイル用で、例えば go run で実行される一時バイナリファイルなどです。デフォルト値はオペレーティングシステムが指定する一時ディレクトリで、mac または linux では /tmp、windows では %TEMP% です。ユーザーが指定する場所に変更することもできます。
GO111MODULE
この環境変数は go プロジェクトの依存関係を管理する方法を示し、以下の 3 つの利用可能な値があります
off:gomod をオフにして gopath を使用し、すべてのgo.modファイルを無視しますon:gomod を使用し、gopath は使用しません(デフォルト)auto:自動検知。プロジェクトファイルにgo.modが含まれている場合は gomod を使用して管理します
TIP
なぜ GO111MODULE という名前で、GOMODULE と呼ばないのでしょうか?それは gomod が go1.11 バージョンで初めて導入されたからです。
GOPROXY
go モジュールプロキシで、デフォルト値は https://proxy.golang.org,direct です。url はカンマで区切られ、direct はモジュールプロキシを直接使用せずに VCS を使用することを意味し、前者にアクセスできない場合にのみ後者が実行されます。もう一つの利用可能なオプションは off で、モジュールのダウンロードを禁止することを示します。さらに、GOPROXY はファイルアドレス也可以是、例えば
GOPROXY=file://$(go env GOMODCACHE)/cache/downloadgo get -x を使用すると、依存関係のダウンロードプロセスで実行されるコマンドを確認でき、プロキシを使用しているかどうかを知ることができます。
$ go get -x github.com/spf13/cast
# get https://goproxy.cn/github.com/@v/list
# get https://goproxy.cn/github.com/spf13/cast/@v/list
# get https://goproxy.cn/github.com/spf13/@v/list
# get https://goproxy.cn/github.com/spf13/@v/list: 404 Not Found (0.118s)
# get https://goproxy.cn/github.com/@v/list: 404 Not Found (0.197s)
# get https://goproxy.cn/github.com/spf13/cast/@v/list: 200 OK (0.257s)
# get https://goproxy.cn/github.com/spf13/cast/@v/v1.5.1.info
# get https://goproxy.cn/github.com/spf13/cast/@v/v1.5.1.info: 200 OK (0.013s)
# get https://goproxy.cn/github.com/spf13/cast/@v/v1.5.1.mod
# get https://goproxy.cn/github.com/spf13/cast/@v/v1.5.1.mod: 200 OK (0.015s)
# get https://goproxy.cn/sumdb/sum.golang.org/supported
# get https://goproxy.cn/sumdb/sum.golang.org/supported: 200 OK (0.064s)
# get https://goproxy.cn/sumdb/sum.golang.org/lookup/github.com/spf13/cast@v1.5.1
# get https://goproxy.cn/sumdb/sum.golang.org/lookup/github.com/spf13/cast@v1.5.1: 200 OK (0.014s)
# get https://goproxy.cn/sumdb/sum.golang.org/tile/8/0/x079/736
# get https://goproxy.cn/sumdb/sum.golang.org/tile/8/0/x079/736: 200 OK (0.016s)
# get https://goproxy.cn/sumdb/sum.golang.org/tile/8/0/x068/334
# get https://goproxy.cn/sumdb/sum.golang.org/tile/8/1/266
# get https://goproxy.cn/sumdb/sum.golang.org/tile/8/0/x068/334: 200 OK (0.023s)
# get https://goproxy.cn/sumdb/sum.golang.org/tile/8/1/266: 200 OK (0.028s)
go: downloading github.com/spf13/cast v1.5.1
# get https://goproxy.cn/github.com/spf13/cast/@v/v1.5.1.zip
# get https://goproxy.cn/github.com/spf13/cast/@v/v1.5.1.zip: 200 OK (0.024s)
go: added github.com/spf13/cast v1.5.1モジュールプロキシを使用すると、モジュールのダウンロード速度を効果的に向上させることができます。国内ユーザーは基本的にプロキシを使用しないとデフォルトの公式プロキシにアクセスできません。現在、公開されており信頼できるサードパーティモジュールプロキシは以下の通りです
https://proxy.golang.com.cn:オープンソースで、企業版サービスも提供https://goproxy.cn:七牛雲が提供し、オープンソース
もちろん、オープンソースの自建モジュールプロキシソリューションもあります:goproxy
GOSUMDB
GOSUMDB は依存ライブラリのチェックサム検証データベースアドレスを設定するために使用され、デフォルトは sum.golang.org です。プロキシを設定すると、go はプロキシを介して検証データベースにアクセスします。
GOPRIVATE
GOPRIVATE 環境変数はプライベートライブラリを設定するために使用され、一致するライブラリは sumdb による検証もプロキシも経由しません。VCS を介して直接依存関係をダウンロードします。ワイルドカード設定をサポートし、カンマで区切ります。以下の例では、corp.example.com で終わるすべてのものと github.com/gohper/myproject という名前の依存関係はプロキシも sumdb も経由しません。
GOPRIVATE=*.corp.example.com,github.com/gohper/myproject特定のユーザーまたは組織を直接設定することもできます
GOPRIVATE=github.com/gopher,github.com/myorganizationGONOPROXY
どの依存関係がプロキシを経由しない必要があるかを示し、ルールは GOPRIVATE と同じで、GOPRIVATE を上書きします。
GONOSUMDB
どの依存関係が検証データベースを経由しない必要があるかを示し、ルールは GOPRIVATE と同じで、GOPRIVATE を上書きします。
GOINSECURE
どの依存関係が VCS を直接使用してダウンロードされるかを示し、ルールは GOPRIVATE と同じで、GONOPROXY と GONOSUMDB によって上書きされます。
GOVCS
モジュール管理のバージョン管理システムを設定し、デフォルトは public:git|hg,private:all です。特定のドメインの VCS を制限することもできます。例えば
GOVCS=github.com:git,evil.com:off,*:git|hg上記の制限では、github は git のみ使用でき、evil.com は使用できません。| を使用して複数の VCS を表すことができます。制限を全く設定しない場合は、以下のように設定できます
GOVCS=*:allVCS の使用を全く許可しない場合は、以下のように設定できます
GOVCS=*:offGOWORK
ワークスペースを有効にするかどうかを設定し、デフォルトは空で有効です。off に設定すると無効になり、すべての go.work ファイルを無視します。
GOTOOLDIR
使用する go ツールチェーンの位置を設定し、デフォルトは $GOROOT/pkg/tool で、デフォルトのツールチェーンもこの位置に格納されています。
GODEBUG
デバッグオプションを設定し、キーバリュー形式で go プログラムの一部の実行動作を制御します。例えば
GODEBUG=http2client=0,http2server=0これらの設定は、バージョン更新プロセス中に互換性のない変更が発生した場合に、go が以前の動作に戻すことができるようにするためです。例えば 1.21 では panic(nil) が許可されなくなりました。これについて、go 公式は GODEBUG History を記録しており、詳細については GODEBUG をご覧ください。
CGO_ENABLED
cgo を有効にするかどうかを示し、デフォルトは 1 で有効です。0 に設定すると無効になります。
上記の環境変数は一般的に使用されるもので、CGO、WASM などのあまり一般的でないものについてはここでは詳しく紹介しません。興味がある場合は自分で調べてみてください。
build
go がサポートするコンパイラには gccgo と gc の 2 種類があります。gcc は老舗の c/c++ コンパイラで、go を含む複数の言語をサポートしています。後者の gc はガベージコレクションを意味するのではなく、go compiler を意味します。go 言語は go1.5 でブートストラップを完了し、gc は完全に go 言語で書かれたコンパイラで、そのソースコードは cmd/compile パッケージ下にあり、完全に go 言語で実装されているため、内部メカニズムの学習と理解にも非常に便利です。デフォルトでは、コンパイラは gc を使用してコンパイルします。ついでに言うと、go 言語デバッガも gdb と dlv の 2 種類に分かれています。gdb は老舗の c/c++ デバッガで、go を含む複数の言語をサポートしています。後者の dlv は go 言語で書かれたデバッガで、go 言語のサポートがより親切です。これもオープンソースで、後者の使用をお勧めします。
build コマンドの役割は go ソースファイルを実行可能なバイナリファイルにコンパイルすることで、非常に迅速なコンパイル体験を味わうことができます。これも go 言語の特徴の一つです。
$ go build -h
usage: go build [-o output] [build flags] [packages]
Run 'go help build' for details.3 つのパラメータを受け取り、1 つ目は -o フラグで示されるファイル出力パス、2 つ目はコンパイル動作を定義するビルドフラグ build flags、3 つ目はコンパイルするパッケージで、このパラメータは最後に配置する必要があります。以下はビルドフラグを使用しない簡単な例です。
# Windows
$ go build -o .\bin\golearn.exe golearn
# macOS / Linux
$ go build -o ./bin/golearn golearn./bin/golearn.exe は出力パスを示し、golearn はコンパイルするモジュールを示します。エントリーファイル または フォルダ でもかまいません。以下は main.go エントリーファイルをコンパイルターゲットとする簡単な例です。
# Windows
$ go build -o .\bin\golearn.exe main.go
# macOS / Linux
$ go build -o ./bin/golearn main.goコンパイル時、_test.go で終わるすべてのファイルは無視されます。これらのファイルは慣例によりテストファイルであるためです。
さらに、build コマンドはコンパイル時の動作を制御するために相当数のビルドフラグをサポートしています。
-x:コンパイルプロセス中の詳細なコマンドを出力-n:-xと似ていますが、違いはこれらのコマンドを出力するだけで、実際には実行しないことです。-v:コンパイルされたパッケージを出力-p:コンパイルプロセス中の並行数-a:最新であっても強制的に再構築します。-compiler:使用するコンパイラを指定します。gccgoまたはgcで、後者は go で書かれたコンパイラです。-race:競合検出を有効にします-msan:メモリ分析を有効にします-asan:アドレス分析を有効にします-cover:コードカバレッジ検出を有効にします-buildmode:コンパイルモードを指定します。archive、c-archive、c-shared、default、shared、exe、pie、pluginのオプションがあります。-pgo:pgo ファイルを指定します-trimpath:ソースファイルパスのプレフィックスを削除します。例えば相対パス/var/lib/go/src/main.goは、削除後にruntimeを介して取得されるファイル名はモジュールパスへの相対パス/main.goのみになります。この項目を有効にすると、コンパイル時間は明らかに上昇し、ファイル数に応じて約 20-40% 上昇します。-toolexec:コンパイル前に実行されるいくつかの go コマンドで、形式は-toolexec 'cmd args'です。-gcflags:コンパイラ gc のいくつかのタグを指定します-gccgoflags:コンパイラ gccgo のいくつかのタグを指定します-ldflags:link ツールのいくつかのタグを指定します
ldflags などのパラメータ渡しの場合は、"-help" などのパラメータを渡して、その取り得る値を取得できます。例えば
$ go build -ldflags -help
usage: link [options] main.o
-B note
add an ELF NT_GNU_BUILD_ID note when using ELF
-E entry
set entry symbol name
......上記は一般的に使用されるもので、他のあまり一般的でないものは自分で調べてみてください。
gcflags
gcflags を使用して、コンパイラ gc にパラメータを渡し、特定の動作を制御できます。使用形式は -gcflags="pattern=args list" で、ages list はパラメータリスト、pattern は作用範囲で、以下の利用可能な値があります
main:エントリーファイルがあるトップレベルのパッケージパスall:現在のモジュールおよび現在のモードのすべての依存関係std:標準ライブラリcmd:cmdパッケージ下のすべてのソースファイル- ワイルドカード:例えば
.、./...、cmd/...
この pattern ルールは、この形式をサポートするすべてのフラグに適用されます。例えば ldflags です。以下のコマンドを使用して、パラメータの取り得る値を確認できます
$ go build -gcflags -help
usage: compile [options] file.go...
-% debug non-static initializers
-+ compiling runtime
-B disable bounds checking
-C disable printing of columns in error messages
-D path
set relative path for local imports
-E debug symbol export
-I directory
add directory to import search path
-K debug missing line numbers
-L also show actual source file names in error messages for positions affected by //line directives
-N disable optimizations
-S print assembly listing
-V print version and exit
-W debug parse tree after type checking
......以下はいくつかの一般的なパラメータの紹介です
-S:コードのアセンブリ形式を出力-N:コンパイル最適化を無効-m:最適化決定を出力-l:関数インラインを無効-c:コンパイルの並行数-dwarf:DWARF フラグを生成
例えば、コードのアセンブリ形式を確認したい場合は、-S パラメータを使用し、最適化とインラインを無効にして、本来の形式を復元する必要があります。以下はその例です
$ go build -trimpath -gcflags="-N -l -S" main.go
main.main STEXT size=171 args=0x0 locals=0x58 funcid=0x0 align=0x0
0x0000 00000 (./main.go:9) TEXT main.main(SB), ABIInternal, $88-0
0x0000 00000 (./main.go:9) CMPQ SP, 16(R14)
0x0004 00004 (./main.go:9) PCDATA $0, $-2
0x0004 00004 (./main.go:9) JLS 161
0x000a 00010 (./main.go:9) PCDATA $0, $-1
0x000a 00010 (./main.go:9) PUSHQ BP
0x000b 00011 (./main.go:9) MOVQ SP, BP
0x000e 00014 (./main.go:9) SUBQ $80, SP
0x0012 00018 (./main.go:9) FUNCDATA $0, gclocals·J5F+7Qw7O7ve2QcWC7DpeQ==(SB)
0x0012 00018 (./main.go:9) FUNCDATA $1, gclocals·bDfKCdmtOiGIuJz/x+yQyQ==(SB)
0x0012 00018 (./main.go:9) FUNCDATA $2, main.main.stkobj(SB)
0x0012 00018 (./main.go:10) MOVUPS X15, main..autotmp_0+40(SP)
0x0018 00024 (./main.go:10) LEAQ main..autotmp_0+40(SP), CX
0x001d 00029 (./main.go:10) MOVQ CX, main..autotmp_2+32(SP)ldflags
ldflags を使用して、リンカーにパラメータを渡し、特定の動作を制御できます。以下のコマンドを使用して、ldflags のすべての利用可能な値を確認できます。ほぼ 20〜30 個あります。
$ go build -ldflags -help
usage: link [options] main.o
-B note
add an ELF NT_GNU_BUILD_ID note when using ELF
-E entry
set entry symbol name
-H type
set header type
-I linker
use linker as ELF dynamic linker
-L directory
add specified directory to library path
-R quantum
set address rounding quantum (default -1)
-T int
set the start address of text symbols (default -1)
-V print version and exit
-X definition
add string value definition of the form importpath.name=value
-a no-op (deprecated)
.....ldflags の -X パラメータは非常に実用的な機能で、リンク時に指定されたパッケージの文字列変数の値を定義できます。この機能を使用すると、コンパイル時にいくつかのメタ情報を簡単に注入できます。また、これは変数にすぎないため、実行時に取得するのも便利です。以下は簡単な例です。
package main
import "fmt"
var (
Version string
)
func main() {
fmt.Println(Version)
}コマンドを実行
go build -ldflags "-X main.Version=$(git describe --always)" main.go実行後、git コミットの sha1 チェックサムが出力されます。
5e3fd7aその他、実用的なパラメータには以下があります
-w:DWARF を生成しません。これはソースコードのデバッグに便利な情報です。-s:シンボルテーブルを無効にします
これらは通常一緒に使用され、コンパイル後のバイナリファイルのサイズを大幅に削減できます。約 40%-50% 程度ですが、欠点も明らかで、デバッグができなくなります。以下はその例です。
$ go build -ldflags="-w -s" main.goクロスコンパイル
go 言語のコンパイルには 2 つの大きな特徴があります。1 つ目は高速であることで、もう 1 つはクロスコンパイルです。クロスコンパイルとは、ローカルで他のシステムのターゲットコードをコンパイルできることを指します。例えば windows で linux や darwin 用のバイナリファイルをコンパイルでき、その逆も同様です。クロスコンパイルをサポートする言語は非常に多いですが、これは珍しいことではありません。しかし、go 言語のクロスコンパイルは非常に簡単で、以下の 2 ステップだけです
- GOOS 環境変数を設定し、ターゲットオペレーティングシステムを選択
- GOARCH 環境変数を設定し、ターゲット CPU アーキテクチャを選択
- 普段通り
go buildを使用してコンパイル
プロセス全体は非常に短く、追加のツールや設定は不要で、速度も普段と同じくらい速いです。以下に示します
build_linux:
SET CGO_ENABLED=0
SET GOOS="linux"
SET GOARCH="amd64"
go build -o golearn main.go
build_mac:
SET CGO_ENABLED=0
SET GOOS="darwin"
SET GOARCH="amd64"
go build -o golearn main.go
build_win:
SET CGO_ENABLED=0
SET GOOS="win"
SET GOARCH="amd64"
go build -o golearn.exe main.go
.PHONY: build_linux \
build_mac \
build_win最初のステップ SET CGO_ENABLED=0 は cgo を無効にします。コードが cgo を使用している場合、クロスコンパイルを正常に使用できません。2 番目のステップ SET GOOS はターゲットシステムを設定し、オプションは linux、darwin、windwos、netbsd です。3 番目のステップは CPU アーキテクチャを設定し、SET GOARCH で、オプションは amd64、386、arm、ppc64 です。最後のステップは普段通りコンパイルします。
コンパイル制御
build コマンドは tags を使用してコンパイルを制御できます。これはソースコード内にディレクティブとして存在します。例を見てみましょう。product.go ファイル
// +build product
package main
import "fmt"
func main() {
fmt.Println("product")
}debug.go ファイル
// +build debug
package main
import "fmt"
func main() {
fmt.Println("debug")
}これらには // +build ディレクティブがあり、どのような状況でコンパイルされるかを示します。基本形式は以下の通りです
// +build tag1 tag2
package pkg_name遵守しなければならないルールがいくつかあります
//と+buildの間に 1 つのスペースが必要です- パッケージ宣言の上に配置する必要があります
- パッケージ宣言との間に 1 行の空行が必要です
さらに、単純なスペースを使用して論理制御を達成できます。スペースは OR、カンマは AND、!は NOT を表します。以下の例を見てください
// +build windows linux
package pkg_nameこれは windows または linux プラットフォームで現在のファイルがコンパイルされることを示します。
// +build windows,amd64,!cgo linux,i386,cgo
package pkg_nameこの例は、windows プラットフォーム amd64 アーキテクチャで cgo が無効になっている場合、または linux プラットフォーム i386 アーキテクチャで cgo が有効になっている場合にのみコンパイルされることを示します。特定のファイルをコンパイルに参加させたくないだけの場合は、ignore を使用できます。
// +build ignore
package pkg_name複数の行のディレクティブも存在できます
// +build windows
// +build amd64
package pkg_name複数の行のディレクティブは AND 方式で処理されます。プラットフォームやアーキテクチャなどのタグは、コンパイル時に go によって自動的に渡されます。カスタムタグを渡すこともできます。最初の 2 つのファイルを使用して例を示します
$ go build -tags="debug" . && ./golearn.exe
debug
$ go build -tags="product" . && ./golearn.exe
product異なるタグを渡すと異なる出力が得られることがわかります。コンパイル制御の目的はこれで達成されます。
run
run コマンドと build はどちらもソースコードをコンパイルしますが、run コマンドはコンパイル後に直接実行します。run コマンドはコンパイル速度を上げるために、コンパイルプロセス中にデバッグ情報を生成せず、デバッグもサポートしません。また、一時バイナリファイルのみを生成し、通常は GOTMEPDIR ディレクトリ(例:/temp/go-build2822241271/b001/exe/main.exe)に格納されます。
$ go run -h
usage: go run [build flags] [-exec xprog] package [arguments...]
Run 'go help run' for details.build コマンドのビルドフラグもサポートし、-exec パラメータを提供して、バイナリファイルを実行するプログラムを指定します。[arguments...] はプログラムの実行パラメータを指します。以下は例です
package main
import (
"fmt"
"os"
)
var (
Version string
)
func main() {
fmt.Println(Version)
fmt.Println(os.Args[1:])
}go run を使用して実行
$ go run -ldflags="-X main.Version=$(git describe --always)" main.go hello
5e3fd7a
[hello]全体的に go build と大きな違いはなく、これ以上の詳細は省略します。
tool
tool コマンド自体には機能はなく、cmd/ ディレクトリ下のツールを直接呼び出す役割を果たします。例えば cmd/compile は組み込みのコンパイラです。go tool を使用してこれらのツールを直接呼び出せ、これらのツールのバイナリファイルを手動で実行する必要はありません。
$ go tool -h
usage: go tool [-n] command [args...]-n パラメータを使用して、サポートされているすべてのコマンドパラメータを出力します
$ go tool -n
addr2line
asm
buildid
cgo
compile
covdata
cover
doc
fix
link
nm
objdump
pack
pprof
test2json
trace
vetこれらのツールは GOROOT/pkg/tool ディレクトリ下に格納され、オペレーティングシステムと CPU アーキテクチャに基づいてグループ化されています。以下に示します。
$ ls $GOROOT/pkg/tool/windows_amd64/ -1
addr2line.exe*
asm.exe*
buildid.exe*
cgo.exe*
compile.exe*
covdata.exe*
cover.exe*
doc.exe*
fix.exe*
link.exe*
nm.exe*
objdump.exe*
pack.exe*
pprof.exe*
test2json.exe*
trace.exe*
vet.exe*go doc cmd/command 形式を使用して、各コマンドの用法を確認できます。例えば
$ go doc cmd/compile
Usage:
go tool compile [flags] file...
The specified files must be Go source files and all part of the same package.
The same compiler is used for all target operating systems and architectures.
The GOOS and GOARCH environment variables set the desired target.
Flags:
-D path
Set relative path for local imports.
-I dir1 -I dir2
Search for imported packages in dir1, dir2, etc,
after consulting $GOROOT/pkg/$GOOS_$GOARCH.
-L
Show complete file path in error messages.
...cmd/compile がサポートするフラグパラメータは、前述の gcflags がサポートするパラメータです。go tool compile と go build の違いは、前者はコンパイルのみを担当し、ファイルのみをパラメータとして使用できることです。後者はフォルダ、パッケージ、ファイルをパラメータとして使用でき、ソースコードのコンパイルだけでなく、ファイルのリンク、不要なファイルのクリアなども担当します。前者は後者の一部です。build プロセス中に実行されるコマンドを出力できます
$ go build -n main.go
#
# internal/goarch
#
mkdir -p $WORK\b004\
cat >$WORK\b004\importcfg << 'EOF' # internal
# import config
EOF
"/golang/pkg/tool/windows_amd64/compile.exe" -o "$WORK/b004/_pkg_.a" -trimpath "$WORK/b004=>" -p internal/goarch -std -+ -complete -buildid 3gunEkUExGdhOPa2rFsh/3gunEkUExGdhOPa2rFsh -goversion go1.21.0 -c=4 -nolocalimports -importcfg "$WORK/b004/importcfg" -pack "/golang/src/internal/goarch/goarch.go" "/golang/src/internal/goarch/goarch_amd64.go" "/golang/src/internal/goarch/zgoarch_amd64.go"
"/golang/pkg/tool/windows_amd64/buildid.exe" -w "$WORK/b004/_pkg_.a" # internal
...プロセス中に /golang/pkg/tool/windows_amd64/compile.exe という部分があり、コンパイラを呼び出していることがわかります。compile の他にも多くのツールを呼び出せます。多くの go コマンドは実際にはそれらのエイリアスです。
clean
clean コマンドはコンパイルプロセス中に生成されたオブジェクトファイルをクリアするために使用されます
$ go clean -h
usage: go clean [clean flags] [build flags] [packages]
Run 'go help clean' for details.以下のフラグをサポートします
-i:対応するアーカイブファイルまたはバイナリファイルをクリア-n:クリアプロセス中に実行されるコマンドを出力しますが、実際には実行しません-x:クリアプロセス中に実行されるコマンドを出力し、実行します-r:import pathを介して再帰的にクリア-cache:go buildによって生成されたすべてのキャッシュをクリア-testcache:生成されたすべてのテストキャッシュをクリア-modcache:ダウンロードされたすべてのモジュールキャッシュをクリア-fuzzcache:fuzz testによって生成されたキャッシュをクリア
go tool compile を使用する場合、コンパイラコマンドを直接呼び出し、go build のように多くの後処理を行わないため、オブジェクトファイルが生成されます。例えば以下のコマンドを実行すると
go tool compile -N -S -l main.gomain.o というファイルが生成されます。go clean コマンドを使用してクリアします。または -n パラメータを使用して、実行されるコマンドを出力します。
$ go clean -n
rm -f golearn golearn.exe golearn golearn.exe golearn.test golearn.test.exe golearn.test golearn.test.exe api api.exe main main.exeコンパイルキャッシュをクリアすると、GOCACHE ディレクトリ下に生成されたコンパイルキャッシュが削除されます
$ go clean -cache -n
rm -r /cache/00 /cache/01 /cache/02fuzz test によって生成されたキャッシュをクリアします。これらのキャッシュはデフォルトで GOCACHE/fuzz/ ディレクトリ下に格納されます
$ go clean -fuzzcache -n
rm -rf /cache/fuzzfix
この記事を作成した時点で、go 言語はすでに 10 年になっています。言語が継続的に更新および修正されるプロセスで、API の変更による互換性の問題が発生することがあります。fix コマンドはこのために存在し、ソースファイル内で時代遅れになった API を検出し、新しい API に置き換えます。
$ go fix -h
usage: go fix [-fix list] [packages]
Run 'go help fix' for details.フォルダ、ファイル名、ディレクトリをパラメータとして受け取り、-fix フラグを受け取ってパラメータを渡し、どのような修正を行うかを示します。got tool fix -help コマンドを使用して、利用可能な値を確認できます
$ go tool fix -help
usage: go tool fix [-diff] [-r fixname,...] [-force fixname,...] [path ...]
-diff
display diffs instead of rewriting files
-force string
force these fixes to run even if the code looks updated
-go string
go language version for files
-r string
restrict the rewrites to this comma-separated list
Available rewrites are:
buildtag
Remove +build comments from modules using Go 1.18 or later
cftype
Fixes initializers and casts of C.*Ref and JNI types
context
Change imports of golang.org/x/net/context to context
egl
Fixes initializers of EGLDisplay
eglconf
Fixes initializers of EGLConfig
gotypes
Change imports of golang.org/x/tools/go/{exact,themes} to go/{constant,types}
jni
Fixes initializers of JNI's jobject and subtypes
netipv6zone
Adapt element key to IPAddr, UDPAddr or TCPAddr composite literals.
https://codereview.appspot.com/6849045/
printerconfig
Add element keys to Config composite literals.以下は例で、ソースコードで golang.org/x/net/context パッケージが使用されています
package main
import (
"fmt"
"golang.org/x/net/context"
)
func main() {
background := context.Background()
fmt.Println(background.Err())
}go fix を使用して修正し、標準ライブラリの context パッケージに置き換えます。以下のコマンドを使用して置き換えることができます
$ go fix -fix context main.goまたは、置き換えせずにファイルの前後の変更を確認することもできます。
$ go tool fix -r context -diff main.go
main.go: fixed context
diff main.go fixed/main.go
--- main.go
+++ fixed/main.go
@@ -1,8 +1,8 @@
package main
import (
+ "context"
"fmt"
- "golang.org/x/net/context"
)
func main() {go 言語は 10 年以上の歴史がありますが、利用可能な置き換えパラメータは 9 つだけで、互換性が比較的よく保たれていることがわかります。
fmt
fmt コマンドは go 言語に組み込みのフォーマットツールで、go ソースコードファイルをフォーマットするために使用されます。
$ go fmt -h
usage: go fmt [-n] [-x] [packages]
Run 'go help fmt' for details.go doc gofmt コマンドを使用して、詳細ドキュメントを確認できます
$ go doc cmd/gofmt
Gofmt formats Go programs. It uses tabs for indentation and blanks for
alignment. Alignment assumes that an editor is using a fixed-width font.
Usage:
gofmt [flags] [path ...]
The flags are:
-d
Do not print reformatted sources to standard output.
If a file's formatting is different than gofmt's, print diffs
to standard output.
-e
Print all (including spurious) errors.
-l
Do not print reformatted sources to standard output.
If a file's formatting is different from gofmt's, print its name
to standard output.
-r rule
Apply the rewrite rule to the source before reformatting.
-s
Try to simplify code (after applying the rewrite rule, if any).
-w
Do not print reformatted sources to standard output.
If a file's formatting is different from gofmt's, overwrite it
with gofmt's version. If an error occurred during overwriting,
the original file is restored from an automatic backup.gofmt はインデントに tab を使用し、スペースで整列します。デフォルトでは、フォーマット後のコードは標準出力に出力され、元のファイルは上書きされません。go fmt コマンドは実際には gofmt コマンドを使用しています。これは独立したバイナリファイルで、GOROOT/bin ディレクトリ下に格納されています。
$ ls $GOROOT/bin -1
go.exe*
gofmt.exe*go fmt コマンドに -n フラグを追加すると、実行されるコマンドを確認できます。
$ go fmt main.go
/golang/bin/gofmt.exe -l -w main.gogo fmt は実際には gofmt -l -w のエイリアスであることがわかります。gofmt コマンドには以下のパラメータがあります
-d:フォーマット前後のファイルの差分を出力-e:すべてのエラーを出力-l:変更されたファイル名を出力-r:フォーマットルールを適用-s:コードの簡素化を試みる-w:ソースファイルを上書き。エラーが発生した場合はバックアップを復元
現在、以下のソースファイルがあると仮定します
$ cat main.go
package main
import "fmt"
func main() {
fmt.Println("hello world!")}-d パラメータを使用して、変更をプレビューできます
$ gofmt -d main.go
diff main.go.orig main.go
--- main.go.orig
+++ main.go
@@ -3,5 +3,5 @@
import "fmt"
func main() {
-fmt.Println("hello world!")}
-
+ fmt.Println("hello world!")
+}-l パラメータは変更されるファイル名を出力します
$ gofmt -l .
main.go構文エラーがある場合、-e パラメータはより詳細に出力できます
$ gofmt -d -e main.go
main.go:6:27: missing ',' in argument list
main.go:6:28: expected operand, found newline
main.go:7:2: expected ')', found 'EOF'
main.go:7:2: expected ';', found 'EOF'
main.go:7:2: expected ';', found 'EOF'
main.go:7:2: expected '}', found 'EOF'
main.go:7:2: missing ',' in argument list-w は変更をソースファイルに適用します
$ gofmt -l -w .
main.go
$ cat main.go
package main
import "fmt"
func main() {
fmt.Println("hello world!")
}フォーマットツールとして、gofmt はカスタム構成を全く提供していないことがわかります。一方、js コードを美化するためのフォーマッター prettify はコードをフォーマットするために相当数の構成を提供しています。これは go 公式の態度を示しています。個性化を望まず、すべての人のコードスタイルをできるだけ一貫させることを望んでいます。少なくとも、コードを読むときに他人の習慣に適応する必要がないという利点があります。ただし、実際にはカスタム項目が 1 つ残されています。それはフォーマットコードの置換ルールで、ルールはカスタマイズできます。形式は以下の通りです
pattern -> replacement例えば、冗長な括弧を削除します
(a) -> aファイルの変更を確認します
$ gofmt -r "(a) -> a" -d -l .
main.go
diff main.go.orig main.go
--- main.go.orig
+++ main.go
@@ -3,5 +3,5 @@
import "fmt"
func main() {
- fmt.Println(("hello world!"))
+ fmt.Println("hello world!")
}gofmt が冗長な括弧を削除することがわかります。
get
get コマンドは go 開発プロセスで最も一般的に使用されるコマンドの 1 つで、指定されたアドレスのパッケージのソースコードを GOMODCACHE が示すディレクトリにダウンロードする役割を果たします。
$ go get -h
usage: go get [-t] [-u] [-v] [build flags] [packages]
Run 'go help get' for details.-u:パッケージのマイナーバージョンおよびパッチバージョンの更新を試みます。メインバージョンの変更(例:v1->v2)が関与する場合は更新されません。-t:テスト中の依存関係のバージョンを更新-v:コンパイルされたパッケージを出力。実際にはbuild flagsのパラメータの 1 つです
昔、go get の役割は go install と似ており、これらのパッケージをダウンロードしてコンパイルしていました。しかし、go モジュールの登場と完成に伴い、この部分の役割は次第に廃止されました。現在、get コマンドの最も一般的な役割は go モジュールのダウンロードと依存関係の解析です。そのため、go get コマンドが build flags などのビルドフラグをサポートしていることがわかります。モジュール外で go install と同じように go get を使用しようとすると、この用法は廃止されたというプロンプトが表示されます。
$ go get github.com/wire/wire
go: go.mod file not found in current directory or any parent directory.
'go get' is no longer supported outside a module.
To build and install a command, use 'go install' with a version,
like 'go install example.com/cmd@latest'
For more information, see https://golang.org/doc/go-get-install-deprecation
or run 'go help get' or 'go help install'.ドキュメントの説明でこれらが保持されている理由は不明ですが、get コマンドのソースコードを確認すると、以前のフラグが保持されていることがわかります。
var (
getD = CmdGet.Flag.Bool("d", true, "")
getF = CmdGet.Flag.Bool("f", false, "")
getFix = CmdGet.Flag.Bool("fix", false, "")
getM = CmdGet.Flag.Bool("m", false, "")
getT = CmdGet.Flag.Bool("t", false, "")
getU upgradeFlag
getInsecure = CmdGet.Flag.Bool("insecure", false, "")
// -v is cfg.BuildV
)本題に戻ると、get コマンドは指定されたパッケージのソースコードをローカルのグローバル依存関係ディレクトリ(つまり GOCACHE が示すディレクトリ)にダウンロードし、情報を go.mod および go.sum ファイルに記録します。前者はバージョンを記録する責任があり、後者は sha1 チェックサムを記録してセキュリティを確保します。get コマンドは実際には VCS(ローカルのバージョン管理システム)に基づいており、以下のいくつかをサポートしています
- git
- hg (Mercurial)
- bzr (Bazaar)
- svn
- fossil
その中で、デフォルトでは git と hg のみをサポートしています。GOVCS で構成でき、形式は以下の通りです
GOVCS=github.com:git,example.com:hg,*:git|hg,*:allGOVCS は git と hg のみを VCS としてサポートしており、他の 3 つは GOPRIVATE で構成する必要があります。
go get コマンドには以下の使用方法があります。依存関係のアドレスを直接パラメータとして使用できます
$ go get golang.org/x/netバージョンを指定することもできます
$ go get golang.org/x/net@0.17.0最新バージョンを指定
$ go get golang.org/x/net@latestバージョンの更新を試みる
$ go get -u golang.org/x/net特定の依存関係を削除
$ go get golang.org/x/net@none上記は通常の依存関係を管理するためのものです。それほど一般的でない依存関係を管理するためにも使用できます。例えば go 言語のバージョンを更新
$ go get go@latest
go: updating go.mod requires go >= 1.21.3; switching to go1.21.3
go: downloading go1.21.3 (windows/amd64)
go: upgraded go 1.21.0 => 1.21.3go ツールチェーンのバージョンを更新するためにも使用できます
$ go get toolchain@latestgo get を使用して go およびツールチェーンのバージョンを更新すると、GOMODCACHE/golang.org/ ディレクトリに新しいバージョンの go がインストールされます
$ ls $(go env GOMODCACHE)/golang.org -1
'toolchain@v0.0.1-go1.21.3.windows-amd64'/
x/この時点で GOROOT を手動で変更すると、指定されたバージョンに切り替えることができます。
install
install コマンドは get コマンドと似ており、どちらもサードパーティの依存関係をダウンロードするために使用されますが、違いは get コマンドがソースコードをダウンロードし、install コマンドがソースコードをマシンの実行可能なバイナリファイルにコンパイルすることです。バイナリファイルの格納パスはまず GOBIN ディレクトリで、次に GOPATH/bin です。このコマンドの主な機能は、サードパーティの公開されているいくつかのコマンドラインツールをダウンロードすることで、go 言語のコンパイル速度と移植性のおかげで、バイナリファイルをダウンロードする必要はなく、ソースコードをダウンロードしてローカルでコンパイルします。
$ go install -h
usage: go install [build flags] [packages]
Run 'go help install' for details.install コマンドはビルドフラグとパッケージ名をパラメータとして受け取り、gomod が有効な場合、パッケージ名にはバージョン番号が必要です。例えば delve デバッガをダウンロード
$ go install -x github.com/go-delve/delve/cmd/dlv@latest
# get https://goproxy.cn/github.com/@v/list
# get https://goproxy.cn/github.com/go-delve/delve/cmd/@v/list
# get https://goproxy.cn/github.com/go-delve/delve/cmd/dlv/@v/list
# get https://goproxy.cn/github.com/go-delve/delve/@v/list
# get https://goproxy.cn/github.com/go-delve/@v/list
# get https://goproxy.cn/github.com/@v/list: 404 Not Found (0.014s)
# get https://goproxy.cn/github.com/go-delve/delve/cmd/@v/list: 404 Not Found (0.027s)
# get https://goproxy.cn/github.com/go-delve/delve/cmd/dlv/@v/list: 404 Not Found (0.027s)
# get https://goproxy.cn/github.com/go-delve/delve/@v/list: 200 OK (0.027s)
# get https://goproxy.cn/github.com/go-delve/@v/list: 404 Not Found (0.027s)
WORK=/home/user/tmp/go-build2033992495
mkdir -p $WORK/b001/
cat >/home/user/tmp/go-build2033992495/b001/importcfg.link << 'EOF' # internal
packagefile github.com/go-delve/delve/cmd/dlv=/home/user/.cache/go-build/f1/f11d552287458c0fce625abe50bf928c487064c36bbb1251ad8b1968772c3e4b-d
......
......
mkdir -p /home/wyh/gomod/bin/
mv $WORK/b001/exe/a.out /home/wyh/gomod/bin/dlv
rm -r $WORK/b001/まずソースコードを GOMODCACHE が示すパスにダウンロードします。これは get コマンドと同じです。次に一時作業ディレクトリに切り替え、コンパイルを実行し、コンパイル完了後にバイナリファイルを GOPATH/bin ディレクトリに移動し、最後に一時フォルダを削除します。install コマンドにはもう 1 つ制限があり、ダウンロードするパッケージはプロジェクトのエントリーパッケージである必要があります。つまり main.go エントリーファイルを含む必要があります。そうしないと、インストールできないというプロンプトが表示されます。例えば、go install を使用して gin をダウンロード
$ go install -x github.com/gin-gonic/gin@latest
# get https://goproxy.cn/github.com/@v/list
# get https://goproxy.cn/github.com/gin-gonic/gin/@v/list
# get https://goproxy.cn/github.com/gin-gonic/@v/list
# get https://goproxy.cn/github.com/@v/list: 404 Not Found (0.022s)
# get https://goproxy.cn/github.com/gin-gonic/gin/@v/list: 200 OK (0.027s)
# get https://goproxy.cn/github.com/gin-gonic/@v/list: 404 Not Found (0.028s)
package github.com/gin-gonic/gin is not a main packagegin は Web フレームワークの依存関係ライブラリであり、コマンドラインツールではないため、当然エントリーファイルがなく、インストールに失敗します。
list
list コマンドは指定された位置のパッケージを一覧表示し、1 行に 1 つずつ表示し、カスタムフォーマット出力をサポートし、多くのパラメータをサポートします。これを使用する前提は gomod をサポートするプロジェクト内であることです。
$ go list -h
usage: go list [-f format] [-json] [-m] [list flags] [build flags] [packages]
Run 'go help list' for details.サポートするパラメータは以下の通りです
-f:フォーマットパラメータ-json:JSON 形式で出力-compiled:コンパイラによってコンパイルされるすべてのパッケージを表示-deps:各パッケージおよびその依存関係のすべてのパッケージの名前を表示-test:各パッケージのテストパッケージを表示-e:エラーが発生したパッケージでも正常に出力-find:これらのパッケージの依存関係を解析しない-export:このパラメータを使用すると、構造体Package.Exportフィールドの値を指定されたパッケージを含む最新の出力情報ファイルに設定し、Package.BuildIDフィールドの値をパッケージのBuildIDに設定します。主にフォーマット出力用です。
モジュール情報パラメータ:
-m:パッケージではなくモジュールを出力-versions:モジュールのすべての利用可能な情報を表示-retracted:モジュールの撤回バージョンを表示
[packages] パラメータは指定されたパッケージ名、フォルダ、または all にできます。all は任意の場所を意味し、-m パラメータを使用する場合、all は現在のモジュールによって参照されるすべての依存関係を意味します。
例えば、現在のファイルに main.go ファイルが 1 つだけで、"hello world" を出力するコードが 1 行だけある場合、go list -deps . を実行すると、現在のプロジェクトから fmt およびその参照されるすべての依存関係のパッケージが出力されます。
$ ls
go.mod go.sum main.go
$ cat main.go
package main
import "fmt"
func main() {
fmt.Println("hello world")
}
$ go list -deps .
internal/goarch
unsafe
internal/abi
internal/unsafeheader
internal/cpu
internal/bytealg
internal/coverage/rtcov
internal/godebugs
internal/goexperiment
internal/goos
runtime/internal/atomic
runtime/internal/math
runtime/internal/sys
runtime
......
......
path
io/fs
os
fmt
golearnまたは、現在のプロジェクトのすべてのモジュール依存関係を出力
$ go list -m all
golearn
cloud.google.com/go v0.26.0
github.com/246859/containers v0.0.1
github.com/246859/river v0.1.0 => D:\WorkSpace\Code\riverdb
github.com/BurntSushi/toml v0.3.1
github.com/Jleagle/steam-go v0.0.0-20230725082712-1053b441b1f2
github.com/Jleagle/unmarshal-go v0.0.0-20210227002040-694f544f9265
github.com/KyleBanks/depth v1.2.1
github.com/Microsoft/go-winio v0.6.1
github.com/PuerkitoBio/purell v1.1.1
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578
github.com/andeya/ameda v1.5.3
github.com/andeya/goutil v1.0.1
...format
list コマンドの出力は行単位で、各行の出力はパッケージです。公式はカスタム行出力フォーマットのパラメータ -f を提供しており、受け取る値は template/text テンプレートエンジンパッケージによって定義されたテンプレート構文です。例えば以下の例
-f "package {{ .Dir }} {{ .Name }}"反復される各パッケージは以下の構造体として渡され、この構造体のすべてのフィールドはテンプレートパラメータとして使用できます。
type Package struct {
Dir string // directory containing package sources
ImportPath string // import path of package in dir
ImportComment string // path in import comment on package statement
Name string // package name
Doc string // package documentation string
Target string // install path
Shlib string // the shared library that contains this package (only set when -linkshared)
Goroot bool // is this package in the Go root?
Standard bool // is this package part of the standard Go library?
Stale bool // would 'go install' do anything for this package?
StaleReason string // explanation for Stale==true
Root string // Go root or Go path dir containing this package
ConflictDir string // this directory shadows Dir in $GOPATH
BinaryOnly bool // binary-only package (no longer supported)
ForTest string // package is only for use in named test
Export string // file containing export data (when using -export)
BuildID string // build ID of the compiled package (when using -export)
Module *Module // info about package's containing module, if any (can be nil)
Match []string // command-line patterns matching this package
DepOnly bool // package is only a dependency, not explicitly listed
DefaultGODEBUG string // default GODEBUG setting, for main packages
// Source files
GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
CgoFiles []string // .go source files that import "C"
CompiledGoFiles []string // .go files presented to compiler (when using -compiled)
IgnoredGoFiles []string // .go source files ignored due to build constraints
IgnoredOtherFiles []string // non-.go source files ignored due to build constraints
CFiles []string // .c source files
CXXFiles []string // .cc, .cxx and .cpp source files
MFiles []string // .m source files
HFiles []string // .h, .hh, .hpp and .hxx source files
FFiles []string // .f, .F, .for and .f90 Fortran source files
SFiles []string // .s source files
SwigFiles []string // .swig files
SwigCXXFiles []string // .swigcxx files
SysoFiles []string // .syso object files to add to archive
TestGoFiles []string // _test.go files in package
XTestGoFiles []string // _test.go files outside package
// Embedded files
EmbedPatterns []string // //go:embed patterns
EmbedFiles []string // files matched by EmbedPatterns
TestEmbedPatterns []string // //go:embed patterns in TestGoFiles
TestEmbedFiles []string // files matched by TestEmbedPatterns
XTestEmbedPatterns []string // //go:embed patterns in XTestGoFiles
XTestEmbedFiles []string // files matched by XTestEmbedPatterns
// Cgo directives
CgoCFLAGS []string // cgo: flags for C compiler
CgoCPPFLAGS []string // cgo: flags for C preprocessor
CgoCXXFLAGS []string // cgo: flags for C++ compiler
CgoFFLAGS []string // cgo: flags for Fortran compiler
CgoLDFLAGS []string // cgo: flags for linker
CgoPkgConfig []string // cgo: pkg-config names
// Dependency information
Imports []string // import paths used by this package
ImportMap map[string]string // map from source import to ImportPath (identity entries omitted)
Deps []string // all (recursively) imported dependencies
TestImports []string // imports from TestGoFiles
XTestImports []string // imports from XTestGoFiles
// Error information
Incomplete bool // this package or a dependency has an error
Error *PackageError // error loading package
DepsErrors []*PackageError // errors loading dependencies
}
type PackageError struct {
ImportStack []string // shortest path from package named on command line to this one
Pos string // position of error (if present, file:line:col)
Err string // the error itself
}モジュールが反復される場合、以下の構造体として渡され、そのすべてのフィールドもテンプレートパラメータとして使用できます。
type Module struct {
Path string // module path
Query string // version query corresponding to this version
Version string // module version
Versions []string // available module versions
Replace *Module // replaced by this module
Time *time.Time // time version was created
Update *Module // available update (with -u)
Main bool // is this the main module?
Indirect bool // module is only indirectly needed by main module
Dir string // directory holding local copy of files, if any
GoMod string // path to go.mod file describing module, if any
GoVersion string // go version used in module
Retracted []string // retraction information, if any (with -retracted or -u)
Deprecated string // deprecation message, if any (with -u)
Error *ModuleError // error loading module
Origin any // provenance of module
Reuse bool // reuse of old module info is safe
}
type ModuleError struct {
Err string // the error itself
}すべてのパッケージを表示
$ go list -f "package {{.Dir}} {{.Name}}" ./...
package /golearn main
package /golearn/app cmd
package /golearn/cmd cmd
package /golearn/docs docs
package /golearn/tool tool
package /golearn/tool_test toolモジュールを表示
$ go list -m -f "mod {{.Path}} {{.Version}} {{.GoVersion}} {{.GoMod}}"
mod golearn 1.21.3 /golearn/go.modmod
go mod は go モジュールを管理するための専用コマンドです。
$ go mod help
Go mod provides access to operations on modules.
Note that support for modules is built into all the go commands,
not just 'go mod'. For example, day-to-day adding, removing, upgrading,
and downgrading of dependencies should be done using 'go get'.
See 'go help modules' for an overview of module functionality.
Usage:
go mod <command> [arguments]
The commands are:
download download modules to local cache
edit edit go.mod from tools or scripts
graph print module requirement graph
init initialize new module in current directory
tidy add missing and remove unused modules
vendor make vendored copy of dependencies
verify verify dependencies have expected content
why explain why packages or modules are needed
Use "go help mod <command>" for more information about a command.以下のサブコマンドがあります
download:go.modファイルに記載されているすべての依存関係をローカルキャッシュにダウンロードedit:go.modファイルを編集。コマンドラインインターフェースは主に他のツールやスクリプトに提供されます。init:現在のディレクトリに gomod プロジェクトを初期化tidy:不足している依存関係をダウンロードし、未使用の依存関係を削除graph:依存関係グラフを出力verify:ローカルの依存関係を検証why:なぜこれらのモジュールに依存しているかを説明vendor:プロジェクトの依存関係を vendor ディレクトリにエクスポート
init
$ go help mod init
usage: go mod init [module-path]init コマンドは gomod プロジェクトを初期化するために使用され、唯一のパラメータはモジュールパスです。将来的に他人が依存関係をダウンロードする必要がある場合、このモジュールパスを基準として使用する必要があります。命名ルールは一般的に以下の通りです
domain_name/user_name/repo_name例えば、プロジェクトを github に配置するのが一般的なので、以下のようになります
github.com/jack/gotour特殊な記号をモジュールパスとして使用することはお勧めしません。使用例を見てみましょう
$ mkdir gotour
$ cd gotour
$ go mod init "github.com/jack/gotour"
go: creating new go.mod: module github.com/jack/gotourtidy
$ go help mod tidy
usage: go mod tidy [-e] [-v] [-x] [-go=version] [-compat=version]tidy コマンドは go.mod から未使用の依存関係(参照されていない依存関係)をクリアし、参照されているが存在しない依存関係をダウンロードします。以下のパラメータをサポートします
-v:削除されたモジュール依存関係を出力-e:プロセス中にエラーが発生しても無視して続行-x:実行プロセスを出力-go=version:go.modファイルの go バージョンを更新-compact=version:指定された主要な Go バージョンから必要な追加チェックサムを保持してモジュールグラフを正常に読み込み、そのバージョンのgoコマンドが異なるモジュールバージョンからインポートされたパッケージを読み込むと tidy がエラーを発生させます。このパラメータは一般的にほとんど使用されず、通常はバージョン変更時にのみエラーが発生します。stackoverflow のこの回答をご覧ください:go modules - go mod tidy error message: "but go 1.16 would select" - Stack Overflow
使用例を見てみましょう
$ go mod tidy -v
unused github.com/246859/containers
unused github.com/246859/river
unused github.com/Jleagle/steam-go
unused github.com/Jleagle/unmarshal-go
unused github.com/KyleBanks/depth
unused github.com/Microsoft/go-winio
unused github.com/PuerkitoBio/purell
unused github.com/PuerkitoBio/urlesc
unused github.com/andeya/ameda
unused github.com/andeya/goutil
unused github.com/asaskevich/govalidator
unused github.com/buger/jsonparser
unused github.com/bwmarrin/snowflake
unused github.com/bytedance/go-tagexpr/v2
unused github.com/bytedance/sonic
unused github.com/cespare/xxhash/v2
unused github.com/chenzhuoyu/base64x
......download
$ go help mod download
usage: go mod download [-x] [-json] [-reuse=old.json] [modules]download コマンドの名前は翻訳するとダウンロードですが、依存関係をローカルの依存関係キャッシュにダウンロードするだけで、go.mod ファイルは変更しません。その役割は依存関係をローカルのファイルキャッシュに事前にダウンロードすることで、特定の依存関係をダウンロードしたい場合は、go get または go mod tidy を使用することをお勧めします。
以下はいくつかの使用例です
$ go mod download -x gorm.io/gorm
# get https://goproxy.cn/gorm.io/gorm/@v/list
# get https://goproxy.cn/gorm.io/gorm/@v/list: 200 OK (0.084s)パラメータなしで実行すると、go.mod ファイルに存在するがローカルの依存関係キャッシュに存在しないすべての依存関係をダウンロードします。ダウンロードする必要がない場合は、以下を出力します
go: no module dependencies to downloadedit
$ go help mod edit
usage: go mod edit [editing flags] [-fmt|-print|-json] [go.mod]edit は go.mod ファイルを変更するためのコマンドラインインターフェースで、通常は他のプログラムに提供されます。一部のエディタ IDE は gomod サポートを提供するためにこれらのコマンドを使用します。以下のパラメータをサポートします
-module:モジュールパスを変更-go=version:期待される go バージョンを変更-require=path@version:依存関係を追加-droprequire=path@version:依存関係を削除-exclude=path@version:除外依存関係を追加-dropexclude=path@version:除外依存関係を削除-replace=old@version=new@version:置換依存関係を追加-dropreplace=old@version:置換依存関係を削除-retract=version:バージョンロールバック項目を追加-dropretract=version:バージョンロールバック項目を削除
表示に使用される他のパラメータもあります
-print:ファイルの内容を出力-json:JSON 形式で出力
以下の例を見てください
$ go mod edit -print
module golearn
go 1.21.3
require (
github.com/dstgo/task v1.2.0
github.com/spf13/cast v1.5.1
github.com/swaggo/swag v1.16.2
golang.org/x/net v0.19.0
gorm.io/gorm v1.25.5
)graph
$ go help mod graph
usage: go mod graph [-go=version] [-x]graph コマンドは現在のプロジェクトの依存関係グラフを出力します。可読性は非常に悪く、ほとんどの場合、人間が読むためのものではなく、結果は通常処理されて視覚的な形式で表示されます。各行は依存関係で、形式は以下の通りです
引用方 被引用方例えば
golearn go@1.21.32 つのパラメータもサポートします
-go=version:指定された go バージョンを使用して依存関係グラフを読み込みます。その値はgo.modファイルのバージョンより小さくすることはできません。-x:プロセス中に実行されるコマンドを表示します。
簡単な使用例を見てみましょう
$ go mod graph
golearn github.com/246859/containers@v0.0.1
golearn github.com/246859/river@v0.1.0
golearn github.com/Jleagle/steam-go@v0.0.0-20230725082712-1053b441b1f2
golearn github.com/Jleagle/unmarshal-go@v0.0.0-20210227002040-694f544f9265
golearn github.com/KyleBanks/depth@v1.2.1
golearn github.com/Microsoft/go-winio@v0.6.1
golearn github.com/PuerkitoBio/purell@v1.1.1
golearn github.com/PuerkitoBio/urlesc@v0.0.0-20170810143723-de5bf2ad4578
golearn github.com/andeya/ameda@v1.5.3
golearn github.com/andeya/goutil@v1.0.1
golearn github.com/asaskevich/govalidator@v0.0.0-20230301143203-a9d515a09cc2
golearn github.com/buger/jsonparser@v1.1.1
golearn github.com/bwmarrin/snowflake@v0.3.0
golearn github.com/bytedance/go-tagexpr/v2@v2.9.11
......vendor
$ go help mod vendor
usage: go mod vendor [-e] [-v] [-o outdir]vendor は gomod が導入される前の gopath の代替案で、すべての go プロジェクトの下に vendor ディレクトリがあり、domain/user/project 形式で各プロジェクトの依存関係が個別に格納されています。隣接する nodeJs の膨大な node_module のように、各プロジェクトの依存関係が別々に格納されています。この依存関係管理方法は現在見ると確かに愚かですが、当時はより良い解決策がありませんでした。vendor が保持されているのは、go が下位互換性の約束を維持しているためで、いくつかの古いプロジェクトや go のソースコードでさえ vendor を使用している可能性があります。
本題に戻ると、vendor は go mod のサブコマンドで、現在のモジュールによって参照されるグローバル依存関係を vendor ディレクトリにエクスポートできます。
$ go mod vendor -h
usage: go mod vendor [-e] [-v] [-o outdir]
Run 'go help mod vendor' for details.以下のパラメータがあります
-o:出力パスフォルダを指定-v:各依存関係を出力-e:エラーが発生しても終了せずに続行
以下の例を見てみましょう。まず go list -m all を使用して、現在のプロジェクトによって参照される依存関係を確認します
$ go list -m all
github.com/dstgo/task
github.com/davecgh/go-spew v1.1.1
github.com/pkg/errors v0.9.1
github.com/pmezard/go-difflib v1.0.0
github.com/stretchr/objx v0.5.0
github.com/stretchr/testify v1.8.4
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405
gopkg.in/yaml.v3 v3.0.1現在の vendor ディレクトリにエクスポート
$ go mod vendor -v -e -o vendor
# github.com/davecgh/go-spew v1.1.1
## explicit
github.com/davecgh/go-spew/spew
# github.com/pkg/errors v0.9.1
## explicit
github.com/pkg/errors
# github.com/pmezard/go-difflib v1.0.0
## explicit
github.com/pmezard/go-difflib/difflib
# github.com/stretchr/testify v1.8.4
## explicit; go 1.20
github.com/stretchr/testify/assert
# gopkg.in/yaml.v3 v3.0.1
## explicit
gopkg.in/yaml.v3エクスポート後のディレクトリ構造は以下の通りです
└─vendor
├─github.com
│ ├─davecgh
│ │ └─go-spew
│ │ └─spew
│ ├─pkg
│ │ └─errors
│ ├─pmezard
│ │ └─go-difflib
│ │ └─difflib
│ └─stretchr
│ └─testify
│ └─assert
└─gopkg.in
| └─yaml.v3
|
|--modules.txtその中の modules.txt はすべての依存関係項目を記述するファイルで、現在の go.mod に似ています。
verify
$ go help mod verify
usage: go mod verifyこのコマンドは、プロジェクトの依存関係がローカルにダウンロードされた後に変更されたかどうかをチェックします。例えば、問題がなければ all modules verified を出力します
$ go mod verify
all modules verifiedそうでない場合は、どこが変更されたかを報告し、異常な状態でコマンドを終了します。例えば
$ go mod verify
gorm.io/gorm v1.25.5: dir has been modified (/go/mod/libs/gorm.io/gorm@v1.25.5)why
$ go help mod why
usage: go mod why [-m] [-vendor] packages...なぜこのパッケージに依存しているかを説明し、実際にはそれに関する依存関係グラフを出力します。例えば
$ go mod why gorm.io/gorm
# gorm.io/gorm
golearn
gorm.io/gormデフォルトでは main からのインポートのみを解析し、-m パラメータを追加すると、各パッケージのインポート状況を分析できます。
work
work コマンドは go の複数モジュール管理のためのローカル開発ツールです
$ go work help
Work provides access to operations on workspaces.
Note that support for workspaces is built into many other commands, not
just 'go work'.
The commands are:
edit edit go.work from tools or scripts
init initialize workspace file
sync sync workspace build list to modules
use add modules to workspace file
vendor make vendored copy of dependencies
Use "go help work <command>" for more information about a command.init
init サブコマンドは workspace を初期化するために使用され、go.work というファイルを作成します
$ go work init -h
usage: go work init [moddirs]
Run 'go help work init' for details.パラメータ [moddirs] を受け取り、どのモジュールを管理に含めるかを指定します。例えば
$ go work init ./service ./apiuse
use サブコマンドは go.work に管理対象モジュールディレクトリを追加するために使用されます
$ go help work use
usage: go work use [-r] [moddirs]
Use provides a command-line interface for adding
directories, optionally recursively, to a go.work file.パラメータ [moddirs] を受け取り、-r は [moddirs] パス下でモジュールを再帰的に検索することを示します。例えば
$ go work use -r ./oss-api ./multi_modulesedit
edit サブコマンドの役割は go mod edit と同じで、他のツールやスクリプトに提供されるコマンドラインインターフェースです。
$ go help work edit
usage: go work edit [editing flags] [go.work]
Edit provides a command-line interface for editing go.work,
for use primarily by tools or scripts. It only reads go.work;
it does not look up information about the modules involved.
If no file is specified, Edit looks for a go.work file in the current
directory and its parent directoriesパラメータは以下の通りです
-fmt:go.workファイルをフォーマット-use、-dropuse:モジュールパスを追加および削除-replace=old[@v]=new[@v]、-dropreplace=old[@v]=new[@v]:置換するモジュールを追加および削除-go、-toolchain=name:go バージョンを指定、および使用するツールチェーンを指定-print:最後の変更を出力し、ファイルに書き戻しません-json:json形式で出力。-printと同時に存在することはできません。対応する型構造は以下の通りですgotype GoWork struct { Go string Toolchain string Use []Use Replace []Replace } type Use struct { DiskPath string ModulePath string } type Replace struct { Old Module New Module } type Module struct { Path string Version string }
いくつかの使用例を以下に示します。フォーマット出力
$ go work edit -fmt -print
go 1.22.0
use (
./ab/cd
./auth
./user
)json 出力
$ go work edit -fmt -json
{
"Go": "1.22.0",
"Use": [
{
"DiskPath": "./ab/cd"
},
{
"DiskPath": "./auth"
},
{
"DiskPath": "./user"
}
],
"Replace": null
}sync
sync サブコマンドは go.work のモジュールリストを workspace の各モジュールに戻すために使用されます。
$ go help work sync
usage: go work sync
Sync syncs the workspace's build list back to the
workspace's modulesこのプロセスは主にローカル開発完了後、各モジュールのリリース作業が完了した後に発生します。この時点で sync を使用すると、各モジュールの依存関係に基づいて worksapce 内のすべてのモジュールの go.mod の依存関係が更新され、手動で更新する必要がなくなります。
vendor
vendor コマンドは workspace 内のすべてのモジュールが依存するライブラリのコピーを vendor ディレクトリに作成します。
$ go work help vendor
usage: go work vendor [-e] [-v] [-o outdir]機能は go mod vendor と同じで、これ以上の詳細は省略します。
vet
vet コマンドは go 言語ソースコードの静的エラーチェックツールで、他の言語の lint ツール(例えば Eslint)に似ています。
$ go vet -h
usage: go vet [build flags] [-vettool prog] [vet flags] [packages]
Run 'go help vet' for details.
Run 'go tool vet help' for a full list of flags and analyzers.
Run 'go tool vet -help' for an overview.まず簡単な例を見てみましょう。以下のソースコードがあります
$ cat main.go
package main
import "fmt"
func main(){
fmt.Println("hello world!"
}同じディレクトリでパラメータなしで go vet を実行
$ go vet
vet: ./main.go:6:28: missing ',' before newline in argument list (and 1 more errors)vet はどのファイルのどの行に什么问题があるかを報告します。ビルドフラグをパラメータとしてサポートし、例えば -n と -x、パッケージ、フォルダ、ファイル名をパラメータとしてサポートします。
$ go vet .
$ go vet main.go
$ go vet ./cmd
$ go vet runtime以下のコマンドを使用して、より詳細なパラメータと説明を確認できます。
$ go tool vet help
vet is a tool for static analysis of Go programs.
vet examines Go source code and reports suspicious constructs,
such as Printf calls whose arguments do not align with the format
string. It uses heuristics that do not guarantee all reports are
genuine problems, but it can find errors not caught by the compilers.
Registered analyzers:
asmdecl report mismatches between assembly files and Go declarations
assign check for useless assignments
atomic check for common mistakes using the sync/atomic package
bools check for common mistakes involving boolean operators
buildtag check //go:build and // +build directives
......go tool vet コマンドはコードのチェックに直接使用できず、go vet を使用する必要があります。go vet パラメータの [vet flag] はコードアナライザーを設定でき、利用可能な値は以下の通りです
asmdecl アセンブリファイルと go 宣言の不一致をチェック
assign 無用な代入をチェック
atomic sync/atomic の使用時の一般的なミスをチェック
bools 論理演算子の誤った使用をチェック
buildtag build tag をチェック
cgocall cgo ポインタ渡しルールの違反をチェック
composites 初期化されていない複合構造(map、chan など)をチェック
copylocks ロックの値コピーが発生したかチェック
directive go ツールチェーンディレクティブをチェック
errorsas errors.As に非ポインタ型または非 error 型が渡されているかチェック
framepointer コンパイル最適化後のアセンブリコードがフレームポインタを保存する前にクリアするかチェック
httpresponse httpresponse の誤った使用をチェック
ifaceassert インターフェースからインターフェースへの型アサーションをチェック
loopclosure ループ変数の参照問題
lostcancel context.WithCancel が cancel 関数を使用していない
nilfunc 関数と nil の間の無用な比較をチェック
printf printf のフォーマットパラメータが正しいかチェック
shift 整数幅と等しいか超えるシフトをチェック
sigchanyzer バッファなしの chan os.Signal をチェック
slog 無効な構造化ログ呼び出しをチェック
stdmethods 既知のインターフェースメソッドの署名が正しいかチェック
stringintconv 文字列整数変換をチェック
structtag 構造体 tag が正しいかチェック
testinggoroutine テストで goroutine を使用して testing.Fatal を呼び出しているかチェック
tests テストと例の一般的な誤った使用法をチェック
timeformat (time.Time).Format または time.Parse の時間形式が正しいかチェック
unmarshal unmarshal に非ポインタまたは非インターフェース型を渡しているかチェック
unreachable 到達できないコードをチェック
unsafeptr uintptr から unsafe.Pointer への不正な変換をチェック
unusedresult 未使用の関数戻り値をチェックこれらはすべて特定のポイントを分析するアナライザーで、例えば timeformat アナライザーは time.Format の呼び出し形式が正しい構文に従っているかを分析します。デフォルトでは上記のすべてのアナライザーが有効になります。個別に有効にするには以下の形式を使用します
$ go vet -timeformat main.go個別に無効にする
$ go vet -timeformat=false main.goこれらのアナライザーのソースコードは cmd/vendor/golang.org/x/tools/go/analysis/passes にあり、各アナライザーは go 言語でよくあるミスを対象としているため、vet コマンドを使用してコードをチェックすることを強くお勧めします。これら以外にも、いくつかの他のフラグパラメータをサポートしています
-V:バージョンのみを出力して終了-json:JSON 形式で出力-c=n:コンテキスト内の指定された数の競合行を表示(実際には何の役にも立たないようです)
いくつかの外部アナライザーもあります。例えば shadows は、短変数名の変数隠蔽問題をチェックします。外部にあるため、go install を使用してダウンロードする必要があります
$ go install golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow@latest使用形式は以下の通りです
$ go vet -vettool=$(which shadow)test
$ go test -h
usage: go test [build/test flags] [packages] [build/test flags & test binary flags]
Run 'go help test' and 'go help testflag' for details.test コマンドは go 言語ツールチェーンがテスト機能を提供するコマンドで、この機能は非常に重要です。ソフトウェアにとって、完善されたテストは不可欠です。ここでは test コマンドの使用方法を簡単に紹介するだけです。テストに関する詳細については、テスト をご覧ください。
build コマンドのコンパイルパラメータをサポートするほか、test は以下のパラメータもサポートします
-args:プログラムのエントリーパラメータ-c:現在のパッケージのテストバイナリファイルを現在のディレクトリにコンパイルしますが、実行しません。pkg.test方式で命名-exec:テスト開始前に他のコマンドを実行-json:テストの出力スタイルを json に変更-o:テストバイナリファイルのパス名を指定
また、多くの testflag もサポートしています。help コマンドを使用してすべての testflag を確認できます
$ go help testflag
The 'go test' command takes both flags that apply to 'go test' itself
and flags that apply to the resulting test binary.
The following flags are recognized by the 'go test' command and
control the execution of any test:
-bench regexp
-benchtime t
-count n
......いくつかの一般的なものを紹介します
-v:各ユースケースのテスト結果を出力-timeout duration:テスト実行のタイムアウト時間-skip regexp:指定されたテストユースケースをスキップ-short:実行時間の長いテストユースケースの実行時間を短縮-shuffle:すべてのテストユースケースの実行順序をシャッフル-run regexp:指定されたテストユースケースを実行-list regexp:各テストユースケースを一覧表示-cpu 1,2,4:CPU 数を指定-count n:各テストユースケースの実行回数を指定
最も簡単な使い方は、パラメータなしで、現在のパッケージ下のすべてのテストユースケースを実行し、結果を出力します。
$ ls *_test.go
hello_test.go
$ go test
PASS
ok golearn 0.522s特定のテストファイルを指定
$ go test hello_test.go
ok command-line-arguments 0.041s-v パラメータを追加すると、より詳細な出力を確認できます。非常に一般的に使用されます。
$ go test -v hello_test.go
=== RUN TestHello
hello_test.go:6: hello world!
--- PASS: TestHello (0.00s)
PASS
ok command-line-arguments 0.041s特定のテストユースケースを指定
$ go test -v -run TestHello
=== RUN TestHello
hello_test.go:6: hello world!
--- PASS: TestHello (0.00s)
PASS
ok golearn 0.028sテスト時、test コマンドには 2 つのモードがあります。まず 1 つ目のフォルダモードから説明します。package パラメータなしで test コマンドを実行すると、フォルダモードでテストが実行されます。以下のコマンドのようになります
$ go test
$ go test -vこのモードでは、テストキャッシュが無効になります。もう 1 つのモードはリストモードで、package パラメータが空でない場合、リストモードでテストが実行されます。前者との違いはテストキャッシュが有効かどうかです。例えば以下のようになります
$ go test -v .
$ go test -v ./...
$ go test .
$ go test -v net/httpリストモードでは、go は指定されたパッケージ下の各パッケージのテストファイルをバイナリファイルにコンパイルして実行します。テストの重複実行を避けるため、go はデフォルトで結果をキャッシュし、2 回目の実行時に再コンパイルしません。以下のパラメータを使用すると、デフォルトでキャッシュが有効になります
-benchtime-cpu-list-parallel-runshort-timeout-failfast-v
これらのパラメータ以外の他のパラメータを使用すると、キャッシュを無効にできます。公式が推奨する方法は -count=1 を使用してキャッシュを無効にすることです。例えば
$ go test -v -count=1 ./...ディレクティブ
コマンドとは異なり、go のディレクティブはソースファイル内にハードコードされた形式で存在し、別の専門的な名前があります:コンパイルディレクティブ(progma directives)です。
コンパイラとリンカーはこれらの動作を変更することでコンパイルを制御し、c 言語のマクロに少し似ています。もちろん、すべてのディレクティブがコンパイルに影響を与えるわけではなく、一部は他の機能的な動作に使用されます。例えば generate ディレクティブは通常コード生成機能に使用されます。これらのディレクティブは通常コメントの形式で存在し、//go: をプレフィックスとし、間にスペースを含めることはできません。例えば //go:generate ディレクティブです。すべてのディレクティブタイプは 2 つに分類されます
- 機能的ディレクティブ:これらは go が提供する機能的ディレクティブで、自由に使用できます。例えば
generate、embed、build。 - コンパイラディレクティブ:これらは慎重に使用する必要があり、無闇に使用すると予測できない結果を招く可能性があります。
機能的ディレクティブを除き、ほとんどのディレクティブは関数署名にのみ作用できます。コンパイラディレクティブについては、go doc compile コマンドを実行してディレクティブを確認できます。すべてのディレクティブについては、cmd/compile/internal/ir/node.go: 440 で関連情報を見つけることができます。
generate
$ go help generate
usage: go generate [-run regexp] [-n] [-v] [-x] [build flags] [file.go... | packages]generate ディレクティブはその名の通り生成に関連するもので、通常はコード生成およびソースコード更新のコマンドを実行するために使用されますが、実際には任意のコマンドを実行できます。さらに、generate ディレクティブは他のディレクティブとは異なり、ソースファイル内のすべての generate ディレクティブを実行するための専用コマンドがあります。ファイル名またはパッケージ名を入力パラメータとして使用して、どのファイルの generate ディレクティブを実行するかを示せます。以下は他のパラメータです。
-run=regex:指定された generate ディレクティブを実行-skip=regex:指定された generate ディレクティブをスキップ-n:実行されるコマンドを出力-x:プロセス中に実行されるコマンドを出力-v:処理されたファイルを出力
さらに、generate ディレクティブで実行されるコマンドは以下の組み込みパラメータもサポートします
$GOARCH:CPU アーキテクチャ$GOOS:オペレーティングシステム$GOFILE:ファイル名$GOLINE:行番号$GOPACKAGE:パッケージ名$GOROOT:go root$DOLLAR:ドル記号$PATH:path 環境変数
例を見てみましょう。コードは何もなく、コメントが 1 行だけです
package main
//go:generate echo "hello world!"コマンドを実行
$ go generate .
hello world!この例は go コマンドを実行します
package main
//go:generate go versionコマンドを実行
$ go generate .
go version go1.21.3 windows/amd64generate ディレクティブは任意のコマンドを実行するために使用でき、例えば swagger で API ドキュメントを生成したり、Wire で IOC コードを生成したりできます。ただし、このディレクティブは特に複雑なコマンドを実行するには適していません。短いコマンドの実行に適しており、複雑な要件がある場合はスクリプトまたは makefile を代わりに使用できます。
embed
embed ディレクティブは 1.16 で追加され、静的ファイルをバイナリファイルにパッケージ化する役割を果たします。例えば HTML テンプレートなどです。形式は以下の通りです
//go:embed patternpattern は glob 式、フォルダ、または特定のファイルにできます。例を見てみましょう
package main
import "embed"
//go:embed *
var static embed.FSembed ディレクティブは embed.Fs 型のグローバル変数の上に配置する必要があります。グローバル変数である必要があり、これを使用するには embed パッケージをインポートする必要があります。この例では、* は現在のフォルダ下のすべてのファイルをバイナリファイルにパッケージ化することを表しますが、. で始まるフォルダの存在は許可されません。
以下の例は、埋め込まれたファイルから内容を読み取る方法を示しています
package main
import (
"embed"
"fmt"
)
//go:embed *.txt
var static embed.FS
func main() {
bytes, err := static.ReadFile("hello.txt")
if err != nil {
panic(err)
}
fmt.Println(string(bytes))
}3 つのメソッドしかなく、通常のファイルシステムとの使い方に違いはありません。io/Fs インターフェースを実装しているため、Fs オブジェクトとして渡すこともできます。
func (f FS) Open(name string) (fs.File, error)
func (f FS) ReadFile(name string) ([]byte, error)
func (f FS) ReadDir(name string) ([]fs.DirEntry, error)以下の例は、embed ディレクティブを介して html ファイルを埋め込み、http サービスを介してアクセスする方法を示しています。
package main
import (
"embed"
"net/http"
)
//go:embed index.html
var htmlFs embed.FS
func main() {
http.Handle("/", http.FileServer(http.FS(htmlFs)))
http.ListenAndServe(":8080", http.DefaultServeMux)
}アクセス結果は以下の通りです
$ curl -s -GET 127.0.0.1:8080
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>hello world!</title>
</head>
<body>
<H1>Hello World!</H1>
<script>
alert("hello world!");
</script>
</body>
</html>embed ディレクティブは、グローバル変数の型を []byte にすることもサポートします。以下の例を見てください
package main
import (
_ "embed"
"net/http"
)
//go:embed index.html
var rawdata []byte
func main() {
http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
writer.Write(rawdata)
})
http.ListenAndServe(":8080", http.DefaultServeMux)
}実装される効果は前の例とあまり変わりません。
$ curl -s -GET 127.0.0.1:8080
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>hello world!</title>
</head>
<body>
<H1>Hello World!</H1>
<script>
alert("hello world!");
</script>
</body>
</html>build
build-コンパイル制御 セクションでは、// +build ディレクティブを使用してコンパイル動作を制御する方法について説明しました。//go:build ディレクティブは 1.17 で新しく導入され、以前のディレクティブに取って代わることを意図していましたが、現在 1.21 でもまだ置き換えられておらず、おそらく今後は共存する形で存在するでしょう。この新しいディレクティブについては、公式ドキュメントでも紹介されています:build constraints。機能は前者と変わりませんが、構文はより厳格で、ブール式をサポートします。例を見てみましょう
//go:build (linux && 386) || (darwin && !cgo)
package pkg_nameこの方式は元の方式よりもはるかに可読性が高くなっています。
line
line ディレクティブは次の行の行番号、列番号、およびファイル名に影響します。その役割はこれだけで、ほとんどの場合、エラーのデバッグなどに使用される可能性があります。例えば、エラー発生時にコンパイラが出力する情報を変更します。
package main
var a undefinedType
func main() {
}通常、コンパイラは以下を出力します
.\main.go:3:7: undefined: undefinedTypeしかし、line ディレクティブを使用すると、状況が異なります
package main
//line abc.go:10:100
var a undefinedType
func main() {
}出力は以下のようになります
abc.go:10:106: undefined: undefinedType歴史的な理由により、line ディレクティブは他のディレクティブとは異なる唯一のディレクティブです。形式は以下の通りです
//line filename:line:column他のディレクティブとは異なり、go: をプレフィックスとする必要がないことがわかります。
linkname
このディレクティブの操作は、他のパッケージの関数またはグローバル変数にリンクするために使用でき、それがプライベート型であってもかまいません。この操作は標準ライブラリ、特に runtime で頻繁に使用されます。関数本体がない一部の関数はこの方式を介して実装され、もう一方の関数本体が空の関数はアセンブリによって実装されます。使い方を確認してみましょう。使用形式は以下の通りです
//go:linkname リンク型名 リンクされる型使用前に、例えば unsafe パッケージをインポートする必要があります。標準ライブラリのプライベート型にリンクする簡単な例を見てみましょう
import (
"fmt"
"unsafe"
)
//go:linkname memhash runtime.memhash
func memhash(p unsafe.Pointer, h, s uintptr) uintptr
func MemHash(data []byte) uint64 {
ptr := unsafe.Pointer(unsafe.SliceData(data))
return uint64(memhash(ptr, 0, uintptr(len(data))))
}
func main() {
fmt.Println(MemHash([]byte("hello")))
}出力
15395306441938000233runtime.memhash というプライベート関数を自分で宣言した関数にリンクしました。この関数は関数本体ではなく署名だけで、キャリアの役割を果たします。memhash の役割は、ポインタ、ハッシュシード、およびメモリオフセットを指定して、メモリに基づいてハッシュ値を計算することです。このリンクプロセスはコンパイル時に完了します。
標準ライブラリでない場合、状況は少し異なります。例えば example パッケージに test 関数がある場合、リンクする前にまずこのパッケージを匿名インポートする必要があります。
package example
// プライベート型、外部からアクセスできません。
func test() string {
return "a"
}package main
import (
"fmt"
_ "golearn/example"
_ "unsafe"
)
//go:linkname test golearn/example.test
func test() string
func main() {
fmt.Println(test())
}出力
aリンクが成功したことがわかります。この方法は go のモジュールシステムを迂回して何でもできますが、大規模な使用はお勧めしません。自分が何をしているかを知っている場合を除きます。
noinline
noinline ディレクティブは、関数が非常にシンプルであっても、インライン最適化を禁止することを示します。簡単な例を見てみましょう
package main
func val() string {
return "val"
}
func main() {
var c = val()
_ = c
}val は非常にシンプルな関数で、文字列リテラルを返す役割を果たします。非常にシンプルで結果が常に予測可能であるため、コンパイル時に以下の形式に最適化されます
package main
func main() {
var c = "val"
_ = c
}アセンブリ形式を確認してみましょう。val 関数の呼び出しが見つからないことがわかります。
TEXT main.val(SB), NOSPLIT|NOFRAME|ABIInternal, $0-0
FUNCDATA $0, gclocals·g2BeySu+wFnoycgXfElmcg==(SB)
FUNCDATA $1, gclocals·g2BeySu+wFnoycgXfElmcg==(SB)
LEAQ go:string."val"(SB), AX
MOVL $3, BX
FUNCDATA $0, gclocals·g2BeySu+wFnoycgXfElmcg==(SB)
RET次に noinline ディレクティブを追加します
package main
//go:noinline
func val() string {
return "val"
}
func main() {
var c = val()
_ = c
}アセンブリ形式を再度確認してみましょう
CMPQ SP, 16(R14)
PCDATA $0, $-2
JLS 17
PCDATA $0, $-1
PUSHQ BP
MOVQ SP, BP
FUNCDATA $0, gclocals·g2BeySu+wFnoycgXfElmcg==(SB)
FUNCDATA $1, gclocals·g2BeySu+wFnoycgXfElmcg==(SB)
PCDATA $1, $0
CALL main.val(SB)
POPQ BP
RET今回は main.val という呼び出しがはっきりと見え、これが noinline ディレクティブの機能で、コンパイラ最適化時の関数インラインを阻止します。
nosplit
nosplit ディレクティブの役割はスタックオーバーフロー検出をスキップすることです。go の並行スケジューリングモデルはプリエンプティブスケジューリングであるため、関数が非常に低レベルのコードを実行し、他の goroutine がこの関数を呼び出す際にプリエンプトに適さない場合、このディレクティブを使用して示すことができます。
//go:nosplit
func nospilitFn()このディレクティブを使用すると、スタック成長も実行されなくなります。
noescape
noescape は名前からも推測できるようにエスケープに関連するもので、現在の関数でメモリリーク動作が発生しないことを示します。実行完了後、すべてのリソースが回収され、この関数は署名のみで関数本体を持たない必要があります。この場合、通常関数の実装はアセンブリによって実装されます。
例えば、以前に使用した memhash はこのディレクティブを使用します
//go:noescape
//go:linkname memhash runtime.memhash
func memhash(p unsafe.Pointer, h, s uintptr) uintptrこれにより、コンパイラはエスケープ分析を実行しなくなります。エスケープが発生しないことを保証する必要があります。エスケープが発生した場合、どのような結果になるかはわかりません。
uintptrescapes
uintptrescapes ディレクティブは、この関数内の uintptr 型パラメータがポインタ値に変換され、ヒープにエスケープし、存続を維持する必要があることを示します。このディレクティブは通常、いくつかの低レベルのシステム呼び出しに使用され、ほとんどの場合、理解する必要はありません。
//go:uintptrescapes
func nospilit(ptr uintptr) uintptr以前は notinheaps というディレクティブがあり、型がヒープにメモリを割り当てることを許可しないことを示していましたが、どのバージョンで削除されたかはわかりません。
norace
norace ディレクティブは、関数のメモリアクセスが競合分析を必要としないことを示します。通常、低レベルのコードを実行する際に競合分析に適さない場合に使用されます。
//go:norace
func low_level_code(ptr uintptr) uintptrTIP
runtime パッケージのみで使用が制限されているディレクティブもあり、外部では使用できません。それらはより深いものに関与し、詳細については Runtime-only compiler directives で確認できます。
