명령줄

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 명령으로, 이를 통해 명령의 사용법을 확인할 수 있습니다. 두 가지 사용 방법이 있는데, 지정된 명령 뒤에 -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: 한 줄 간단한 설명만 표시-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
pkg
PATENTS
README.md
SECURITY.md
src
test
VERSION루트 디렉토리에는 몇 가지 중요한 폴더나 파일이 있습니다.
lib: 일부 의존성을 저장하며, 현재는 세계 각국의 시간대 정보를 포함하는 라이브러리 하나만 있으며,$GOROOT/lib/time에 위치합니다. 컴파일된 바이너리 파일에는 이러한 시간대 정보가 포함되지 않습니다.pkg: 일부 도구 라이브러리와 헤더 파일을 저장하며, 예를 들어go tool명령은$GOROOT/pkg/tool디렉토리에서 go 도구 체인의 바이너리 파일을 찾습니다.bin: 바이너리 파일을 저장하며, 기본적으로go와gofmt두 개의 실행 파일만 있습니다.go명령을 사용하려면$GOROOT/bin을 시스템 변수에 추가해야 합니다.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 프로젝트의 의존성을 관리하는 방식을 나타내며, 다음 세 가지 값을 사용할 수 있습니다.
off: gomod 를 끄고 gopath 를 사용하며 모든go.mod파일을 무시합니다.on: gomod 를 사용하고 gopath 를 사용하지 않습니다 (기본값).auto: 자동 감지, 프로젝트 파일에go.mod가 포함되어 있으면 gomod 를 사용하여 관리합니다.
TIP
왜 GOMODULE 이 아니라 GO111MODULE 일까요? 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/1/266
# get https://goproxy.cn/sumdb/sum.golang.org/tile/8/0/x068/334
# 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: Qiniu Cloud 에서 제공하며 오픈소스
물론 오픈소스 자체 모듈 프록시 구축方案도 있습니다: 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 두 가지 컴파일러를 지원합니다. gcc 는 오래된 c/c++ 컴파일러로 go 를 포함한 여러 언어를 지원하며, 후자인 gc 는 garbage collection 을 의미하는 것이 아니라 go compiler 를 의미합니다. go 언어는 go1.5 에서 자체 컴파일을 완료했으며, gc 는 완전히 go 언어로 작성된 컴파일러로, 소스 코드는 cmd/compile 패키지에 위치합니다. 완전히 go 언어로 구현되었기 때문에 내부 메커니즘을 이해하고 학습하기에 매우 편리합니다. 기본적으로 컴파일러는 gc 를 사용하여 컴파일합니다.顺便说一下,go 언어 디버거도 gdb 와 dlv 두 가지가 있으며, 전자는 오래된 c/c++ 디버거로 go 를 포함한 여러 언어를 지원하고, 후자는 go 언어로 작성된 디버거로 go 언어에 더 친숙한 지원을 제공합니다. 이 또한 오픈소스이며 후자를 사용하는 것을 권장합니다.
build 명령은 go 소스 파일을 실행 가능한 바이너리 파일로 컴파일하는 역할을 하며, 매우 빠른 컴파일 경험을 제공합니다. 이 또한 go 언어의 특징 중 하나입니다.
$ go build -h
usage: go build [-o output] [build flags] [packages]
Run 'go help build' for details.세 가지 매개변수를 받습니다. 하나는 -o 플래그가 지시하는 파일 출력 경로, 하나는 컴파일 동작을 정의하는 빌드 플래그 build flags, 마지막 하나는 컴파일할 패키지입니다. 이 매개변수는 반드시 마지막에 있어야 합니다. 다음은 빌드 플래그를 사용하지 않는 간단한 예시입니다.
# 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 의 일부 tag 지정-gccgoflags: 컴파일러 gccgo 의 일부 tag 지정-ldflags: link 도구의 일부 tag 지정
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
用法:compile [选项] file.go...
-% 调试非静态初始化器
-+ 编译运行时
-B 禁用边界检查
-C 禁用错误消息中的列号打印
-D path
设置本地导入的相对路径
-E 调试符号导出
-I directory
添加目录到导入搜索路径
-K 调试缺失的行号
-L 对于受 //line 指令影响的错误位置,同时显示实际源文件名
-N 禁用优化
-S 打印汇编列表
-V 打印版本并退出
-W 类型检查后调试解析树
......다음은 몇 가지 일반적으로 사용되는 매개변수입니다.
-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 언어 컴파일의 두 가지 큰 특징 중 하나는 빠르다는 것이며, 다른 하나는 교차 컴파일입니다. 교차 컴파일은 로컬에서 다른 시스템의 대상 코드로 컴파일할 수 있음을 의미합니다. 예를 들어 windows 에서 linux 나 darwin 의 바이너리 파일로 컴파일할 수 있으며, 그 반대도 마찬가지입니다. 교차 컴파일을 지원하는 언어는 매우 많지만 이는 특별한 일이 아닙니다. 그러나 go 언어의 교차 컴파일은 매우 간단하며 다음 두 단계만 필요합니다.
- 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 를 사용하면 교차 컴파일을 정상적으로 사용할 수 없습니다. 두 번째 단계 SET GOOS 는 대상 시스템을 설정하며, 옵션은 linux, darwin, windwos, netbsd 가 있습니다. 세 번째 단계는 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는 한 칸 띄어야 합니다.- 패키지 선언 위에 있어야 합니다.
- 패키지 선언과는 한 줄의 빈 줄을 두어야 합니다.
또한 간단한 간격을 통해 논리 제어를 할 수 있습니다. 공백은 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 방식으로 처리됩니다. 플랫폼과 아키텍처와 같은 tag 는 컴파일 시 go 가 자동으로 전달하며, 사용자 정의 tag 도 전달할 수 있습니다. 처음 두 파일을 예로 들면:
$ go build -tags="debug" . && ./golearn.exe
debug
$ go build -tags="product" . && ./golearn.exe
product서로 다른 tag 를 전달할 때 출력이 다르며 컴파일 제어 목적을 달성할 수 있습니다.
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,types} 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 공식의 태도를 보여줍니다. 개인화를 원하지 않으며 모든 사람의 코드 스타일이 일치하는 것이 좋습니다. 적어도 코드를 읽을 때 다른 사람의 습관에 적응할 필요가 없다는 장점이 있습니다. 하지만 실제로는 사용자 정의 항목이 하나 있습니다. 바로 포맷팅 코드 교체 규칙으로, 규칙은 사용자 정의할 수 있으며 형식은 다음과 같습니다.
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 개발 과정에서 가장 일반적으로 사용되는 명령으로, 지정된 주소의 패키지 소스 코드를 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의 매개변수 중 하나입니다.
옛날에는 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 로 지원하며, 다른 세 가지는 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 명령에는 또 다른 제한 사항이 있으며, 다운로드할 패키지는 프로젝트의 진입 패키지여야 합니다. 즉, 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 은 웹 프레임워크 의존성 라이브러리이며 명령줄 도구가 아니므로 진입 파일이 없어 설치가 실패합니다.
list
list 명령은 지정된 위치의 패키지를 나열하며, 한 줄에 하나씩 출력하며 사용자 정의 포맷팅 출력을 지원하며 많은 매개변수를 지원합니다. 사용하려면 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 일 수도 있으며, 이는 어디든 의미합니다. -m 매개변수를 사용할 때 all 은 현재 모듈이 참조하는 모든 의존성을 의미합니다.
예를 들어, 현재 파일에 main.go 파일 하나만 있으며, "hello world" 를 출력하는 코드 한 줄만 있는 경우, 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.3두 가지 매개변수를 지원합니다.
-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 를 사용하면 각 모듈의 의존성 관계에 따라 workspace 의 모든 모듈의 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 테스트에서 코루틴으로 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
`go test` 命令既接受作用于 `go test` 本身的标志,
也接受作用于生成的测试二进制文件的标志。
`go 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 명령에는 두 가지 모드가 있습니다. 먼저 폴더 모드에 대해 설명하겠습니다. package 매개변수 없이 test 명령을 실행하면 폴더 모드로 실행됩니다. 예를 들어 다음 명령들이 있습니다.
$ go test
$ go test -v이 모드에서는 테스트 캐시가 비활성화됩니다. 다른 모드는 목록 모드로, package 매개변수가 비어 있지 않으면 목록 모드로 테스트합니다. 이전과의 차이점은 테스트 캐시 활성화 여부입니다. 예를 들어 다음 명령들이 있습니다.
$ go test -v .
$ go test -v ./...
$ go test .
$ go test -v net/http목록 모드에서 go 는 지정된 패키지의 각 패키지의 테스트 파일을 바이너리 파일로 컴파일하여 실행합니다. 테스트 반복 실행을 피하기 위해 go 는 기본적으로 결과를 캐시하며, 두 번째 실행 시 다시 컴파일하지 않습니다. 다음 매개변수를 사용할 때 기본적으로 캐시가 활성화됩니다.
-benchtime-cpu-list-parallel-runshort-timeout-failfast-v
이러한 매개변수 외의 다른 매개변수를 사용하면 캐시를 끌 수 있으며, 공식에서 권장하는 방법은 -count=1 을 사용하여 캐시를 비활성화하는 것입니다. 예를 들어:
$ go test -v -count=1 ./...지시문
명령과 달리 go 의 지시문은 소스 파일에 하드코딩 형태로 존재하며, 또 다른 전문적인 이름인 컴파일 지시 (progma directives) 라고도 합니다.
컴파일러와 링커는 이로 인해 동작을 변경하여 컴파일을 제어하는 효과를 얻으며, c 언어의 매크로와 유사합니다. 물론 모든 지시문이 컴파일에 영향을 미치는 것은 아니며, 일부는 다른 기능적 동작 (예: generate 지시문은 일반적으로 코드 생성 기능에 사용됨) 에 사용됩니다. 이러한 지시문은 일반적으로 주석 형태로 존재하며, //go: 를 접두사로 하며 중간에 공백을 포함할 수 없습니다. 예를 들어 //go:generate 지시문입니다. 모든 지시문 유형은 총 두 가지로 나뉩니다.
- 기능적 지시문: 이는 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 환경 변수
예를 보겠습니다. 코드 없이 주석 한 줄만 있습니다.
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))
}세 가지 메서드만 있으며, 일반적인 파일 시스템과 다르게 사용할 수 없습니다. 또한 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 의 동시성 스케줄링 모델이 선점형 스케줄링이기 때문에, 함수가 매우 낮은 수준의 코드를 실행하고 다른 코루틴이 이 함수를 호출할 때 선점하기에 적합하지 않은 경우 이 지시문을 사용하여 나타낼 수 있습니다.
//go:nosplit
func nosplitFn()이 지시문을 사용하면 더 이상 스택 증가가 수행되지 않습니다.
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 nosplit(ptr uintptr) uintptr예전에는 notinheaps 라는 지시문이 있어 타입이 힙에 메모리를 할당할 수 없음을 나타냈지만, 어느 버전에서 삭제되었는지 알 수 없습니다.
norace
norace 지시문은 함수의 메모리 액세스가 더 이상 경합 분석이 필요하지 않음을 나타내며, 일반적으로 낮은 수준의 코드를 실행할 때 경합 분석을 수행하기에 적합하지 않은 경우 사용됩니다.
//go:norace
func low_level_code(ptr uintptr) uintptrTIP
일부 지시문은 runtime 패키지에서만 사용할 수 있도록 제한되어 있으며, 외부에서는 사용할 수 없습니다. 이들은 더 깊은 것과 관련이 있으며, Runtime-only compiler directives 에서 관련 소개를 볼 수 있습니다.
