Go programını çalıştırılabilir bir dosyaya dönüştürmek için modül dizininde go build yazarsınız; çıktı dosyasının adını ve yerini -o ile belirlersiniz. Başka bir işletim sistemi veya işlemci için derlemek (çapraz derleme) ek bir araç gerektirmez: hedefi GOOS ve GOARCH ortam değişkenleriyle verirsiniz, ör. GOOS=linux GOARCH=arm64 go build -o uygulama. Sürüm numarası gibi değerleri derleme anında koda yazmak için -ldflags "-X main.surum=1.4.0", belirli dosyaları yalnızca belirli koşullarda derlemek için de //go:build satırları kullanılır.

Bu yazıda go help build, go help install ve go help buildconstraint çıktılarını, go.dev'deki derleme ve kurulum öğreticisini ve runtime/debug paket belgesini temel alıyoruz. Örnekler Windows/amd64 üzerinde Go 1.27.3 ile çalıştırıldı; Linux için üretilen ikili dosyaları bu makinede çalıştıramadığımız için onları go version -m ile inceledik. Sunucuya dağıtım (Docker, systemd vb.) bu yazının kapsamı dışında; ilgili genel rehberlere yazının sonunda bağlantı veriyoruz. Önceki adımlar için Go öğrenme rehberi ve Go kurulumu ve ilk program sayfalarına bakabilirsiniz.

go run, go build ve go install farkı

go run, go build ve go install farkı: go run ., go build, go install

Üç komut da aynı derleyiciyi kullanır, ama sonuçla ne yaptıkları farklıdır. Derleme öğreticisine göre go run sık değişiklik yaparken programı derleyip çalıştırmanın kısayoludur ve kalıcı bir ikili dosya bırakmaz. go build paketleri bağımlılıklarıyla birlikte derler ama sonucu kurmaz. go install ise derleyip ikili dosyayı kurulum dizinine koyar.

Komutİkili dosyaNereye
go run .Kalıcı dosya bırakmazDerleyip hemen çalıştırır
go buildÜretir (main paket için)Bulunduğunuz dizine ya da -o ile verilen yere
go installÜretirGOBIN, yoksa GOPATH/bin, o da yoksa HOME/go/bin

Örnek programımız iki paket düzeyi değişken ve hedef platformu yazdırıyor:

go
package main

import (
	"fmt"
	"runtime"
)

var (
	surum = "geliştirme"
	tarih = "bilinmiyor"
)

func main() {
	fmt.Printf("surum=%s tarih=%s\n", surum, tarih)
	fmt.Printf("hedef=%s/%s\n", runtime.GOOS, runtime.GOARCH)
}
bash
$ go run .
surum=geliştirme tarih=bilinmiyor
hedef=windows/amd64
$ go build
$ ls
go.mod
main.go
surum.exe
$ go build -o bin/ .
$ ls bin
surum.exe

go help build çıktısına göre tek bir main paketi derlendiğinde ikili dosya, import yolunun son bileşeninin adını alır; Windows için yazılırken .exe eklenir. Bu yüzden example.com/surum modülü surum.exe üretti. Son bileşen v2 gibi bir büyük sürüm ekiyse o atlanır: example.com/foo/v2 için çıktı foo olur. -o değeri var olan bir dizinse ya da eğik çizgiyle bitiyorsa ikili dosya o dizine yazılır. Birden çok paket ya da main olmayan tek bir paket derlediğinizde go build sonucu atar; bu kullanım yalnızca paketlerin derlenebildiğini denetler. _test.go dosyaları derlemeye hiç girmez.

