Menu

go run, go build e go install a confronto: compilare ed eseguire Go

Cosa fanno go run, go build e go install, come Go assegna il nome al binario, come fare cross-compilazione con GOOS e GOARCH e i controlli go fmt e go vet da eseguire prima di un commit.

Questa pagina include editor eseguibili: modifica, esegui e vedi subito l'output.

go run compila ed esegue un programma in un solo passaggio e non conserva il binario. go build compila e lascia un eseguibile nella directory corrente. go install compila e mette l'eseguibile in $HOME/go/bin. Tutti e tre compilano in codice macchina nativo; nessuno di loro interpreta nulla.

ComandoCompilaEsegueConserva un binarioDove finisce il binario
go run .sìsìnodirectory temporanea, eliminata dopo
go buildsìnosìdirectory corrente (o -o path)
go installsìnosì$GOBIN, altrimenti $GOPATH/bin

Il programma qui sotto è quello usato negli esempi di questa pagina. L'editor lo esegue come farebbe go run.

go run

go run riceve un package (di solito ., la directory corrente) o una lista di file .go:

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

Tutto ciò che segue il package viene passato al tuo programma come argomenti:

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

Preferisci go run . a go run main.go. Indicare un file compila solo quel file, quindi appena il package ha un secondo file, le funzioni definite lì vengono segnalate come undefined. La pagina su package e import tratta quell'errore in dettaglio.

go run esegue anche un programma remoto a una versione specifica senza installarlo, il che è comodo per i generatori di codice:

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

go build

go build compila il package nella directory corrente. Per un package main scrive un eseguibile; per un package di libreria compila, segnala gli errori e scarta il risultato.

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

Il nome del binario segue queste regole:

EseguiNome del binario
go build nel modulo example.com/hellohello
go build ./cmd/serverserver
go build main.gomain (dal nome del primo file)
go build -o bin/app .bin/app
uno qualsiasi dei precedenti con GOOS=windowslo stesso nome più .exe

Altre due forme che userai di continuo:

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

./... significa "questa directory e tutte le directory sottostanti". go build ./... con più package main non scrive nessun binario; è un rapido controllo per verificare che tutto compili.

Flag di build utili

FlagCosa fa
-o namefile o directory di output
-vstampa i nomi dei package mentre vengono compilati
-racecompila con il rilevatore di data race (binario più lento e più grande; per i test)
-trimpathrimuove dal binario i percorsi del file system locale, per build riproducibili
-ldflags "-s -w"elimina la tabella dei simboli e le informazioni di debug DWARF, rendendo il binario più piccolo
-ldflags "-X main.version=1.4.0"imposta una variabile stringa in fase di link
-tags nameinclude i file protetti da un vincolo //go:build name

Il flag -X è il modo in cui la maggior parte dei progetti Go imprime una versione nel binario. Funziona solo sulle variabili string a livello di package (non sulle costanti):

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

Il binario registra anche le versioni dei suoi moduli e, da Go 1.18, il commit VCS da cui è stato compilato. go version -m ./app li stampa, e un programma può leggerli con runtime/debug.ReadBuildInfo.

go install

go install compila esattamente come go build e poi sposta l'eseguibile in $GOBIN, o in $GOPATH/bin quando GOBIN non è impostata (per impostazione predefinita $HOME/go/bin):

go install .
go env GOPATH

L'uso più comune è installare strumenti scritti in Go. Con @version installa un programma senza toccare il tuo go.mod:

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

Se dopo la shell non trova uno strumento, $HOME/go/bin non è nel tuo PATH. Aggiungi export PATH=$PATH:$(go env GOPATH)/bin al profilo della tua shell.

Cross-compilazione con GOOS e GOARCH

Go può compilare per un altro sistema operativo o un'altra CPU da qualsiasi macchina, senza toolchain aggiuntive. Imposta due variabili d'ambiente per il comando di build:

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 .

In PowerShell, le variabili d'ambiente si impostano in modo diverso:

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

Le coppie più comuni:

