Menu

go run, go build i go install: kompilacja i uruchamianie Go

Co robią go run, go build i go install, jak Go nazywa plik wykonywalny, jak kompilować na inne platformy przez GOOS i GOARCH oraz jakie sprawdzenia go fmt i go vet uruchomić przed commitem.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

go run kompiluje i uruchamia program w jednym kroku i nie zostawia pliku wykonywalnego. go build kompiluje i zostawia plik wykonywalny w bieżącym katalogu. go install kompiluje i umieszcza plik wykonywalny w $HOME/go/bin. Wszystkie trzy kompilują do natywnego kodu maszynowego; żadna z nich niczego nie interpretuje.

KomendaKompilujeUruchamiaZostawia plik wykonywalnyDokąd trafia plik wykonywalny
go run .taktakniekatalog tymczasowy, potem usuwany
go buildtaknietakbieżący katalog (lub -o path)
go installtaknietak$GOBIN, w przeciwnym razie $GOPATH/bin

Poniższy program jest używany w przykładach na tej stronie. Edytor uruchamia go tak, jak zrobiłoby to go run.

go run

go run przyjmuje pakiet (zwykle ., czyli bieżący katalog) albo listę plików .go:

go run .
go run main.go
go run ./cmd/server

Wszystko po pakiecie trafia do programu jako argumenty:

go run . --port 8080 verbose
version: dev
built for: linux/amd64
args: [--port 8080 verbose]

Wybieraj go run . zamiast go run main.go. Podanie nazwy pliku kompiluje tylko ten plik, więc gdy tylko pakiet ma drugi plik, zdefiniowane w nim funkcje są zgłaszane jako undefined. Strona o pakietach i importach szczegółowo omawia ten błąd.

go run potrafi też uruchomić zdalny program w konkretnej wersji bez instalowania go, co przydaje się przy generatorach kodu:

go run golang.org/x/tools/cmd/stringer@v0.30.0 -type=Color

go build

go build kompiluje pakiet z bieżącego katalogu. Dla pakietu main zapisuje plik wykonywalny; dla pakietu bibliotecznego kompiluje go, zgłasza błędy i odrzuca wynik.

go mod init example.com/hello
go build
ls
go.mod  hello  main.go

Nazwa pliku wykonywalnego wynika z tych reguł:

UruchamiaszNazwa pliku wykonywalnego
go build w module example.com/hellohello
go build ./cmd/serverserver
go build main.gomain (od nazwy pierwszego pliku)
go build -o bin/app .bin/app
dowolne z powyższych z GOOS=windowsta sama nazwa plus .exe

Dwie kolejne formy, których będziesz używać bez przerwy:

go build ./...      # compile every package in the module
go vet ./...        # static checks, covered below

./... oznacza "ten katalog i każdy katalog pod nim". go build ./... z kilkoma pakietami main nie zapisuje żadnych plików wykonywalnych; to szybkie sprawdzenie, czy wszystko się kompiluje.

Przydatne flagi budowania

FlagaCo robi
-o nameplik lub katalog wyjściowy
-vwypisuje nazwy pakietów podczas kompilacji
-racebuduje z detektorem wyścigów danych (wolniej, większy plik; do testów)
-trimpathusuwa lokalne ścieżki systemu plików z pliku wykonywalnego, dla powtarzalnych buildów
-ldflags "-s -w"usuwa tablicę symboli i informacje debugowania DWARF, co zmniejsza plik
-ldflags "-X main.version=1.4.0"ustawia zmienną typu string podczas linkowania
-tags namedołącza pliki chronione ograniczeniem //go:build name

Flaga -X to sposób, w jaki większość projektów Go wpisuje wersję do pliku wykonywalnego. Działa tylko na zmiennych string na poziomie pakietu (nie na stałych):

go build -o app -ldflags "-X main.version=1.4.0" .
./app
version: 1.4.0
built for: linux/amd64
args: []

Plik wykonywalny zapisuje też wersje swoich modułów, a od Go 1.18 także commit VCS, z którego został zbudowany. go version -m ./app je wypisuje, a program może je odczytać przez runtime/debug.ReadBuildInfo.

go install

go install buduje dokładnie tak jak go build, a potem przenosi plik wykonywalny do $GOBIN albo do $GOPATH/bin, gdy GOBIN nie jest ustawione (domyślnie $HOME/go/bin):

go install .
go env GOPATH

Najczęściej służy do instalowania narzędzi napisanych w Go. Z @version instaluje program bez ruszania twojego go.mod:

go install golang.org/x/tools/gopls@latest
go install honnef.co/go/tools/cmd/staticcheck@latest

Jeśli potem powłoka nie może znaleźć narzędzia, $HOME/go/bin nie jest w twoim PATH. Dodaj export PATH=$PATH:$(go env GOPATH)/bin do profilu powłoki.

Kompilacja skrośna przez GOOS i GOARCH

Go potrafi budować dla innego systemu operacyjnego lub procesora z dowolnej maszyny, bez dodatkowego zestawu narzędzi. Ustaw dwie zmienne środowiskowe dla komendy budowania:

GOOS=linux GOARCH=amd64 go build -o app-linux-amd64 .
GOOS=linux GOARCH=arm64 go build -o app-linux-arm64 .
GOOS=darwin GOARCH=arm64 go build -o app-macos .
GOOS=windows GOARCH=amd64 go build -o app.exe .