go install ikili dosyayı GOBIN dizinine koyar. Bu değişken boşsa GOPATH listesindeki ilk dizinin bin alt dizini, GOPATH da ayarlı değilse $HOME/go/bin (Windows'ta %USERPROFILE%\go\bin) kullanılır. Hedef yolu görmek için go list -f '{{.Target}}' . çalıştırabilirsiniz. Kalıcı ayar yapmadan, yalnızca tek bir komut için GOBIN verdiğimizde dosya o dizine kuruldu:

bash
$ GOBIN=$PWD/../gobin go install .
$ ls ../gobin
surum.exe

Komut @latest ya da @v1.0.0 gibi bir sürüm ekiyle çağrılırsa, bulunduğunuz dizindeki go.mod dosyasını yok sayarak o sürümü kurar. Böylece bir aracı projenizin bağımlılıklarını değiştirmeden kurabilirsiniz. Bu kullanımın kuralları go help install içinde listelenir: tüm argümanlar aynı modülün aynı sürümündeki main paketlerini göstermelidir. Modül bağımlılıklarının go get ile yönetimi Go modül yönetimi yazısında.

Çapraz derleme: GOOS ve GOARCH

Go, hedef platformu iki ortam değişkeninden okur: GOOS hedef işletim sistemi, GOARCH hedef mimaridir. Kaynaktan kurulum belgesi önemli bir noktanın altını çizer: bu değişkenler üzerinde çalıştığınız ortamı değil hedef ortamı tanımlar, yani aslında her zaman çapraz derleme yapıyorsunuzdur. Linux/arm64 için derleyip sonucu inceleyelim:

bash
$ GOOS=linux GOARCH=arm64 go build -o bin/surum-linux-arm64 .
$ go version -m bin/surum-linux-arm64
bin/surum-linux-arm64: go1.27.3
	path	example.com/surum
	mod	example.com/surum	(devel)	
	build	-buildmode=exe
	build	-compiler=gc
	build	CGO_ENABLED=0
	build	GOARCH=arm64
	build	GOOS=linux
	build	GOARM64=v8.0

go version -m, ikili dosyaya gömülmüş derleme bilgisini okur: hangi Go sürümüyle, hangi modülden ve hangi ayarlarla derlendiğini. Bu çıktıdan dosyanın Linux/arm64 için üretildiğini ve cgo kullanılmadığını görüyoruz. Desteklenen tüm hedefleri go tool dist list yazdırır; Go 1.27.3'te liste 47 satırdı ve aralarında şunlar var:

text
aix/ppc64 android/arm64 darwin/amd64 darwin/arm64 freebsd/amd64 ios/arm64 js/wasm
linux/386 linux/amd64 linux/arm linux/arm64 linux/loong64 linux/ppc64le linux/riscv64
linux/s390x netbsd/amd64 openbsd/amd64 plan9/amd64 solaris/amd64 wasip1/wasm
windows/386 windows/amd64 windows/arm64 (seçme)
HedefKomut
Linux sunucu (x86-64)GOOS=linux GOARCH=amd64 go build
Linux ARM64 sunucuGOOS=linux GOARCH=arm64 go build
macOS (arm64)GOOS=darwin GOARCH=arm64 go build
WindowsGOOS=windows GOARCH=amd64 go build
WebAssembly (WASI)GOOS=wasip1 GOARCH=wasm go build

Yukarıdaki komutlar Linux ve macOS kabuklarının (ve Windows'taki Git Bash'in) sözdizimidir; değişken yalnızca o komut için geçerli olur. PowerShell'de önce $env:GOOS="linux" ve $env:GOARCH="arm64" atanır, sonra go build çalıştırılır. Bazı mimarilerin ek ayarları vardır: GOAMD64 (v1, v2, v3), GOARM ve GOARM64 gibi değişkenler hedef işlemcinin özellik düzeyini seçer; yukarıdaki çıktıda varsayılan GOARM64=v8.0 görünüyor. Go 1.27 sürüm notları da bu konuda bir değişiklik içeriyor: macOS hedefi için artık macOS 13 Ventura veya üstü gerekiyor ve büyük endian PowerPC Linux (linux/ppc64) ikilileri ELFv2 ABI ile üretiliyor.

go install çapraz derlenmiş ikilileri, belgeye göre kurulum dizininin altındaki $GOOS_$GOARCH alt dizinine koyar. GOBIN ayarlıyken bu mümkün olmadığı için komut reddedilir:

bash
$ GOOS=linux GOBIN=$PWD/../gobin go install .
go: cannot install cross-compiled binaries when GOBIN is set

cgo ve statik ikili dosyalar

Go kodunuz C kütüphanelerini cgo ile çağırıyorsa, çapraz derleme için hedef platforma uygun bir C derleyicisi de gerekir. go help environment, CGO_ENABLED değişkenini cgo komutunun desteklenip desteklenmediğini belirten 0 ya da 1 değeri olarak tanımlar. Bu makinede C derleyicisi olmadığı için go env CGO_ENABLED değeri 0 çıktı ve yukarıdaki derleme bilgisinde de CGO_ENABLED=0 görünüyor. Go 1.27 sürüm notlarının PowerPC bölümünde, cgo kullanmayan programlar için araç takımının varsayılan olarak iç bağlamayla statik ikili ürettiği ve statik, saf Go bir ikili gerektiğinde go build sırasında CGO_ENABLED=0 ayarlanabileceği belirtiliyor. Bu, Go ile yazılmış bir web servisini tek dosya olarak bir Linux sunucusuna kopyalamayı kolaylaştırır. cgo'nun kendisi bu serinin kapsamı dışında.

-ldflags -X ile sürüm bilgisi yazmak

-ldflags bayrağı, go help build çıktısına göre her go tool link çağrısına iletilecek argümanları alır. Bağlayıcının -X seçeneği ise go tool link -help çıktısında "importpath.name=value biçiminde bir dizgi değeri tanımı ekler" diye açıklanır. Bu sayede sürüm numarasını ya da derleme tarihini kaynak dosyayı değiştirmeden programa yazabilirsiniz. main paketindeki değişkenler için import yolu yerine main yazılır:

bash
$ go build -ldflags "-X main.surum=1.4.0 -X main.tarih=2026-11-07" -o bin/surum2.exe .
$ ./bin/surum2.exe
surum=1.4.0 tarih=2026-11-07
hedef=windows/amd64

Değer yalnızca dizgi değişkenlerine yazılabilir. Bir const ile denediğimizde derleme hata vermeden tamamlandı ama değer değişmedi; bu sessizlik, yanlış adı yazdığınızda da (ör. main.Surum) bir uyarı almayacağınız anlamına gelir. Aşağıdaki programı -X main.surum=1.4.0 -X main.adres=uzak ile derledik:

go
package main

import "fmt"

const surum = "geliştirme"

var adres = varsayilan()

func varsayilan() string { return "yerel" }

func main() {
	fmt.Println(surum, adres)
}
text
geliştirme uzak

Sabit surum değişmedi, dizgi değişkeni adres ise bir fonksiyon çağrısıyla başlatılmasına rağmen bu denemede yeni değeri aldı. Değişkenin bulunduğu paket main değilse tam import yolunu yazın: -X example.com/proje/internal/surum.Numara=1.4.0. Bağlayıcının -s seçeneği sembol tablosunu, -w seçeneği DWARF hata ayıklama bilgisini kapatır ve dosyayı küçültür, ama hata ayıklayıcıların işini zorlaştırır. Bu denemede Linux/arm64 ikilisi -trimpath -ldflags "-s -w" ile yaklaşık 2,3 MB'tan 1,6 MB'a indi; boyutlar sürüme ve koda göre değişir.

Derleme bilgisini programın içinden okumak için runtime/debug.ReadBuildInfo kullanılır. Belgeye göre bu bilgi yalnızca modül desteğiyle derlenmiş ikililerde bulunur:

go
package main

import (
	"fmt"
	"runtime/debug"
)

func main() {
	bi, ok := debug.ReadBuildInfo()
	if !ok {
		fmt.Println("derleme bilgisi yok")
		return
	}
	fmt.Println("Go:", bi.GoVersion)
	fmt.Println("modül:", bi.Main.Path)
	for _, s := range bi.Settings {
		if s.Key == "GOOS" || s.Key == "GOARCH" || s.Key == "-trimpath" {
			fmt.Println(s.Key, "=", s.Value)
		}
	}
}
bash
$ go build -trimpath -o b.exe . && ./b.exe
Go: go1.27.3
modül: example.com/bilgi
-trimpath = true
GOARCH = amd64
GOOS = windows

-trimpath, go help build açıklamasına göre ikili dosyadaki tüm dosya sistemi yollarını kaldırır ve dosya adlarını modül yolu ile başlatır; derleme makinesinin dizin yapısının ikiliye sızmasını önler. Go 1.24 sürüm notlarına göre go build, sürüm kontrol sistemindeki etikete ya da commit'e göre ana modülün sürümünü ikiliye yazar, işlenmemiş değişiklik varsa sona +dirty ekler; bu bilgiyi kapatmak için -buildvcs=false kullanılır. Örneklerimiz bir Git deposunda olmadığı için modül sürümü (devel) göründü.

Derleme kısıtları: //go:build ve dosya adları

go help buildconstraint çıktısına göre derleme kısıtı (build tag), bir dosyanın pakete dahil edilme koşuludur. //go:build ile başlayan bir satır yorumuyla yazılır, ||, &&, ! ve parantezlerle birleştirilir. Kısıt dosyanın başında, yalnızca boş satırlar ve diğer yorumlardan sonra, yani paket satırından önce yer almalıdır; belge yorumuyla karışmaması için arkasından boş bir satır gelmelidir. Bir dosyada birden çok //go:build satırı olamaz.

Derleme sırasında şu etiketler sağlanmış sayılır: hedef işletim sistemi (runtime.GOOS), hedef mimari (runtime.GOARCH), Unix benzeri sistemlerde unix, kullanılan derleyici (gc ya da gccgo), cgo destekleniyorsa cgo, mevcut sürüme kadar her Go büyük sürümü için go1.1 ile go1.27 arası terimler ve -tags bayrağıyla verilen ek etiketler. Ayrıca dosya adı uzantı ve olası _test eki atıldıktan sonra *_GOOS, *_GOARCH ya da *_GOOS_GOARCH kalıbına uyuyorsa, dosya örtük bir kısıt taşır. Bu iki mekanizmayı birlikte kullanan bir program yazalım:

go
package main

import "fmt"

func main() {
	fmt.Println("sistem:", sistemAdi())
	fmt.Println("sürüm:", paket)
}
go
package main

func sistemAdi() string { return "Windows" }
go
package main

func sistemAdi() string { return "Linux" }
go
//go:build !windows && !linux

package main

func sistemAdi() string { return "başka bir sistem" }
go
//go:build pro

package main

const paket = "Pro"
go
//go:build !pro

package main

const paket = "Ücretsiz"
bash
$ go run .
sistem: Windows
sürüm: Ücretsiz
$ go run -tags pro .
sistem: Windows
sürüm: Pro

sistem_windows.go ve sistem_linux.go dosyalarında hiç //go:build satırı yok; dosya adları yeterli. Diğer sistemler için !windows && !linux kısıtı yazdık ki her platformda sistemAdi fonksiyonunun tam olarak bir tanımı bulunsun. Hangi dosyaların seçildiğini derlemeden görmek için go list kullanılabilir; ortam değişkenleri ve -tags bu seçimi değiştirir:

bash
$ go list -f '{{.GoFiles}}' .
[main.go sistem_windows.go ucretsiz.go]
$ GOOS=linux go list -f '{{.GoFiles}}' .
[main.go sistem_linux.go ucretsiz.go]
$ GOOS=darwin go list -f '{{.GoFiles}}' -tags pro .
[main.go pro.go sistem_diger.go]
$ GOOS=darwin go list -f '{{.IgnoredGoFiles}}' -tags pro .
[sistem_linux.go sistem_windows.go ucretsiz.go]

Bir dosyayı hiçbir derlemeye almamak için gelenek //go:build ignore yazmaktır. Go 1.16 ve öncesi // +build sözdizimini kullanıyordu; gofmt eski sözdizimini gördüğünde eşdeğer bir //go:build satırı ekler ve go fix içindeki plusbuild düzelticisi artık gereksiz olan eski satırları siler. Go 1.21 ve sonrasını hedefleyen modüllerde bir dosyanın kısıtında Go sürümü terimi varsa (ör. //go:build go1.24), o dosya kısıtın gerektirdiği en düşük dil sürümüyle derlenir. Go 1.24 sürüm notlarına göre go vet'in buildtag denetimi go1.23.1 gibi ara sürüm terimlerini geçersiz sayar; yalnızca go1.23 gibi büyük sürüm terimleri kullanılmalıdır.

Kısıtı paket satırından sonraya yazmak sık yapılan bir hatadır. Bu durumda satır kısıt olarak işlenmez; Go 1.27.3 programı derlemeyi reddetti ve go vet de sorunu ayrıca raporladı:

text
package main

//go:build pro

import "fmt"

func main() {
	fmt.Println("bu dosya her zaman derlenir")
}
text
$ go run .
# example.com/yanlis
./main.go:3:3: misplaced compiler directive
$ go vet .
main.go:3:1: misplaced //go:build comment

gofmt -d bu dosyada //go:build satırını paket satırının üstüne taşımayı önerdi; ama kısıt yer değiştirince dosyanın anlamı da değişir (artık yalnızca -tags pro ile derlenir), bu yüzden düzeltmeyi bilinçli yapın. Kısıtları programatik olarak ayrıştırmak ve değerlendirmek gerekirse standart kütüphanedeki go/build/constraint paketi her iki sözdizimini de ayrıştırır.

Sık yapılan hatalar

Sık yapılan hatalar: GOOS ve GOARCH değerlerini kalıcı bırakmak, cgo kullanan bir projeyi C derleyicisi olmadan çapraz derlemeye..., -X adını yanlış yazmak, //go:build satırını...
  • GOOS ve GOARCH değerlerini kalıcı bırakmak: go env -w GOOS=linux sonraki tüm komutları etkiler; hedefi tek komut için ortam değişkeniyle verin.
  • cgo kullanan bir projeyi C derleyicisi olmadan çapraz derlemeye çalışmak: cgo hedef platform için bir C derleyicisine ihtiyaç duyar; saf Go kod yazıyorsanız CGO_ENABLED=0 ile statik ikili üretin.
  • -X adını yanlış yazmak: Bağlayıcı uyarı vermez, değer sessizce yazılmaz. Değişkenin tam import yolunu ve adını kontrol edin; sabitlere değer yazılamaz.
  • //go:build satırını paket satırından sonra koymak: Kısıt yok sayılmaz, derleme hatası alırsınız. Kısıt dosyanın en üstünde, arkasında boş satırla durmalıdır.
  • Her platform için fonksiyon tanımını eksik bırakmak: Yalnızca _windows.go ve _linux.go yazarsanız macOS derlemesi tanımsız fonksiyon hatası verir. GOOS=darwin go build ile deneyin ya da varsayılan bir dosya ekleyin.
  • go build ile go install'ı karıştırmak: go build dosyayı bulunduğunuz dizine yazar, PATH'e eklemez; bir aracı her yerden çalıştırmak istiyorsanız go install kullanın ve kurulum dizinini PATH'e ekleyin.

Sık Sorulan Sorular

Windows'ta Linux sunucusu için nasıl derlerim?

PowerShell'de $env:GOOS="linux"; $env:GOARCH="amd64"; go build -o uygulama, Git Bash'te GOOS=linux GOARCH=amd64 go build -o uygulama yazın. Kod cgo kullanmıyorsa ek araç gerekmez. Oluşan dosyayı sunucuya kopyalayıp çalıştırılabilir izni verdikten sonra çalıştırabilirsiniz; Linux temelleri için Linux nedir? yazısına bakabilirsiniz.

Go ikili dosyası neden bu kadar büyük?

Go programları çalışma zamanını ve kullandıkları tüm paketleri tek dosyada taşır ve varsayılan olarak hata ayıklama bilgisi içerir. -ldflags "-s -w" sembol tablosunu ve DWARF bilgisini çıkararak dosyayı küçültür; bu yazıdaki denemede yaklaşık üçte bir oranında küçülme oldu.

Derlenmiş bir dosyanın hangi Go sürümüyle üretildiğini nasıl öğrenirim?

go version dosya sürümü, go version -m dosya modül yolu, bağımlılık sürümleri ve derleme ayarlarıyla birlikte tam bilgiyi yazar. Program içinden aynı bilgiyi runtime/debug.ReadBuildInfo ile okuyabilirsiniz.

Dosyaları ikiliye gömebilir miyim?

Evet; HTML şablonları, statik dosyalar ya da yapılandırma örnekleri //go:embed yönergesiyle derleme sırasında ikiliye eklenebilir. Ayrıntılar Go embed ile dosya gömme yazısında. Ortaya çıkan tek dosyayı bir konteynere koymak için Dockerfile yazma rehberi, sunucuda servis olarak çalıştırmak için systemd servis dosyası rehberi yazılarına bakabilirsiniz.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: Go öğrenme rehberi · Go modül yönetimi · gofmt, go vet ve go doc · Go embed · Go flag ile komut satırı argümanları · Dockerfile yazma rehberi