Menu

go run vs go build vs go install: Go kompilieren und ausführen

Was go run, go build und go install jeweils tun, wie Go das Binary benennt, wie du mit GOOS und GOARCH cross-kompilierst und welche Prüfungen mit go fmt und go vet vor dem Commit laufen sollten.

Diese Seite enthält ausführbare Editoren - bearbeiten, ausführen und Ausgabe sofort sehen.

go run kompiliert und startet ein Programm in einem Schritt und behält kein Binary. go build kompiliert und legt eine ausführbare Datei im aktuellen Verzeichnis ab. go install kompiliert und legt die ausführbare Datei in $HOME/go/bin ab. Alle drei kompilieren zu nativem Maschinencode; keiner davon interpretiert irgendetwas.

BefehlKompiliertFührt ausBehält ein BinaryWohin das Binary kommt
go run .jajaneintemporäres Verzeichnis, danach gelöscht
go buildjaneinjaaktuelles Verzeichnis (oder -o path)
go installjaneinja$GOBIN, sonst $GOPATH/bin

Das Programm unten wird in den Beispielen auf dieser Seite verwendet. Der Editor führt es so aus, wie go run es tun würde.

go run

go run nimmt ein Paket (meist ., das aktuelle Verzeichnis) oder eine Liste von .go-Dateien:

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

Alles nach dem Paket wird deinem Programm als Argumente übergeben:

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

Nimm lieber go run . statt go run main.go. Nennst du eine Datei, wird nur diese kompiliert, und sobald das Paket eine zweite Datei hat, werden die dort definierten Funktionen als undefined gemeldet. Die Seite zu Paketen und Imports erklärt diesen Fehler im Detail.

go run führt auch ein entferntes Programm in einer bestimmten Version aus, ohne es zu installieren. Das ist praktisch für Code-Generatoren:

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

go build

go build kompiliert das Paket im aktuellen Verzeichnis. Bei einem main-Paket schreibt es eine ausführbare Datei; bei einem Bibliothekspaket kompiliert es, meldet Fehler und verwirft das Ergebnis.

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

Der Name des Binarys folgt diesen Regeln:

Du führst ausName des Binarys
go build im Modul example.com/hellohello
go build ./cmd/serverserver
go build main.gomain (nach der ersten Datei benannt)
go build -o bin/app .bin/app
eine der obigen Formen mit GOOS=windowsderselbe Name plus .exe

Zwei weitere Formen, die du ständig brauchen wirst:

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

./... bedeutet „dieses Verzeichnis und jedes Verzeichnis darunter“. go build ./... mit mehreren main-Paketen schreibt keine Binaries; es ist eine schnelle Prüfung, ob alles kompiliert.

Nützliche Build-Flags

FlagWas es tut
-o nameAusgabedatei oder Verzeichnis
-vgibt Paketnamen beim Kompilieren aus
-racebaut mit dem Data Race Detector (langsamer, größeres Binary; für Tests)
-trimpathentfernt lokale Dateisystempfade aus dem Binary, für reproduzierbare Builds
-ldflags "-s -w"entfernt Symboltabelle und DWARF-Debuginfos, das Binary wird kleiner
-ldflags "-X main.version=1.4.0"setzt beim Linken eine String-Variable
-tags namebezieht Dateien ein, die durch ein Constraint //go:build name geschützt sind

Mit dem Flag -X stempeln die meisten Go-Projekte eine Version in das Binary. Es funktioniert nur bei string-Variablen auf Paketebene (nicht bei Konstanten):

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

Das Binary speichert außerdem seine Modulversionen und seit Go 1.18 den VCS-Commit, aus dem es gebaut wurde. go version -m ./app gibt sie aus, und ein Programm kann sie mit runtime/debug.ReadBuildInfo lesen.

go install

go install baut genau wie go build und verschiebt die ausführbare Datei dann nach $GOBIN, oder nach $GOPATH/bin, wenn GOBIN nicht gesetzt ist (standardmäßig $HOME/go/bin):

go install .
go env GOPATH

Am häufigsten installierst du damit in Go geschriebene Tools. Mit @version installiert es ein Programm, ohne deine go.mod anzufassen:

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

Findet die Shell ein Tool danach nicht, ist $HOME/go/bin nicht in deinem PATH. Füg export PATH=$PATH:$(go env GOPATH)/bin in dein Shell-Profil ein.

Cross-Kompilierung mit GOOS und GOARCH

Go kann auf jedem Rechner für ein anderes Betriebssystem oder eine andere CPU bauen, ohne zusätzliche Toolchain. Setz für den Build-Befehl zwei Umgebungsvariablen:

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 werden Umgebungsvariablen anders gesetzt:

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