W PowerShellu zmienne środowiskowe ustawia się inaczej:

$env:GOOS = "linux"; $env:GOARCH = "amd64"; go build -o app-linux .

Najczęstsze pary:

GOOSGOARCHCel
linuxamd64większość serwerów i kontenerów
linuxarm64AWS Graviton, Raspberry Pi z 64-bitowym systemem
darwinarm64Maki z Apple Silicon
darwinamd64Maki z procesorem Intel
windowsamd6464-bitowy Windows
jswasmWebAssembly w przeglądarce

go tool dist list wypisuje każdą obsługiwaną parę (48 w Go 1.24).

Kompilacja skrośna jest tak prosta tylko dla czystego kodu Go. Pakiet używający cgo (kodu w C, na przykład niektóre sterowniki SQLite) potrzebuje kompilatora skrośnego C dla platformy docelowej. Przy kompilacji skrośnej cgo jest domyślnie wyłączone, a jawne ustawienie CGO_ENABLED=0 daje też w pełni statyczny plik wykonywalny dla Linuksa, czyli to, czego potrzebujesz w minimalnym obrazie kontenera scratch lub distroless.

go fmt i go vet

Dwa sprawdzenia powinny być w każdym procesie pracy i w CI.

go fmt przepisuje pliki w jednym oficjalnym stylu: tabulatory, wyrównane pola, ujednolicone odstępy. To nakładka na gofmt -l -w:

go fmt ./...
gofmt -l .     # list files that are not formatted; empty output means clean

go vet zgłasza kod, który się kompiluje, ale prawie na pewno jest błędny. Klasycznym przykładem są niezgodności formatów Printf:

package main

import "fmt"

func main() {
	count := 3
	fmt.Printf("%s items\n", count)
}
go vet ./...
# example.com/hello
# [example.com/hello]
./main.go:7:2: fmt.Printf format %s has arg count of wrong type int

Program się kompiluje i wypisuje %!s(int=3) items, a to dokładnie ten rodzaj błędu, do którego wyłapywania istnieje vet. Inne sprawdzenia vet obejmują kopiowanie sync.Mutex przez wartość, nieosiągalny kod, tagi struktur ze złą składnią i context.CancelFunc, która nigdy nie zostaje wywołana. go test automatycznie uruchamia część tych sprawdzeń; go build nie uruchamia żadnego.

Inne podkomendy go

KomendaCel
go test ./...uruchamia testy
go mod tidydodaje brakujące i usuwa nieużywane zależności
go get pkg@versiondodaje lub zmienia zależność
go clean -cacheczyści cache budowania
go envwypisuje konfigurację Go
go doc fmt.Printlnpokazuje dokumentację w terminalu
go list -m allwymienia każdy moduł w buildzie

Dlaczego drugi build jest szybki

Go przechowuje skompilowane pakiety w cache budowania (go env GOCACHE). Ponowny build kompiluje tylko pakiety, których kod źródłowy lub zależności się zmieniły, więc go run . w niezmienionym projekcie startuje niemal natychmiast. Jeśli po zmianie wersji Go lub zmiennych środowiskowych build zachowuje się dziwnie, go clean -cache czyści cache; rzadko powinno to być potrzebne.

Najczęściej zadawane pytania

Czym różni się go run od go build?

go run kompiluje program do katalogu tymczasowego, uruchamia go i wyrzuca plik wykonywalny. go build kompiluje program i zapisuje plik wykonywalny w bieżącym katalogu, żeby można go było uruchomić ponownie albo skopiować gdzie indziej. Używaj go run podczas pracy nad kodem, a go build, gdy potrzebujesz pliku wykonywalnego.

Jak ustawić nazwę pliku wynikowego go build?

Użyj -o: go build -o myapp . zapisuje myapp (w Windows samodzielnie dopisz rozszerzenie: -o myapp.exe). Bez -o go build nazywa plik wykonywalny od ostatniego elementu ścieżki importu pakietu albo od pierwszego pliku, gdy podajesz pliki .go, i dodaje .exe przy budowaniu dla Windows.

Jak skompilować Go dla Linuksa albo Windows z innego systemu?

Ustaw GOOS i GOARCH dla buildu: GOOS=linux GOARCH=amd64 go build -o app-linux . albo GOOS=windows GOARCH=amd64 go build . (co daje plik .exe). Dla czystego kodu Go nie potrzeba żadnego dodatkowego zestawu narzędzi. go tool dist list wypisuje każdą obsługiwaną parę.

Gdzie go install umieszcza plik wykonywalny?

W $GOBIN, jeśli jest ustawione, a w przeciwnym razie w $GOPATH/bin, czyli domyślnie w $HOME/go/bin. Dodaj ten katalog do PATH, żeby uruchamiać zainstalowane narzędzia po nazwie. go install example.com/tool@latest instaluje narzędzie bez dodawania go do twojego modułu.

Czy go build uruchamia go vet?

Nie. go build tylko kompiluje. go test automatycznie uruchamia część sprawdzeń go vet, ale pełny zestaw uruchamiasz przez go vet ./..., zwykle w CI obok gofmt -l ..

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