саморазведение суслика

задняя часть Go

написать впереди

В повседневной работе или обучении разработчиков языка го наиболее часто используемые команды могут бытьgo build,go run,go install,go get... эти команды могут помочь нам компилировать программы, запускать программы, устанавливать программы и получать пакеты кода.Однако при выполнении этих команд задумывались ли вы о том, как наши исходные файлы организованы в процессе компиляции go? Что произошло при установке? И можно ли просто пойти и загрузить файлы пакетов, от которых мы зависим? Какие еще полезные команды есть в go? Эту статью можно назвать относительно базовой, и ее также можно использовать в качестве краткого справочного руководства по команде go, цель которой — помочь нам глубже понять go.

несколько концепций

  • Файл исходного кода команды: файл исходного кода основной функции, объявленный как принадлежащий пакету основного кода и не содержащий объявления параметра и объявления результата.Как правило, проект имеет только один файл исходного кода команды.
  • Файлы исходного кода библиотеки: обычные файлы исходного кода, которые не имеют характеристик исходного кода команды и существуют в пакете.
  • Файл исходного кода теста: файл исходного кода с суффиксом _test.go и должен содержать функции с префиксом имени Test или Benchmark.

gopath, наверное, самая знакомая вещь для каждого разработчика go, gopath — это наше рабочее пространство, черезgo envВы можете просмотреть наш gopath, напримерGOPATH="/Users/code/go", gopath — это наша рабочая область, которая обычно создается под gopathbin,src,pkgТри папки.

  • bin: исполняемый файл после установки будет помещен в каталог bin. Но в переменной среды go есть один, который называется GOBIN.По умолчанию GOBIN пуст, но когда мы установим GOBIN, GOPATH/bin будет бессмысленным, а исполняемый файл go install по умолчанию будет помещен в GOBIN.
export GOBIN=/tmp //声明GOBIN目录
go install $GOPATH/src/code //安装code程序
/tmp/code 发现程序已经被安装到了GOBIN下
  • src: все исходные файлы, которые мы написали, находятся в этой папке.
  • pkg: место, где хранится исходный файл библиотеки после установки пакета зависимостей, то есть файл архива (оканчивающийся на .a), то есть файл статической библиотеки, сгенерированный после компиляции программы.

Общие вспомогательные команды

В Go есть несколько вспомогательных команд, которые могут помочь нам лучше понять некоторые процессы выполнения go.Воплощением вспомогательных команд является go run/build..-x xx.go, -xявляется вспомогательной командой.-xМожет иметь следующие виды:

  • -a: Принудительно перестраивает все задействованные пакеты (включая пакеты из стандартной библиотеки), даже если они обновлены.
  • -n: Печатать другие команды, используемые во время сборки, но не выполнять их на самом деле.Вы можете наблюдать за процессом сборки через -n
  • -race: Используется для обнаружения проблем с гонкой данных, таких как одновременное чтение и запись карты...
  • -v: он используется для печати пакетов кода, участвующих в выполнении команды, включая пакеты кода, от которых мы зависим, и вы также можете увидеть пакеты кода, связанные с зависимыми пакетами кода.
  • -work: используется для печати имени временного рабочего каталога, сгенерированного и используемого при выполнении команды, и не удаляется после выполнения команды. Если этот флаг не установлен, временный рабочий каталог будет удален после выполнения команды.
  • -x: печатает все команды, используемые во время выполнения команды, и выполняет их одновременно.
  • -p n: количество параллелей для построения (n). По умолчанию количество параллелей совпадает с количеством процессоров.
  • -o: скомпилировать указанный вывод в файл.

