Dokumen ini menjelaskan cara menggunakan gccgo, salah satu compiler untuk bahasa Go. Compiler gccgo adalah antar-muka terbaru dari GCC, compiler dari GNU yang banyak digunakan. Walaupun antar-muka itu sendiri berada di bawah lisensi model-BSD, gccgo biasanya digunakan sebagai bagian dari GCC oleh karena itu dilindungi oleh lisensi GNU General Public License (lisensi ini melingkupi gccgo sebagai bagian dari GCC; tidak mengikutkan kode yang dihasilkan oleh gccgo).
Ingatlah bahwa gccgo bukan compiler gc; lihat instruksi Memasang Go untuk compiler tersebut.
Rilis
Cara paling gampang untuk memasang gccgo yaitu dengan memasang rilis dari program GCC yang mengikutkan dukungan Go. Rilis program GCC tersedia pada situs berikut dan biasanya sudah tersedia pada kebanyakan distribusi GNU/Linux. Umumnya distro sudah membangun program GCC yang mengikutkan dukungan terhadap Go.
GCC rilis 4.7.1 dan selanjutnya mengikutkan compiler dan pustaka Go 1.
Dikarenakan isu waktu, GCC rilis 4.8.0 dan 4.8.1 mendekati Go 1.1 tetapi tidak identik. GCC rilis 4.8.2 mengikutkan implementasi Go 1.1.2.
GCC rilis 4.9 mengikutkan implementasi Go 1.2.
GCC rilis 5 mengikutkan implementasi pustaka Go 1.4. Go 1.4 runtime belum digabung semuanya, namun hal ini seharusnya tidak memengaruhi program Go.
GCC rilis 6 mengikutkan implementasi pustaka Go 1.6.1. Go 1.6 runtime belum digabung semuanya, namun hal ini seharusnya tidak memengaruhi program Go.
GCC rilis 7 mengikutkan implementasi pustaka Go 1.8.1. Seperti rilis sebelumnya, Go 1.8 runtime belum digabungkan, namun hal ini tidak memengaruhi program Go.
GCC rilis 8 mengikutkan implementasi Go 1.10.1. Go 1.10 runtime telah digabungkan seluruhnya ke sumber pengembangan GCC, dan telah mendukung garbage collection secara konkuren.
GCC rilis 9 mengikutkan implementasi dari Go rilis 1.12.2.
Kode sumber
Jika Anda tidak bisa menggunakan versi rilis, atau lebih menyukai membangun
gccgo dari awal, kode sumber gccgo tersedia lewat Git.
Situs GCC memiliki
instruksi untuk mendapatkan kode sumber GCC.
Kode sumber gccgo sudah termasuk di dalamnya.
Versi stabil dari dukungan Go tersedia dalam cabang devel/gccgo
pada
repositori utama dari GCC: git://gcc.gnu.org/git/gcc.git
.
Cabang ini secara periodik diperbarui dengan sumber compiler Go yang stabil.
Perlu diketahui, walaupun gcc.gnu.org adalah salah satu cara umum untuk mendapatkan kode sumber untuk antar-muka Go, repositori itu bukanlah sumber utama sebenarnya. Jika Anda ingin berkontribusi pada antar-muka compiler Go, lihatlah halaman Berkontribusi pada gccgo.
Pembangunan
Pembangunan gccgo seperti membangun GCC biasa dengan satu atau dua opsi
tambahan.
Lihat
instruksi pada situs gcc.
Saat Anda menjalankan configure
, tambahkan opsi
--enable-languages=c,c,go
(beserta dengan bahasa pemrograman lain yang
ingin dibangun).
Jika Anda menargetkan 32-bit x86, maka Anda harus membangun gccgo yang
mendukung instruksi locked compare dan exchange;
lakukan hal ini dengan menambahkan opsi --with-arch=i586
(atau arsitektur
terbaru, bergantung pada di mana program Anda akan berjalan).
Jika Anda menargetkan 64-bit x86, tapi terkadang ingin menggunakan opsi
-m32
, maka gunakan opsi --with-arch-32=i586
.
Gold
Pada sistem GNU/Linux, compiler gccgo mampu menggunakan sejumlah stack kecil pada goroutine. Hal ini membolehkan program untuk menjalankan banyak goroutine, secara setiap goroutine menggunakan ukuran stack yang kecil. Fitur ini membutuhkan gold linker versi 2.22 atau terbaru. Anda bisa memasang GNU binutils 2.22 atau yang terbaru, atau Anda bisa membangunnya sendiri.
Untuk membangun gold
sendiri, buat GNU binutils menggunakan
--enable-gold=default
saat menjalankan skrip configure
.
Sebelum pembangunan, Anda harus memasang paket flex
dan bison
.
Urutan langkah-langkahnya biasanya seperti berikut (Anda bisa mengganti
/opt/gold
dengan direktori lain yang bisa Anda tulis):
git clone git://sourceware.org/git/binutils-gdb.git mkdir binutils-objdir cd binutils-objdir ../binutils-gdb/configure --enable-gold=default --prefix=/opt/gold make make install
Bagaimanapun Anda memasang gold, saat menjalankan configure
pada gccgo
gunakan opsi --with-ld=GOLD_BINARY
.
Kebutuhan awal
Sejumlah kebutuhan awal diperlukan untuk membangun GCC, seperti yang
dijelaskan pada
situs GCC.
Sangatlah penting untuk memasang semua kebutuhan awal tersebut sebelum
menjalankan skrip configure
pada gcc.
Pustaka-pustaka untuk kebutuhan awal dapat diunduh menggunakan skrip
contrib/download_prerequisites
dalam sumber GCC.
Perintah pembangunan
Setelah semua kebutuhan terpasang, maka urutan langkah pembangunan dan
pemasangan adalah seperti berikut (hanya gunakan opsi --with-ld
jika Anda
menggunakan gold linker seperti yang dijelaskan di atas):
git clone --branch devel/gccgo git://gcc.gnu.org/git/gcc.git gccgo mkdir objdir cd objdir ../gccgo/configure --prefix=/opt/gccgo --enable-languages=c,c++,go --with-ld=/opt/gold/bin/ld make make install
Menggunakan gccgo
Compiler gccgo bekerja seperti antar-muka gcc lainnya. Pada GCC 5, pemasangan gccgo mengikutkan versi dari perintah go, yang bisa digunakan untuk membangun program Go seperti yang dijelaskan di Perintah Go.
Untuk mengompilasi sebuah berkas tanpa menggunakan perkakas go
,
gccgo -c file.go
Perintah ini menghasilkan file.o
.
Untuk mengaitkan berkas-berkas menjadi sebuah program:
gccgo -o file file.o
Untuk menjalankan program hasil, Anda perlu memberitahu program tersebut tempat di mana paket-paket Go yang telah dikompilasi. Ada beberapa cara untuk melakukan hal ini:
-
Set variabel sistem
LD_LIBRARY_PATH
:LD_LIBRARY_PATH=${prefix}/lib/gcc/MACHINE/VERSION [or] LD_LIBRARY_PATH=${prefix}/lib64/gcc/MACHINE/VERSION export LD_LIBRARY_PATH
Di sini
${prefix}
adalah opsi--prefix
saat membangun gccgo, biasanya/usr
. Apakah menggunakanlib
ataulib64
bergantung kepada target. Biasanyalib64
untuk sistemx86_64
, danlib
untuk sistem lainnya. Inti-nya adalah untuk menentukan direktori tempatlibgo.so
disimpan. -
Mengirim opsi
-WL,-R
saat melakukan langkah pengaitan (gantilib
denganlib64
sesuai dengan sistem Anda):go build -gccgoflags -Wl,-R,${prefix}/lib/gcc/MACHINE/VERSION [or] gccgo -o file file.o -Wl,-R,${prefix}/lib/gcc/MACHINE/VERSION
-
Gunakan opsi
-static-libgo
untuk mengaitkan program secara statis terhadap paket-paket kompilasi. -
Gunakan opsi
-static
untuk menghasilkan program statis sepenuhnya (nilai baku dari compiler gc).
Opsi-opsi
Compiler gccgo mendukung semua opsi GCC untuk bahasa yang berdiri sendiri,
yang palng sering digunakan yaitu -O
dan -g
.
Opsi -fgo-pkgpath=PKGPATH
bisa digunakan untuk men-set prefiks yang unik
untuk paket yang sedang dikompilasi.
Opsi ini digunakan secara otomatis oleh perkakas go, namun Anda mungkin mau
menggunakan opsi ini saat memanggil gccgo.
Opsi ini diperuntukkan untuk program besar yang berisi banyak paket, untuk
membolehkan beberapa paket menggunakan pengidentifikasi yang sama sebagai nama
paket.
Isi dari PKGPATH bisa string apa saja;
pilihan baiknya untuk string ini yaitu path yang digunakan untuk mengimpor
paket tersebut.
Opsi -I
dan -L
, yang bagi compiler berlaku sama, bisa digunakan untuk
menentukan path pencarian saat impor.
Opsi ini tidak dibutuhkan jika Anda membangun dengan perkakas go.
Impor
Saat Anda mengompilasi sebuah berkas yang mengekspor sesuatu, informasi tentang ekspor ini disimpan langsung dalam berkas objek. Jika Anda membangun dengan gccgo, bukan dengan perkakas go, maka saat Anda mengimpor sebuah paket, Anda harus memberitahu gccgo bagaimana mencari berkas tersebut.
Saat Anda mengimpor paket FILE dengan gccgo, ia akan mencari data impor dalam berkas-berkas berikut, dan menggunakan berkas pertama yang ditemukan.
-
FILE.gox
-
libFILE.so
-
libFILE.a
-
FILE.o
FILE.gox
hanya berisi data yang di-ekspor saja.
Berkas ini bisa dihasilkan dari FILE.o
lewat
objcopy -j .go_export FILE.o FILE.gox
Compiler gccgo akan mencari berkas-berkas impor di direktori yang sekarang.
Pada skenario yang kompleks Anda bisa menambahkan opsi -I
atau -L
pada
gccgo.
Kedua opsi ini menerima nama direktori untuk tempat pencarian.
Opsi -L
juga dikirim ke linker.
Compiler gccgo saat ini (2015-06-15) tidak mencatat nama berkas dari
paket-paket yang diimpor di dalam berkas objek.
Anda harus mengatur data yang diimpor untuk dikaitkan pada program.
Sekali lagi, hal ini tidak berlaku saat membangun dengan perintah go
.
gccgo -c mypackage.go # Ekspor mypackage gccgo -c main.go # Impor mypackage gccgo -o main main.o mypackage.o # Secara eksplisit mengaitkan dengan mypackage.o
Debugging
Jika Anda menggunakan opsi -g
saat kompilasi, Anda bisa menjalankan program
debugger gdb
pada program Anda.
Debugger ini memiliki batasan kemampuan tentang Go.
Anda bisa men-set breakpoint, single-step, dan lainnya.
Anda bisa mencetak nilai variabel, namun akan dicetak seperti tipe-tipe C/C++.
Untuk tipe numerik hal ini tidak terlalu penting.
Tipe string dan interface pada Go akan muncul sebagai struct dengan dua
elemen.
Tipe map dan channel
pada Go selalu direpresentasikan sebagai C pointer ke
struktur run-time.
C interoperabilitas
Saat menggunakan gccgo ada keterbatasan interoperabilitas dengan C, atau
dengan kode C++ yang dikompilasi menggunakan extern "C"
.
Tipe-tipe
Tipe-tipe dasar dipetakan secara langsung:
sebuah int32
pada Go adalah int32_t
pada C, sebuah int64
pada Go adalah
int64_t
, dan seterusnya.
Tipe int
pada Go yaitu sebuah integer yang sama dengan ukuran sebuah
pointer, yang berkorespondensi dengan tipe C intptr_t
.
Tipe byte
pada Go sama dengan unsigned char
pada C.
Tipe pointer pada Go sama dengan pointer pada C.
Tipe struct pada Go sama dengan struct pada C dengan field dan tipe yang sama
juga.
Tipe string pada Go didefinisikan sebagai struktur dengan dua elemen (hal ini bisa berubah sewaktu-waktu):
struct __go_string { const unsigned char *__data; intptr_t __length; };
Anda tidak bisa mengirimkan array antara C dan Go.
Namun, sebuah pointer ke array dalam Go sama dengan sebuah pointer ke tipe
elemen pada C.
Sebagai contohnya, Go *[10]int
sama dengan int*
pada C, mengasumsikan
bahwa pointer pada C memang menunjuk ke 10 elemen tersebut.
Sebuah slice pada Go adalah sebuah struct. Definisi slice saat ini (hal ini bisa berubah sewaktu-waktu):
struct __go_slice { void *__values; intptr_t __count; intptr_t __capacity; };
Tipe fungsi pada Go adalah sebuah pointer ke sebuah struct (hal ini bisa berubah sewaktu-waktu). Field pertama pada struct menunjuk ke kode pada fungsi, yang sama dengan sebuah pointer ke sebuah fungsi pada C yang tipe-tipe parameternya sama semua, dengan parameter tambahan di belakang. Parameter tambahan ini adalah closure, dan argumen yang dikirim yaitu sebuah pointer ke tipe struct. Saat sebuah fungsi Go mengembalikan lebih dari satu nilai, fungsi pada C mengembalikan sebuah struct. Misalnya, fungsi berikut ini berlaku sama,
func GoFunction(int) (int, float64) struct { int i; float64 f; } CFunction(int, void*)
Tipe interface, channel, dan map pada Go tidak memiliki tipe korespondensi
langsung pada C (interface adalah struct dengan dua elemen, channel dan map
adalah pointer ke struct pada C, namun struct ini sengaja tidak
didokumentasikan).
Tipe enum
pada C berkorespondensi pada tipe integer, namun secara tepatnya
sangat susah diprediksi secara umum; gunakan cast.
Tipe union
pada C tidak ada korespondensinya pada tipe Go.
Tipe struct
pada C dengan bitfields tidak ada korespondensinya pada tipe
Go.
Tipe class
pada C++ tidak ada korespondensinya pada tipe Go.
Alokasi memori sangatlah berbeda antara C dan Go, secara Go menggunakan garbage collection. Panduan pastinya pada area ini adalah tidak ditentukan, namun ada kemungkinan akan diperbolehkan mengirim sebuah pointer yang dialokasikan dari C ke Go. Tanggung jawab dari yang melepas pointer di memori akan dilakukan pada sisi C, dan tentu saja bila sisi C menghapus pointer sementara di sisi Go masih memiliki salinan maka program akan gagal. Saat mengirim sebuah pointer dari Go ke C, fungsi Go harus menahan salinan dari pointer tersebut dalam variabel Go. Jika tidak maka garbage collector pada Go bisa saja menghapus pointer tersebut saat fungsi C masih menggunakannya.
Nama-nama fungsi
Kode Go bisa memanggil fungsi pada C secara langsung menggunakan sebuah
ekstensi Go yang diimplementasikan dalam gccgo: sebuah deklarasi fungsi bisa
diawali dengan //extern NAME
.
Misalnya, berikut cara mendeklarasikan fungsi C open
dalam Go:
//extern open func c_open(name *byte, mode int, perm int) int
Fungsi C biasanya membutuhkan string yang berakhir dengan NUL, yang pada Go
sama dengan sebuah pointer ke sebuah array (bukan slice!) dari byte
yang berakhir dengan byte kosong.
Jadi contoh pemanggilan dari Go seperti berikut (setelah mengimpor paket
syscall
):
var name = [4]byte{'f', 'o', 'o', 0}; i := c_open(&name[0], syscall.O_RDONLY, 0);
(ini hanyalah contoh saja, untuk membuka sebuah berkas dalam Go gunakanlah
fungsi os.Open
)
Ingatlah jika fungsi C bisa memblok, seperti pemanggilan ke read
,
pemanggilan ke fungsi C tersebut bisa memblok keseluruhan program Go.
Kecuali bila Anda benar-benar paham apa yang Anda lakukan, semua pemanggilan
antara C dan Go sebaiknya diimplementasikan lewat cgo
atau SWIG
, seperti
pada compiler gc.
Nama dari fungsi-fungsi Go yang diakses dari C bisa berubah sewaktu-waktu.
Sekarang ini nama dari fungsi Go yang tidak memiliki receiver yaitu
prefix.package.Functionname
.
Nilai dari prefix
di set lewat opsi -fgo-prefix
saat paket dikompilasi;
jika opsi ini tidak di set, maka nilai baku-nya adalah go
.
Untuk memanggil fungsi tersebut dari C Anda harus mengeset nama tersebut
menggunakan ekstensi GCC.
extern int go_function(int) __asm__ ("myprefix.mypackage.Function");
Pembangkit otomatis deklarasi Go dari kode sumber C
Versi Go pada GCCÂ mendukung pembangkit otomatis deklarasi Go dari kode C.
Fasilitas ini sedikit aneh, dan pengguna pada umumnya sebaiknya menggunakan
program
cgo
dengan opsi -gccgo
.
Kompilasi kode C Anda seperti biasa, dan tambahkan opsi
-fdump-go-spec=FILENAME
.
Opsi tersebut akan membuat berkas FILENAME pada saat kompilasi.
Berkas ini akan berisi deklarasi Go untuk tipe-tipe, variabel, dan fungsi yang
dideklarasikan dalam kode C.
Tipe-tipe C yang tidak dapat direpresentasikan dalam Go akan dicatat sebagai
komentar dalam kode Go.
Berkas yang dibangkitkan tidak akan memiliki deklarasi paket, namun bisa
dikompilasi langsung oleh gccgo.
Prosedur ini memiliki batasan dan kelebihan yang tidak tertulis dan kami tidak menjamin ia tidak berubah di masa depan. Hal ini lebih berguna sebagai titik awal untuk pembangunan kode Go daripada prosedur untuk umum.