Die häufigsten Paare:

GOOSGOARCHZiel
linuxamd64die meisten Server und Container
linuxarm64AWS Graviton, Raspberry Pi mit 64-Bit-Betriebssystem
darwinarm64Macs mit Apple Silicon
darwinamd64Macs mit Intel
windowsamd6464-Bit-Windows
jswasmWebAssembly im Browser

go tool dist list gibt jedes unterstützte Paar aus (48 in Go 1.24).

So einfach ist Cross-Kompilierung nur bei reinem Go-Code. Ein Paket, das cgo nutzt (C-Code, zum Beispiel manche SQLite-Treiber), braucht einen C-Cross-Compiler für das Ziel. Beim Cross-Kompilieren ist cgo standardmäßig deaktiviert, und CGO_ENABLED=0 explizit zu setzen liefert dir außerdem ein vollständig statisches Linux-Binary. Genau das willst du in einem minimalen Container-Image, etwa scratch oder Distroless.

go fmt und go vet

Zwei Prüfungen gehören in jeden Workflow und in die CI.

go fmt schreibt Dateien im einen offiziellen Stil um: Tabs, ausgerichtete Felder, vereinheitlichte Abstände. Es ist ein Wrapper um gofmt -l -w:

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

go vet meldet Code, der kompiliert, aber fast sicher falsch ist. Nicht passende Printf-Formate sind der klassische Fall:

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

Das Programm kompiliert und gibt %!s(int=3) items aus, genau die Art Bug, für die es vet gibt. Weitere Prüfungen von vet betreffen das Kopieren eines sync.Mutex als Wert, unerreichbaren Code, Struct Tags mit fehlerhafter Syntax und eine context.CancelFunc, die nie aufgerufen wird. go test führt automatisch einen Teil davon aus; go build keine.

Weitere go-Unterbefehle

BefehlZweck
go test ./...Tests ausführen
go mod tidyfehlende Abhängigkeiten hinzufügen, ungenutzte entfernen
go get pkg@versioneine Abhängigkeit hinzufügen oder ändern
go clean -cacheden Build-Cache leeren
go envdie Konfiguration von Go ausgeben
go doc fmt.PrintlnDokumentation im Terminal anzeigen
go list -m alljedes Modul im Build auflisten

Warum Builds beim zweiten Mal schnell sind

Go speichert kompilierte Pakete im Build-Cache (go env GOCACHE). Ein erneuter Build kompiliert nur Pakete neu, deren Quelltext oder Abhängigkeiten sich geändert haben, also startet go run . bei einem unveränderten Projekt fast sofort. Verhält sich ein Build nach einem Wechsel der Go-Version oder von Umgebungsvariablen seltsam, leert go clean -cache den Cache; das solltest du selten brauchen.

Häufig gestellte Fragen

Was ist der Unterschied zwischen go run und go build?

go run kompiliert das Programm in ein temporäres Verzeichnis, führt es aus und wirft das Binary weg. go build kompiliert das Programm und schreibt das Binary ins aktuelle Verzeichnis, damit du es erneut ausführen oder woandershin kopieren kannst. Nimm go run während der Entwicklung und go build, wenn du die ausführbare Datei brauchst.

Wie lege ich den Namen der Ausgabedatei von go build fest?

Mit -o: go build -o myapp . schreibt myapp (unter Windows schreibst du -o myapp.exe selbst). Ohne -o benennt go build das Binary nach dem letzten Element des Importpfads des Pakets oder, wenn du .go-Dateien übergibst, nach der ersten Datei und hängt beim Build für Windows .exe an.

Wie kompiliere ich Go für Linux oder Windows über Plattformgrenzen hinweg?

Setz GOOS und GOARCH für den Build: GOOS=linux GOARCH=amd64 go build -o app-linux . oder GOOS=windows GOARCH=amd64 go build . (das erzeugt eine .exe). Für reinen Go-Code ist keine zusätzliche Toolchain nötig. go tool dist list gibt jedes unterstützte Paar aus.

Wohin legt go install das Binary?

In $GOBIN, wenn es gesetzt ist, sonst in $GOPATH/bin, standardmäßig $HOME/go/bin. Füg dieses Verzeichnis deinem PATH hinzu, um installierte Tools per Namen aufzurufen. go install example.com/tool@latest installiert ein Tool, ohne es deinem Modul hinzuzufügen.

Führt go build go vet aus?

Nein. go build kompiliert nur. go test führt automatisch einen Teil der Prüfungen von go vet aus, aber für den vollen Umfang rufst du go vet ./... selbst auf, typischerweise in der CI neben gofmt -l ..

Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S