Вспомогательный заказ ниши

  • -asmflags: за этим тегом могут следовать другие теги, такие как -D, -I, -S и т. д. Следующие флаги используются для управления поведением компилятора Go при компиляции файлов на языке ассемблера.
  • -buildmode: Укажите режим компиляции, например -buildmode=default, который в основном управляет компилятором для создания библиотек статических ссылок (т. е. и/или исполняемых файлов (файлы .exe в Windows).
  • -compiler: указывает имя используемого в данный момент компилятора, его значение может быть gc или gccgo. Среди них компилятор gc — это редактор, поставляемый с языком Go, а компилятор gccgo — это компилятор языка Go, предоставляемый GCC.
  • -gccgoflags: указывает список флагов, которые необходимо передать компилятору или компоновщику gccgo.
  • -gcflags: указывает список флагов, которые необходимо передать команде компиляции инструмента go.
  • -installsuffix: Этот флаг можно использовать, чтобы отделить текущий выходной каталог от выходного каталога компиляции по умолчанию. Значение этого тега используется в качестве суффикса имени родительского каталога результирующего файла. На самом деле, если используется флаг -race, этот флаг будет автоматически добавлен, и его значением будет race. Если мы используем флаг -race и -installsuffix одновременно, то _race будет добавлено к значению флага -installsuffix в качестве фактического используемого суффикса.
  • -ldflags: указывает список флагов, которые необходимо передать команде ссылки на инструмент go.
  • -linkshared: Для использования с -buildmode=shared. Последнее приведет к тому, что неосновной пакет кода в качестве цели компиляции будет объединен с файлом библиотеки динамической компоновки, в то время как первый будет связан поверх этого.
  • pkgdir: Можно указать каталог. Компилятор будет загружать архивы пакетов кода только из этого каталога и размещать в этом каталоге архивы пакетов кода, которые могут быть сгенерированы при компиляции.
  • -tags: указывает список тегов компиляции (также известных как ограничения компиляции), которые необходимо учитывать во время фактической компиляции.
  • -toolexec: позволяет нам настроить способ использования некоторых собственных инструментов языка Go (таких как vet, asm и т. д.) во время компиляции.
  • -mod: Использовать -mod [режим] режим, [режим] поддерживает только чтение, выпуск, поставщик, при выполнении go build -mod=vendor зависимости проекта будут помещены в каталог поставщика основного модуля при генерации исполняемого файла Down.
  • -modcacherw: Сохраняйте пакет загруженного мода для чтения и записи в кеше мода вместо того, чтобы делать его доступным только для чтения.
  • -trimpath: Удалить информацию о пути к исходному коду в двоичном файле. Например, когда наша программа паникует, она может распечатать путь к исходному коду соответствующей ошибки, который можно скрыть.

компилировать

go run

мы проходимgo run -n main.goВзгляните на процесс сборки

mkdir -p $WORK/b001/
cat >$WORK/b001/importcfg.link << 'EOF' # internal
packagefile command-line-arguments=/Users/gopher/Library/Caches/go-build/f5/f58206d3722b7787f6341e5013f38f3887e44138ffbdafbb07b67da377632762-d
packagefile code/utils=/Users/gopher/Library/Caches/go-build/89/8931b87411d98f32ea6222ad605f3367700be896828286782db3e51de73217ff-d
packagefile fmt=/usr/local/go/pkg/darwin_amd64/fmt.a
...
EOF
mkdir -p $WORK/b001/exe/
cd .
/usr/local/go/pkg/tool/darwin_amd64/link -o $WORK/b001/exe/main -importcfg $WORK/b001/importcfg.link -s -w -buildmode=exe -buildid=ttUV5epeZDG7q3yVlG2A/ek8iSJ8rjD-RiujnYKAd/hNomEMXuvdA3I1ks6XOE/ttUV5epeZDG7q3yVlG2A -extld=clang /Users/goper/Library/Caches/go-build/f5/f58206d3722b7787f6341e5013f38f3887e44138ffbdafbb07b67da377632762-d
$WORK/b001/exe/main
  1. Создайте временный каталог: $WORK/b001/
  2. Найдите информацию о пакете зависимостей: $WORK/b001/importcfg.link
  3. Создайте каталог exe: $WORK/b001/exe/
  4. Свяжите файл библиотеки (importcfg.link) по ссылке инструмента go tool, чтобы сгенерировать исполняемый файл $WORK/b001/exe/main.

пройти черезgo run -work main.go, давайте посмотрим на временную папку:

go run -work main.go
WORK=/var/folders/s4/2cpbmp4s1_j4y3zv2s08m9q40000gn/T/go-build281107053

Перейдите во временный каталог:

└── b001
    ├── exe
    │   └── main
    └── importcfg.link
  • exe: наш исполняемый файл.
  • importcfg.link: пакет, от которого зависит наша программа, и зависимый пакет связан через компоновщик.

По умолчанию временная папка удаляется после завершения команды go run.

image.png

go build

go buildИспользуется для компиляции нашей программы, скомпилированные файлы сохраняются в текущей папке по умолчанию, если указано-oЗатем вы можете перейти к указанному файлу.
мы проходимgo build -n main.goРассмотрим процесс сборки:

#
# command-line-arguments
#

mkdir -p $WORK/b001/
cat >$WORK/b001/_gomod_.go << 'EOF' # internal
package main
import _ "unsafe"
//go:linkname __debug_modinfo__ runtime.modinfo
var __debug_modinfo__ = "0w\xaf\f\x92t\b\x02A\xe1\xc1\a\xe6\xd6\x18\xe6path\tcommand-line-arguments\nmod\tcode\t(devel)\t\n\xf92C1\x86\x18 r\x00\x82B\x10A\x16\xd8\xf2"
        EOF
cat >$WORK/b001/importcfg << 'EOF' # internal
# import config
packagefile code/utils=/Users/sunkang/Library/Caches/go-build/89/8931b87411d98f32ea6222ad605f3367700be896828286782db3e51de73217ff-d
packagefile fmt=/usr/local/go/pkg/darwin_amd64/fmt.a
packagefile runtime=/Users/sunkang/Library/Caches/go-build/b4/b44856e241a6bb3baf596eb19e4566e956a490ef403c1ed31ba8f014542fcf81-d
EOF
cd /Users/gopher/go/src/code
/usr/local/go/pkg/tool/darwin_amd64/compile -o $WORK/b001/_pkg_.a -trimpath "$WORK/b001=>" -p main -lang=go1.15 -complete -buildid Fjkl2yr7MirhGqbO0lrl/Fjkl2yr7MirhGqbO0lrl -goversion go1.15.3 -D _/Users/sunkang/go/src/code -importcfg $WORK/b001/importcfg -pack -c=4 ./main.go $WORK/b001/_gomod_.go
/usr/local/go/pkg/tool/darwin_amd64/buildid -w $WORK/b001/_pkg_.a # internal
cat >$WORK/b001/importcfg.link << 'EOF' # internal
packagefile command-line-arguments=$WORK/b001/_pkg_.a
packagefile code/utils=/Users/sunkang/Library/Caches/go-build/89/8931b87411d98f32ea6222ad605f3367700be896828286782db3e51de73217ff-d
packagefile fmt=/usr/local/go/pkg/darwin_amd64/fmt.a
...
EOF
mkdir -p $WORK/b001/exe/
cd .
/usr/local/go/pkg/tool/darwin_amd64/link -o $WORK/b001/exe/a.out -importcfg $WORK/b001/importcfg.link -buildmode=exe -buildid=s0BcVGdGaAeuHGFL7teJ/Fjkl2yr7MirhGqbO0lrl/Fjkl2yr7MirhGqbO0lrl/s0BcVGdGaAeuHGFL7teJ -extld=clang $WORK/b001/_pkg_.a
/usr/local/go/pkg/tool/darwin_amd64/buildid -w $WORK/b001/exe/a.out # internal
mv $WORK/b001/exe/a.out main

общий процесс иgo runПочти единственная разница в том, что после компиляции и линковки сгенерированный исполняемый файл будет перемещен в текущую папку, вместо того, чтобы умирать вместе с временной папкой.

image.png

go install

go installОн используется для компиляции и установки указанного пакета кода и его зависимых пакетов.Если зависимые пакеты указанного пакета кода не были скомпилированы и установлены, сначала будут установлены зависимые пакеты. иgo buildразница в том,go installСкомпилированный инсталляционный пакет будет помещен в указанную папку. Установленный пакет кода будет находиться в каталоге pkg текущей рабочей области, т.е..aФайл архива, когда мы не устанавливаем GOBIN, установленный исходный файл команды будет храниться в каталоге bin текущей рабочей области, когда мы устанавливаем GOBIN, он будет помещен в GOBIN. Предположим, сейчас проект такой:

├── go.mod
├── main.go
└── utils
    └── utils.go

main.go — это наш входной файл, то есть исходный файл команды, а utils — наш пакет зависимостей, то есть исходный файл библиотеки. когда мы выполняем только в текущем каталогеgo install -n main.goЗадний:

mkdir -p $WORK/b001/
cat >$WORK/b001/importcfg.link << 'EOF' # internal
...
EOF
mkdir -p $WORK/b001/exe/
cd .
/usr/local/go/pkg/tool/darwin_amd64/link -o $WORK/b001/exe/a.out -importcfg $WORK/b001/importcfg.link -buildmode=exe -buildid=yfU8nbngCa6KbgUlJLKa/Fjkl2yr7MirhGqbO0lrl/khh18opCAdXA909bR95q/yfU8nbngCa6KbgUlJLKa -extld=clang /Users/sunkang/Library/Caches/go-build/ed/ed5868e69c99c66b8bf4b399e989ea410063b44143b546fd3f4a98f758d73a47-d
/usr/local/go/pkg/tool/darwin_amd64/buildid -w $WORK/b001/exe/a.out # internal
mkdir -p /Users/gopher/go/bin/
mv $WORK/b001/exe/a.out /Users/gopher/go/bin/main

Можно обнаружить, что последняя строка сgo buildРазница в том, что он перемещает исполняемый файл вGOPATH/binсередина.
Когда мы переключаемся на файл utils пакета зависимостей для выполнения go install -nЗадний:

mkdir -p $WORK/b001/
mkdir -p /Users/gopher/go/pkg/darwin_amd64/code/
mv /Users/gopher/Library/Caches/go-build/89/8931b87411d98f32ea6222ad605f3367700be896828286782db3e51de73217ff-d /Users/gopher/go/pkg/darwin_amd64/code/utils.a

Можно обнаружить, что пакет зависимостей будет установлен наGOPATH/pkgпод и по имени.aконечный архив.darwin_amd64да$GOOS_$GOARCHсборка операционной системы и архитектуры процессора,codeэто название нашего проекта.

/Users/gopher/go/pkg/darwin_amd64/code
└── utils.a

Итак, процесс установки, вероятно, выглядит следующим образом:

image.png

go get

С помощью команды go get мы можем загрузить и установить пакет зависимостей.Файл исходного кода, загруженный с помощью go get, будет помещен в первую рабочую область в GOPATH. Поскольку go поддерживает мод go в 1.11, когда мы открываем мод go, код, полученный через go get, будет загружен вGOPAT/pkg/mod, необязательные параметры поддерживаются после go get

  • -d: разрешить командной программе выполнять только действие загрузки, но не действие установки.
  • -u: разрешить команде использовать сеть для обновления существующих пакетов кода и их зависимостей. По умолчанию эта команда загружает из сети только те пакеты кода, которые не существуют локально, и не обновляет существующие пакеты кода.
  • -t: позволить командной программе одновременно загрузить и установить пакет кода, зависящий от тестового файла исходного кода в указанном пакете кода.
  • -insecure: позволяет командной программе использовать небезопасную схему (например, HTTP) для загрузки указанного пакета кода. Вы можете добавить этот флаг, если используете репозиторий кода (например, Gitlab внутри вашей компании), который не поддерживает HTTPS. Пожалуйста, используйте его, когда вы уверены, что это безопасно.
  • -v: отображает выполненную команду.

go mod

Go поддерживает режим go mod с 1.11. Теперь я считаю, что все в основном используют go mod. По сравнению с преимуществами вендора, использованиеgo modПосле этого ваш код может существовать где угодно.

go modСвязанные команды

  1. go mod init 模块名Инициализировать проект go
  2. go mod downloadЗагружать модули в локальный кеш, т.е.$GOPATH/pkg/mod/cache/downloadв, выполнитьgo mod download -jsonИнформация может быть выведена в формате json:
//go mod download -json
{
    "Path": "github.com/go-basic/uuid",
    "Version": "v1.0.0",
    "Info": "/Users/gopher/go/pkg/mod/cache/download/github.com/go-basic/uuid/@v/v1.0.0.info",
    "GoMod": "/Users/gopher/go/pkg/mod/cache/download/github.com/go-basic/uuid/@v/v1.0.0.mod",
    "Zip": "/Users/gopher/go/pkg/mod/cache/download/github.com/go-basic/uuid/@v/v1.0.0.zip",
    "Dir": "/Users/gopher/go/pkg/mod/github.com/go-basic/uuid@v1.0.0",
    "Sum": "h1:Faqtetcr8uwOzR2qp8RSpkahQiv4+BnJhrpuXPOo63M=",
    "GoModSum": "h1:yVtVnsXcmaLc9F4Zw7hTV7R0+vtuQw00mdXi+F6tqco="
}
  1. go mod edit

Отредактируйте файл go.mod.-json,-replace..., вы можете использовать помощьgo help mod edit, например, если вы хотите изменить пакет, вы можете использовать его напрямуюgo mod edit -replace=old[@v]=new[@v], обычно редактируют напрямуюgo.modфайл, эта команда мало используется.

  1. go mod graph

Печатать зависимые пакеты в текстовом режиме, например мой go.mod

module code
go 1.15
require (
   github.com/gin-gonic/gin v1.7.4 // indirect
   github.com/go-basic/uuid v1.0.0 // indirect
)

Выполнить в это времяgo mod graph

//go mod graph
code github.com/gin-gonic/gin@v1.7.4
code github.com/go-basic/uuid@v1.0.0
github.com/gin-gonic/gin@v1.7.4 github.com/gin-contrib/sse@v0.1.0
github.com/gin-gonic/gin@v1.7.4 github.com/go-playground/validator/v10@v10.4.1
github.com/gin-gonic/gin@v1.7.4 github.com/golang/protobuf@v1.3.3
github.com/gin-gonic/gin@v1.7.4 github.com/json-iterator/go@v1.1.9
github.com/gin-gonic/gin@v1.7.4 github.com/mattn/go-isatty@v0.0.12
github.com/gin-gonic/gin@v1.7.4 
...
golang.org/x/text@v0.3.2 golang.org/x/tools@v0.0.0-20180917221912-90fa682c2a6e

Обнаружено, что зависимости по-прежнему не видны, рекомендуется использовать их здесь.go get -u github.com/PaulXu-cn/go-mod-graph-chart/gmchartЭтот пакет, чтобы увидеть зависимости:

image.png

  1. go mod tidy

Добавьте отсутствующие или удаленные ненужные модули.
В настоящее время в моем go.mod есть пакет uuid, но мой код не ссылается на него.

module code

go 1.15

require github.com/go-basic/uuid v1.0.0 // indirect

воплощать в жизньgo mod tidy:

module code

go 1.15

обнаружит, что помогает мне удалить нежелательные пакеты.

6.go mod verify
Проверьте правильность зависимостей.
7. go mod why
Объясните, зачем нужны пакеты и модули, например, для реализации:go mod why github.com/go-basic/uuid, затем выведите:

# github.com/go-basic/uuid
code/utils
github.com/go-basic/uuid

мое пониманиеcode/utilsЭтот пакет полезенgithub.com/go-basic/uuid.

go.sum

go.sumРоль файла две:

  1. контрольная сумма, чтобы предотвратить подделку пакетов, контрольная сумма
  2. Запись записей обновлений пакетов

когда мыgo getКогда пакет загружен, он будет загружен в локальный$GOPATH/pkg/mod/cache/download, после загрузки появитсяvx.x.x.zipzip-пакет иvx.x.x.ziphashдокумент,vx.x.x.ziphashсодержаниеvx.x.x.zipПосле хеширования значения, например:h1:jwqTeEM3x6L9xDXrCxN0Hbg7vdGfPBOTIkr0+/LYZDA=%Возьмем в качестве примера пакет uuid: когда мыgo get github.com/go-basic/uuidПосле этого, помимо добавления в go.mod команды require, в go.sum будут записаны две записи:

github.com/go-basic/uuid v1.0.0 h1:Faqtetcr8uwOzR2qp8RSpkahQiv4+BnJhrpuXPOo63M=
github.com/go-basic/uuid v1.0.0/go.mod h1:yVtVnsXcmaLc9F4Zw7hTV7R0+vtuQw00mdXi+F6tqco=

Первый хеш — это хеш-значение zip-архива, о котором мы упоминали выше, а второй хэш — это если наш пакет зависимостей имеетgo.mod, то это значение хеш-функции этого go.mod. При подготовке к обновлению двух записей хеш-значений доgo.sumЧтобы обеспечить реальную надежность зависимого пакета, go передаст переменную окружения go после загрузки зависимого пакета.GOSUMDB="sum.golang.org"Сервер указал на проверку хеш-значения зависимого пакета.Если хеш-значение запроса отличается от локального хеш-значения, он откажется выполняться и не будет обновляться.go.sum.

go clean

  • -n: распечатайте команды очистки, которые необходимо выполнить, но не выполняйте их, чтобы было легко узнать, как работает нижний слой.
  • -i: очищает связанные установленные пакеты и исполняемые файлы. Мы можем объединить-nприди и посмотри-iКак это работает:
//go clean -i -n
cd /Users/gopher/go/job // 当前项目
rm -f job job.exe job.test job.test.exe main main.exe
rm -f /Users/gopher/go/bin/job

Сначала перейдите к нашему проекту, а затем попробуйте удалить некоторые скомпилированные файлы в текущем каталоге, такие как.exe,.testподождите, наконец, попробуйте удалить$GOPATH/bin/jobэто потому чтоgo installСгенерированные скомпилированные файлы.

  • -r: Циклическая очистка пакетов введена в импорт:
// go clean -r -n 
cd /Users/gopher/go/job
rm -f job job.exe job.test job.test.exe main main.exe
cd /usr/local/go/src/fmt
rm -f fmt.test fmt.test.exe
cd /usr/local/go/src/errors
rm -f errors.test errors.test.exe
cd /usr/local/go/src/internal/reflectlite
rm -f reflectlite.test reflectlite.test.exe
....

Проект задания зависит от многих пакетов, и эти зависимые пакеты также удалят некоторые скомпилированные файлы в текущем каталоге.

  • -x: Распечатайте подробную команду для выполнения, которая на самом деле-nРаспечатать версию исполнения.
  • -cache: удалить всеgo buildКэш команд.

go buildПроцесс создания некоторых кешей, эти кеши являются переменными среды, которые существуют в go.GOCACHE-cache in - удалить соответствующий кеш:

//go clean -n -cache
rm -r /Users/gopher/Library/Caches/go-build/00 
/Users/gopher/Library/Caches/go-build/01
/Users/gopher/Library/Caches/go-build/02 
/Users/gopher/Library/Caches/go-build/03 
/Users/gopher/Library/Caches/go-build/04 
...
rm -r /Users/gopher/Library/Caches/go-build/ff
  • -testcache: удалить все результаты тестов в текущем пакете.

когда мы используемgo test .При запуске тестового примера по определенному пути каждый тестовый файл по указанному пути будет скомпилирован и протестирован, а результаты теста будут кэшированы, чтобы избежать ненужных повторных тестов.

第一次
go test .
ok      job     0.431s
第二次
go test .
ok      job     (cached)

на этот раз черезgo clean -testcacheзаключается в удалении соответствующего тестового кеша.

go clean -testcache
go test .
ok      job     0.459s
  • -modcache: удалить файлы кеша в режиме go.mod.

Когда мы запускаем режим go.mod для организации нашего кода go, загруженные зависимости помещаются в$GOPATH/pkg/mod, go clean -modcache удалить$GOPATH/pkg/modВсе файлы ниже.

//go clean -n -modcache
rm -rf /Users/gopher/go/pkg/mod

Эпилог

Цель написания этой статьи в основном связана с недостатком знаний. Я использую go уже два года. Тем не менее, до сих пор есть ощущение двусмысленности в отношении некоторых команд go и процесса компиляции go. Как управлять пакетами кода мы зависим от того, что такое go.sum? Зачем вам нужен go.sum? Что случилось с процессом сборки? С другой стороны, в этой статье также перечислены команды, которых достаточно для базовой ежедневной разработки, так что, когда вам нужно найти команды, вам не нужно заходить на Baidu в Интернете, и вы можете использовать его в качестве быстрого справочника. руководство.
Возможно, наши повседневные рабочие задачи не требуют от нас понимания лежащих в их основе знаний, но сохранение любопытства — это также способ для программиста быстро совершенствоваться. Принципы и нижний слой — очень скучные вещи, и если их разжевать, то обнаружится, что многие проблемы уже решены. Это похоже на занятия боевыми искусствами. Люди с сильными боевыми искусствами обнаружат, что их внутренняя сила очень мощная. Когда внутренняя сила сильна, им будет быстрее изучать любые боевые искусства.