GOOSGOARCHDestinazione
linuxamd64la maggior parte dei server e dei container
linuxarm64AWS Graviton, Raspberry Pi con un sistema operativo a 64 bit
darwinarm64Mac con Apple Silicon
darwinamd64Mac Intel
windowsamd64Windows a 64 bit
jswasmWebAssembly in un browser

go tool dist list stampa ogni coppia supportata (48 in Go 1.24).

La cross-compilazione è così semplice solo per il codice Go puro. Un package che usa cgo (codice C, per esempio alcuni driver SQLite) ha bisogno di un cross-compilatore C per la destinazione. Durante la cross-compilazione cgo è disattivato per impostazione predefinita, e impostare esplicitamente CGO_ENABLED=0 ti dà anche un binario Linux completamente statico, che è ciò che vuoi in un'immagine di container minimale scratch o distroless.

go fmt e go vet

Due controlli dovrebbero far parte di ogni flusso di lavoro, e della CI.

go fmt riscrive i file nell'unico stile ufficiale: tabulazioni, campi allineati, spaziatura normalizzata. È un wrapper di gofmt -l -w:

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

go vet segnala il codice che compila ma è quasi certamente sbagliato. Le incongruenze nei formati di Printf sono il caso classico:

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

Il programma compila e stampa %!s(int=3) items, che è esattamente il tipo di bug che vet esiste per intercettare. Altri controlli di vet riguardano la copia per valore di un sync.Mutex, il codice irraggiungibile, i tag delle struct con sintassi errata e un context.CancelFunc che non viene mai chiamato. go test esegue automaticamente una parte di questi controlli; go build non ne esegue nessuno.

Altri sottocomandi di go

ComandoScopo
go test ./...esegue i test
go mod tidyaggiunge le dipendenze mancanti e rimuove quelle inutilizzate
go get pkg@versionaggiunge o modifica una dipendenza
go clean -cachesvuota la cache di build
go envstampa la configurazione di Go
go doc fmt.Printlnmostra la documentazione nel terminale
go list -m allelenca ogni modulo della build

Perché la seconda build è veloce

Go mette in cache i package compilati nella cache di build (go env GOCACHE). Una nuova build ricompila solo i package il cui sorgente o le cui dipendenze sono cambiati, quindi go run . su un progetto invariato parte quasi all'istante. Se una build si comporta in modo strano dopo aver cambiato versione di Go o variabili d'ambiente, go clean -cache la svuota; dovrebbe servirti di rado.

Domande frequenti

Qual è la differenza tra go run e go build?

go run compila il programma in una directory temporanea, lo esegue e butta via il binario. go build compila il programma e scrive il binario nella directory corrente, così puoi eseguirlo di nuovo o copiarlo altrove. Usa go run durante lo sviluppo e go build quando ti serve l'eseguibile.

Come imposto il nome del file di output di go build?

Usa -o: go build -o myapp . scrive myapp (su Windows, scrivi tu -o myapp.exe). Senza -o, go build chiama il binario come l'ultimo elemento del percorso di import del package, o come il primo file quando passi dei file .go, e aggiunge .exe quando compili per Windows.

Come faccio la cross-compilazione di Go per Linux o Windows?

Imposta GOOS e GOARCH per la build: GOOS=linux GOARCH=amd64 go build -o app-linux . oppure GOOS=windows GOARCH=amd64 go build . (che produce un .exe). Per il codice Go puro non serve nessuna toolchain aggiuntiva. go tool dist list stampa ogni coppia supportata.

Dove mette il binario go install?

In $GOBIN se è impostata, altrimenti in $GOPATH/bin, che per impostazione predefinita è $HOME/go/bin. Aggiungi quella directory al tuo PATH per eseguire gli strumenti installati per nome. go install example.com/tool@latest installa uno strumento senza aggiungerlo al tuo modulo.

go build esegue go vet?

No. go build si limita a compilare. go test esegue automaticamente una parte dei controlli di go vet, ma per l'insieme completo esegui tu go vet ./..., di solito in CI accanto a gofmt -l ..

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA