CLOVER🍀

That was when it all began.

Goで使用する環境変数を表示・変更するgo envコマンド

これは、なにをしたくて書いたもの?

Goで使う環境変数を知りたいなと思ったのですが、goコマンドを見ていてenvというコマンドがあるのに気づき。

少し見てみようかな、と。

環境

今回の環境は、こちらです。

$ go version
go version go1.15.6 linux/amd64

go env

go envコマンドの説明自体は、ドキュメントに書かれています。

Command go / Print Go environment information

デフォルトではGoの環境変数情報をシェルスクリプト(Windowsではバッチファイル形式)として、出力するコマンドです。

手元の環境では、こうなりました。

$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="$HOME/.cache/go-build"
GOENV="$HOME/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="$HOME/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="$HOME/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/lib/go-1.15"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/lib/go-1.15/pkg/tool/linux_amd64"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build915242196=/tmp/go-build -gno-record-gcc-switches"

これらの環境変数はOSの環境変数で上書きすることも可能ですが、OS上で設定されていない場合はGo内に閉じた環境変数という
扱いのようです。

なので、Goをインストールしたからといって、これらの環境変数がOSに設定されているわけではありません。

$ env | grep GO

話を戻して。

特定の環境変数のみに絞って出力することもできます。

$ go env GOOS
linux


$ go env GOOS GOARCH
linux
amd64

-jsonフラグを付けると、JSON形式として出力できます。

$ go env -json
{
    "AR": "ar",
    "CC": "gcc",
    "CGO_CFLAGS": "-g -O2",
    "CGO_CPPFLAGS": "",
    "CGO_CXXFLAGS": "-g -O2",
    "CGO_ENABLED": "1",
    "CGO_FFLAGS": "-g -O2",
    "CGO_LDFLAGS": "-g -O2",
    "CXX": "g++",
    "GCCGO": "gccgo",
    "GO111MODULE": "",
    "GOARCH": "amd64",
    "GOBIN": "",
    "GOCACHE": "$HOME/.cache/go-build",
    "GOENV": "$HOME/.config/go/env",
    "GOEXE": "",
    "GOFLAGS": "",
    "GOGCCFLAGS": "-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build818370082=/tmp/go-build -gno-record-gcc-switches",
    "GOHOSTARCH": "amd64",
    "GOHOSTOS": "linux",
    "GOINSECURE": "",
    "GOMOD": "",
    "GOMODCACHE": "$HOME/go/pkg/mod",
    "GONOPROXY": "",
    "GONOSUMDB": "",
    "GOOS": "linux",
    "GOPATH": "$HOME/go",
    "GOPRIVATE": "",
    "GOPROXY": "https://proxy.golang.org,direct",
    "GOROOT": "/usr/lib/go-1.15",
    "GOSUMDB": "sum.golang.org",
    "GOTMPDIR": "",
    "GOTOOLDIR": "/usr/lib/go-1.15/pkg/tool/linux_amd64",
    "PKG_CONFIG": "pkg-config"
}

また、環境変数は-w NAME=VALUE形式で設定でき、-uで解除できるようです。これは後で試してみましょう。

Goの環境変数

ドキュメントとしては、以下に説明があります。

Command go / Environment variables

同様の内容は、以下のコマンドでも確認できます。

$ go help environment

Goの環境変数で困ったら、まずはここを見るのが良さそうですね。

環境変数を設定する

go envでは、-w、-uフラグで環境変数の設定ができる、ということでした。こちらを試してみます。

たとえば、$GO111MODULEを変更してみましょう。

まずは現在の値を確認。

$ go env GO111MODULE


$ go env | grep GO111MODULE
GO111MODULE=""

値が入っていません。この環境変数はon、off、autoの3つの値を取りうるらしいので(デフォルトはauto)これをonに
設定してみましょう。

設定。

$ go env -w GO111MODULE=on

確認。

$ go env GO111MODULE
on


$ go env | grep GO111MODULE
GO111MODULE="on"

確かに変更されました。

ちなみに、この値は$GOENVで指定されたファイルに保存されます。こんな感じですね。

$ cat `go env GOENV`
GO111MODULE=on

パスは、こちらです。

$ go env GOENV
$HOME/.config/go/env

では、設定した環境変数を削除してみましょう。

$ go env -u GO111MODULE

値がなくなりました。

$ go env GO111MODULE


$ go env | grep GO111MODULE
GO111MODULE=""

$GOENVに指定されているファイルからも、確かに消えています。

$ cat `go env GOENV`

一時的に環境変数を変更したい場合

Goでクロスプラットフォームを意識したビルドを行う場合、$GOOSを指定した例をよく見ます。

軽くサンプルを作ってみましょう。

$ go mod init hello-world
go: creating new go.mod: module hello-world

「Hello World!!」を出力するプログラムを作成。
hello.go

package main

import (
    "fmt"
)

func main() {
    fmt.Println("Hello World!!")
}

これでgo buildすると、Linux用の実行ファイルが得られます。

$ go build


$ ./hello-world 
Hello World!!


$ ll hello-world
-rwxrwxr-x 1 xxxxx xxxxx 2034781  1月  3 22:19 hello-world*

この時点で、手元の環境ではGoの環境変数$GOOSの値はlinuxです。

$ go env GOOS
linux

ここで、シェル上で$GOOSをwindowsに指定して作成すると、Windows用の実行ファイルが得られます。

$ GOOS=windows go build


$ ll hello-world*
-rwxrwxr-x 1 xxxxx xxxxx 2034781  1月  3 22:19 hello-world*
-rwxrwxr-x 1 xxxxx xxxxx 2140672  1月  3 22:20 hello-world.exe*

こんな感じですね。

で、話を戻して。go env -wで指定してしまうと、goコマンド全体に効いてしまうので、このように一時的に切り替えたい場合は
OSの環境変数で指定するのが良さそうですね。

そして、これでGoの環境変数をOSの環境変数で上書きできることも確認できました、と。

なお、この例からもわかるように、Goの環境変数よりもOSの環境変数の方が優先されるんですね。