Binary hasil go build pada chapter sebelumnya sudah bisa berjalan, tetapi masih membawa tiga bekal yang tidak selalu diinginkan di production: tabel simbol dan informasi debug (memperbesar ukuran), path direktori kerja mesin build (membocorkan struktur folder), dan versi yang tertulis manual di source. Perintah go build menerima flag yang mengendalikan ketiganya sekaligus. Chapter ini mempraktikkan -ldflags untuk memangkas binary dan menyuntik nomor versi, -trimpath untuk membersihkan path, serta build tags untuk memilih kode mana yang ikut dikompilasi.
Memangkas Ukuran dengan -s -w #
Compiler Go menyertakan symbol table dan data debug DWARF di dalam binary — bahan yang dibutuhkan Delve dan profiler saat development. Flag -ldflags "-s -w" menghapus keduanya saat linking: -s membuang symbol table, -w membuang data debug. Kita buktikan dengan program versi-inject.go di bagian bawah halaman (salin isinya sebagai main.go pada modul example.com/appflag):
go build -o app-plain
go build -ldflags "-s -w" -o app-strip
ls -lh app-plain app-stripOutput yang Dihasilkan:
-rwxrwxr-x 1 z z 2.3M Oct 13 13:22 app-plain
-rwxrwxr-x 1 z z 1.5M Oct 13 13:22 app-stripUkuran turun dari 2.3M menjadi 1.5M — pemangkasan 35 persen untuk satu flag. Kedua binary menghasilkan output program yang sama persis:
./app-plain
./app-stripOutput yang Dihasilkan:
aplikasi contoh build-flags
versi: dev
aplikasi contoh build-flags
versi: devMenyuntik Versi dengan -X #
Menulis nomor versi di source lalu meng-commit setiap rilis rawan tertinggal. Flag -X importpath.name=nilai mengisi variabel string dari luar saat build. Berikut program lengkapnya — berkas versi-inject.go di bagian bawah halaman:
package main
import "fmt"
// version diisi lewat flag -ldflags "-X main.version=..." saat build.
var version = "dev"
func main() {
fmt.Println("aplikasi contoh build-flags")
fmt.Println("versi:", version)
}Output yang Dihasilkan:
aplikasi contoh build-flags
versi: devMari kita telaah baris demi baris program di atas:
- Baris 5 (
var version = "dev"): mendeklarasikan variabel package-level bertipe string. Nilai"dev"hanya berlaku bila tidak ada-Xyang menimpanya — misalnya saatgo rundi mesin development. - Baris 5 (penamaan
version): flag-Xmenunjuk variabel dengan path lengkapnya; karena variabel ini berada di packagemain, targetnya adalahmain.version. - Baris 9 (
fmt.Println("versi:", version)): mencetak isi variabel saat binary dijalankan, sehingga nilai hasil inject terlihat langsung.
Sekarang kita bangun dengan versi yang disuntikkan:
go build -ldflags "-X main.version=1.2.3" -o app-inject
./app-injectOutput yang Dihasilkan:
aplikasi contoh build-flags
versi: 1.2.3-trimpath: Membersihkan Path Build #
Tanpa flag tambahan, binary menyimpan path absolut direktori tempat ia dibangun — misalnya /home/z/proyek/appflag — di metadata dan stack trace. Flag -trimpath mengganti seluruh path berkas dengan path relatif module. Kita bisa menghitung jejaknya di dalam binary dengan grep:
go build -o app-plain
go build -trimpath -o app-bersih
grep -ao "$(pwd)" app-plain | wc -l
grep -ao "$(pwd)" app-bersih | wc -lOutput yang Dihasilkan:
1
0Binary pertama memuat path direktori kerja satu kali; binary kedua tidak sama sekali. Dua manfaatnya: binary tidak membocorkan struktur direktori mesin CI, dan dua orang yang membangun source sama dari folder berbeda menghasilkan binary identik — fondasi build yang dapat direproduksi.
Build Tags: Memilih Kode Saat Kompilasi #
Build tags memilih berkas mana yang ikut dikompilasi — kebalikan dari if runtime.GOOS == "linux" yang memutus saat runtime. Constraint ditulis sebagai komentar //go:build di baris pertama berkas. Siapkan modul kedua (go mod init example.com/tagdemo) berisi tiga berkas: main.go yang memanggil namaFitur(), lalu dua definisi fungsinya.
package main
import "fmt"
func main() {
fmt.Println(namaFitur())
}//go:build ekstra
package main
// namaFitur versi penuh, hanya ikut build jika tag "ekstra" aktif.
func namaFitur() string {
return "fitur A: implementasi penuh (tag ekstra)"
}//go:build !ekstra
package main
// namaFitur versi stub, dipakai ketika tag "ekstra" tidak aktif.
func namaFitur() string {
return "fitur A: stub (tanpa tag)"
}Dua berkas tersebut mendefinisikan fungsi bernama sama, tetapi constraint-nya saling melengkapi (ekstra dan !ekstra) sehingga tepat satu definisi aktif pada setiap build. Bukti nyatanya:
go run .
go run -tags ekstra .Output yang Dihasilkan:
fitur A: stub (tanpa tag)
fitur A: implementasi penuh (tag ekstra)Mekanisme yang sama bekerja untuk platform: constraint //go:build linux membuat berkas hanya terkompilasi untuk target Linux, dan pasangan //go:build !linux menyediakan implementasi pengganti. Bedanya dengan pemeriksaan runtime.GOOS: kode di berkas non-aktif tidak dikompilasi sama sekali — berguna saat berkas itu memakai syscall atau library yang hanya ada di satu platform.
Kombinasi Lengkap untuk Rilis #
Satu perintah build production biasanya menggabungkan seluruh kendali di atas:
go build -trimpath -ldflags "-s -w -X main.version=1.2.3" -o app-rilis
ls -lh app-rilis
./app-rilisOutput yang Dihasilkan:
-rwxrwxr-x 1 z z 1.5M Oct 13 13:28 app-rilis
aplikasi contoh build-flags
versi: 1.2.3| Kendali | Efek ke binary |
|---|---|
-ldflags "-s -w" | Ukuran turun 35 persen, simbol dan debug hilang |
-ldflags "-X main.version=..." | Nomor versi tertanpa tanpa mengubah source |
-trimpath | Path build bersih, binary identik lintas mesin |
-tags <nama> | Memilih berkas sumber yang ikut terkompilasi |
Binary app-rilis yang ramping dan beridentitas ini adalah kandidat sempurna untuk dikirim ke berbagai platform sekaligus. Chapter Cross Compilation
membangun binary yang sama untuk Linux ARM, Windows, dan macOS.
Referensi #
- Build flags
— daftar resmi seluruh flag
go buildtermasuk-ldflagsdan-trimpath. - Dokumentasi perintah go
— rujukan induk untuk
go build,go install, dango run.
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
versi-inject.go
Unduh berkaspackage main
import "fmt"
// version diisi lewat flag -ldflags "-X main.version=..." saat build.
var version = "dev"
func main() {
fmt.Println("aplikasi contoh build-flags")
fmt.Println("versi:", version)
}