Bagaimana cara GCC dan g ++ di-bootstrap?

186

Ini telah menggangguku untuk sementara waktu. Bagaimana GCC dan g ++ mengkompilasi sendiri?

Saya menduga bahwa setiap revisi dikompilasi dengan revisi yang dibangun sebelumnya. Apakah ini benar? Dan jika ya, apakah itu berarti versi g ++ dan GCC tertua ditulis dalam assembly?

pengguna1010005
sumber
13
Setiap revisi akhirnya dapat dikompilasi dengan sendirinya. :)
Martin Hennings
4
Ini menarik untuk dibaca jika Anda ingin melihat bagaimana kompiler pertama muncul.
parkovski
1
@parkovski Apakah tautannya mati?
Nubcake
Tautan terakhir terlihat pada 04 Juni 2016: web.archive.org/web/20160604035203/homepage.ntlworld.com/…
akraf

Jawaban:

175

Versi tertua dari GCC dikompilasi menggunakan kompiler C lain, karena ada yang lain ketika ditulis. Kompiler C pertama yang pernah (ca. 1973, IIRC) diimplementasikan baik dalam perakitan PDP-11 , atau dalam bahasa pemrograman B yang mendahuluinya, tetapi dalam hal apa pun kompiler B ditulis dalam perakitan.Demikian pula, kompiler C ++ pertama (CPre / Cfront , 1979-1983) mungkin pertama kali diimplementasikan dalam C, kemudian ditulis ulang dalam C ++.

Saat Anda mengompilasi GCC atau kompiler self-hosting lainnya, susunan lengkap bangunan adalah:

  1. Buat versi baru GCC dengan kompiler C yang ada
  2. membangun kembali versi baru GCC dengan yang baru saja Anda buat
  3. (opsional) ulangi langkah 2 untuk keperluan verifikasi.

Proses ini disebut bootstrap . Ini menguji kemampuan kompiler mengkompilasi sendiri dan memastikan bahwa kompiler yang dihasilkan dibangun dengan semua optimisasi yang diimplementasikan sendiri.

EDIT : Drew Dormann, dalam komentar, menunjuk ke akun Bjarne Stroustrup tentang implementasi paling awal dari C ++ . Itu diimplementasikan dalam C ++ tetapi diterjemahkan oleh apa yang disebut Stroustrup "preprocessor" dari C ++ ke C; bukan kompiler penuh menurut definisinya, tetapi masih C ++ telah bootstrap di C.

Fred Foo
sumber
19
Versi 3 langkah proses pembuatan bootstrap memang untuk verifikasi: kompiler itu sendiri digunakan sebagai test case sendiri. GCC yang dikompilasi dengan [lain] harus menghasilkan hasil yang sama (binari identik, seperti diskon makro __DATE__dan __TIME__yang bervariasi bahkan antara pemanggilan kompiler yang sama ) seperti GCC yang dikompilasi dengan [GCC dikompilasi dengan [lain]] - jika tidak, itu bug, dan build bootstrap 3-tahap dirancang untuk menangkapnya.
pmdj
19
@ pmjordan: "jika tidak, itu bug" atau, kemungkinan kecil, pintu belakang yang licik dalam proses diperkenalkan ("Refleksi Kepercayaan Kepercayaan").
Steve Jessop
12
@sleske: itu tidak benar. Output biner dari langkah 2 harus identik dengan output biner dari langkah 3, jika tidak ada bug di suatu tempat. Alasannya adalah seperti yang dikatakan pmjordan: NewCompiler1 dan NewCompiler2 adalah program dengan sumber yang identik (dari NewCompiler). Mereka diberi input yang identik (sumber untuk NewCompiler). Oleh karena itu mereka akan menghasilkan keluaran yang sama tidak peduli apa pun kompiler yang dikompilasi dengan mereka (dalam hal ini, NewCompiler1 dikompilasi dengan OldCompiler, dan NewCompiler2 dikompilasi dengan NewCompiler1). Yaitu, NewCompiler2 dan NewCompiler3 adalah biner identik.
Steve Jessop
12
Saya pernah bertanya-tanya: Bagaimana jika kita kehilangan semua binari kompiler C? Dan harus bootstrap dari awal? Ini adalah bagaimana saya akan melakukannya: Ada Tiny C Compiler (yang sebenarnya dapat mengkompilasi kernel Linux, jadi ini cukup lengkap). Semua file sumber C-nya hanya menghasilkan 30k baris kode, termasuk komentar. Meskipun itu adalah usaha yang cukup berat, seseorang yang mengerti C dapat belajar dari sumbernya, bagaimana menghasilkan keluaran biner dan "menyusun" sumber-sumber TCC dari tangan (saya sebenarnya memikirkan kartu punch di sini). Kemudian mengkompilasi ulang TCC dengan itu dan menggunakannya untuk mem-bootstrap GCC atau serupa.
datenwolf
11
@datenwolf: sesuatu seperti itu, ya. Jika kita dapat berasumsi bahwa kita telah kehilangan semua binari kompiler C, tetapi kita masih memiliki assembler, maka kita mungkin menulis program assembler TinyTinyC. Ini akan menjadi kompiler C yang kurang lengkap daripada TinyC: kita tidak memerlukannya untuk dapat mengkompilasi GCC atau kernel linux, kita hanya perlu untuk dapat mengkompilasi TinyC. Kemudian jalankan di sumber TinyC, yang memberi kita kompiler C yang mampu mengkompilasi Linux (dan mudah-mudahan glibc dan GCC) dan kita dalam bisnis. Jika kita bahkan tidak memiliki assembler, maka kita pertama-tama akan mem-bootstrap salah satunya, itu lebih mudah daripada kompiler C.
Steve Jessop