1 पॉइंट द्वारा GN⁺ 2024-08-26 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • Dozer एक शुद्ध C-आधारित Rust compiler है, जिसका उद्देश्य Rust को bootstrap के और शुरुआती चरण में उपयोग योग्य बनाना है, और इसे C++·flex·yacc·Makefile के बिना लिखा जा रहा है
  • आधिकारिक compiler rustc खुद Rust में लिखा गया है, इसलिए नया version पुराने rustc से build होता है, और यह श्रृंखला OCaml में लिखे शुरुआती Rust compiler तथा Guile·C परतों तक पीछे जाती है
  • Bootstrappable Builds का Linux bootstrap 512-byte binary seed से शुरू होता है और simple compiler, shell, C subset, TinyCC, yacc, coreutils, Bash, autotools, GCC, Linux तक फैलता है
  • अभी Rust इस chain में mrustc के जरिए काफी देर से आता है, जो rustc 1.56 को compile कर सकता है, इसलिए C++ आने से पहले Rust का उपयोग करना मुश्किल है
  • Dozer का लक्ष्य TinyCC से bootstrap होने वाला Rust compiler बनाना है, और आगे चलकर libcore, rustc का Cranelift backend, cargo replacement tool, तथा canonical rustc/cargo के rebuild तक पहुँचना है

Dozer के लक्ष्य और सीमाएँ

  • Dozer एक शुद्ध C में लिखा जा रहा Rust compiler है
  • यह C++ का उपयोग नहीं करता, और flex, yacc, Makefile भी नहीं उपयोग करता
  • इसका मुख्य लक्ष्य ऐसा compiler बनाना है जो Rust को C से bootstrap करने योग्य बनाए
  • खास तौर पर यह TinyCC से bootstrap होने योग्य होना चाहिए, और यह मानकर चलता है कि system में C compiler और बहुत basic shell के अलावा कोई उपयोगी tool नहीं है

Rust compiler के अपने-आप को build करने की समस्या

  • Rust code चलाने के लिए उसे compile करना पड़ता है, और आम तौर पर cargo build अंदर से rustc को call करता है
  • rustc खुद भी Rust में लिखा हुआ Rust compiler है, इसलिए नया rustc पुराने version के rustc से compile होता है
    • rustc 1.80.0, rustc 1.79.0 से compile होता है
    • यह chain rustc 1.78.0 जैसे और पुराने versions तक लगातार जाती है
  • शुरुआती चरण Rust 0.7 तक पीछे जाता है, जहाँ का compiler OCaml में लिखा गया था
  • OCaml compiler भी चाहिए, इसलिए bootstrap chain फिर दूसरी language implementations तक जाती है
    • camlboot Guile का उपयोग करके OCaml compiler को compile कर सकता है
    • Guile interpreter, C में लिखा गया है

Bootstrappable Builds की निचली chain

  • Bootstrappable Builds छोटे binary seed से पूरे system को bootstrap करने की प्रक्रिया पर काम करता है
  • Linux bootstrap process 512-byte binary seed से शुरू होता है
    • इस seed में एक बेहद simple compiler शामिल है, जो hexadecimal numbers लेकर उनके raw bytes output करता है
    • comments और whitespace हटाकर hexadecimal bytes की सूची को भी तकनीकी रूप से विश्लेषण योग्य source code माना जाता है
  • इसके बाद के चरण धीरे-धीरे higher-level tools build करते हैं
    • बेहद simple operating system
    • basic shell
    • थोड़ा अधिक विकसित compiler
    • assembly code जैसा दिखने वाला चरण
    • बहुत basic C subset
    • उसी C subset में लिखा गया अधिक विकसित C compiler
  • कुछ चरणों बाद TinyCC को compile किया जा सकता है, और उसके बाद yacc, basic coreutils, Bash, autotools, GCC, Linux तक पहुँचा जाता है
  • हर चरण live-bootstrap parts.rst में सूचीबद्ध है

Rust bootstrap chain में बहुत देर से आता है

  • अभी Rust इस प्रक्रिया में बहुत देर से आता है
  • यहाँ उपयोग की जाने वाली implementation mrustc है, जो C++ में लिखा गया एक वैकल्पिक Rust implementation है
  • mrustc, rustc 1.56 को compile कर सकता है, और उसके बाद modern Rust code तक compilation को आगे बढ़ाता है
  • लेकिन जिस समय C++ bootstrap chain में आता है, तब तक bootstrap वास्तव में लगभग पूरा हो चुका होता है
  • अगर C++ आने से पहले के चरण में Rust का उपयोग करना है, तो C से bootstrap होने वाला Rust compiler चाहिए

Dozer की मौजूदा implementation स्थिति

  • Dozer पर लगभग दो महीनों से काम चल रहा है, और इसे बिना extensions के लिखा गया है
  • अभी यह TinyCC और cproc दोनों से बिना समस्या compile हो सकता है
  • backend के लिए QBE का उपयोग किया जा रहा है
  • implementation अभी शुरुआती चरण में है
    • lexer पूरा हो चुका है
    • parser काफी हद तक implement हो चुका है
    • macro/module expansion को जितना संभव हो, उतना बाद के लिए टाला जा रहा है
    • type checking अभी सिर्फ i32 को support करती है
    • code generation अभी काफ़ी शुरुआती/rough स्थिति में है
  • अभी यह नीचे दिया गया Rust code सफलतापूर्वक compile कर सकता है
fn rust_main() -> i32 {
    (2 - 1) * 6 + 3
}

rustc तक पहुँचने की योजना

  • लक्ष्य है कि Dozer को धीरे-धीरे आगे बढ़ाकर basic libc उपयोग वाले examples, फिर libcore, और उसके बाद rustc तक compile किया जाए
  • rustc compilation के लिए Cranelift backend उपयोग करने की योजना है
    • Cranelift backend पूरी तरह Rust में लिखा गया है
    • क्योंकि C++ नहीं मानते, इसलिए LLVM को compile नहीं किया जा सकता
  • Dozer के साथ Rust packages compile करने के लिए एक cargo replacement tool बनाने की भी योजना है
  • rustc source में मौजूद auto-generated files को ढूँढकर हटाना होगा
    • Bootstrappable project के नियमों में auto-generated code की अनुमति नहीं है
  • अंतिम लक्ष्य rustc और cargo को compile करने के बाद, उन्हीं self-compiled rustc/cargo से canonical rustc/cargo को फिर से compile करने की प्रक्रिया बनाना है
  • यह project अब तक किए गए कामों में सबसे कठिन है, और पूरा होने की संभावना पर संदेह होने के बावजूद कोशिश जारी रखने का रुख है

1 टिप्पणियां

 
GN⁺ 2024-08-26
Hacker News की रायें
  • अगर Rust को बूटस्ट्रैप करना हो, तो शायद मैं पूरे Rust से कम फीचर वाला proto-Rust C में बनाऊंगा, और उसी proto-Rust से पूरा Rust compiler लिखूंगा
    उदाहरण के लिए proto-Rust में borrow checker नहीं होगा, macro support सीमित या बिल्कुल नहीं होगा, शायद memory free भी न करे, और अच्छा code generate करना भी जरूरी नहीं होगा
    असल में यह Rust syntax वाला C जैसा होगा, लेकिन Rust enthusiasts के नज़रिए से, यह इस project के लक्ष्य “C syntax वाला C” में Rust compiler लिखने से बेहतर लगता है
    जानना चाहूंगा कि यह रास्ता क्यों नहीं चुना गया

    • संदर्भ के लिए, मौजूदा प्रमुख non-Rust Rust compiler mrustc में भी पहले से borrow checker नहीं है
      borrow checker हटाने से सही programs टूटते नहीं, बस गलत programs बड़ी संख्या में compile हो सकेंगे
      mrustc का मुख्य उपयोग rustc को compile करना है, और हमें पहले से पता है कि rustc borrow checker errors के बिना खुद को compile कर सकता है, इसलिए यह ठीक है
    • Mozart/Oz में सच में ऐसा ही किया गया था। Scala में लिखा हुआ proto-Oz compiler है, और उससे Oz में लिखे असली compiler को compile किया जाता है
      क्योंकि Scala compiler inefficient code बनाता है, बाद में असली compiler को उसी से फिर से compile किया जाता है
      इससे अंत में अच्छा code बनाने वाला efficient असली compiler मिल जाता है, और यह प्रक्रिया language के standard build में शामिल है
      https://github.com/mozart/mozart2
    • तो आखिर में आप दो compilers इस्तेमाल कर रहे होंगे; extra काम के अलावा वास्तव में क्या मिलता है, समझ नहीं आता
  • शौकिया तौर पर Rust में C compiler बना रहा हूं, और मजाक में उसे Small C Compiler कहता हूं क्योंकि Rust जाहिर तौर पर C से ज्यादा heavy है। यह “Tiny C Compiler” की parody है
    backend के रूप में Cranelift इस्तेमाल करता हूं, लेकिन पूरा compiler structure कई traits के जरिए plug-and-replace और hack करने में आसान बनाने की कोशिश कर रहा हूं
    जब तक यह printf("%s", "Hello World!") handle करने जितना कुछ हद तक काम न करने लगे, open source में release करने का इरादा नहीं है
    preprocessor और parser implement करने की कोशिश की थी, और कुख्यात typedef problem की वजह से rust-peg और HimeCC में भी शामिल हुआ
    industry में typedef context बनाए रखने के लिए symbol table इस्तेमाल करने की बात पता है, लेकिन उसमें नीचे वाले type को पढ़ न पाने की सीमा थी। academic समाधान क्या है, यह जानना चाहता हूं; दिमाग में सिर्फ transaction memory आती है
    अगर कुछ उपयोगी हुआ तो आखिरकार release कर दूंगा

    • ऐतिहासिक रोचकता के लिए, Dr. Dobbs Journal ने 1980 में Ron Cain का Small C Compiler नाम का program छापा था
      बाद में James Hendrix ने इसे ज्यादा complete implementation वाली किताब में expand किया। बचपन में CompUSA के discount rack पर यह किताब मिल गई, जिसकी वजह से मैंने C सीखी, और किताब आज भी मेरे पास है
      https://archive.org/details/dr_dobbs_journal_vol_05_201803/p...
      https://www.amazon.com/Small-Compiler-Language-Theory-Design...
    • नाम “SCC” नहीं बल्कि “SmaCC” रखा होता तो अच्छा लगता
  • सच में शानदार है, और दिलचस्प बात यह है कि इसी तरह की bootstrapping problem hardware में भी होती है
    computers क्या बनाते हैं? पहले बने हुए computers और उन पर चलने वाला software। जितना सोचें, उतना दिलचस्प लगता है

    • वही bootstrapping problem हर चीज में है। सड़कें क्या बनाता है? construction equipment। लेकिन जब सड़क अभी है ही नहीं, तो उस construction equipment को work site तक कैसे ले जाएं?
      कुछ महीने पहले construction project materials delivery/fulfillment करने वाले startup में काम करने वाले एक व्यक्ति से मिला था
      ऐसे काम में Amazon जैसी general delivery से अलग expertise चाहिए, क्योंकि materials अक्सर अजीब या dangerous physical properties वाले होते हैं, और delivery site के पास अभी address भी नहीं होता, यह भी आम है
      हल किया जा सकता है, लेकिन आधुनिक delivery companies की सामान्य capabilities से आगे की specialization चाहिए लगती है
    • एक ऐसी company में काम किया था जो datacenters बनाती थी, और हम software को इस स्तर तक बनाना चाहते थे कि एक laptop से पूरा datacenter start किया जा सके
      वजह यह थी कि European companies के साथ काम करते हुए regulators को यह साबित करना था कि कोई backdoor नहीं है
      यह बहुत दिलचस्प लेकिन बेहद कठिन problem थी, और हमारी team केवल indirectly जुड़ी थी, लेकिन हमने data को ऐसे proxy के जरिए pass कराने पर काम किया जो यह ensure करे कि सभी data auditable हों और जो नहीं भेजना चाहिए वह न भेजा जाए
      project खत्म होने से पहले company छोड़ दी, और बाद में सुना कि बहुत कठिन होने के कारण इसे बंद कर दिया गया
    • पुराने Cray-1 के assembly octal opcodes या IBM System/360 के word opcodes देखें, तो पता चलता है कि उन्हें आश्चर्यजनक रूप से इतना simple बनाया गया था कि इंसान opcode bytes सीधे लिखकर हाथ से assemble कर सके
      बाद में x86 बड़े budget या बड़े buyers के बिना आया, और assembly को जितना संभव हो efficient और dense design किया गया
      नतीजा यह हुआ कि दूसरी machines में आसानी से मिल सकने वाली properties खो गईं
    • ऐसी bootstrapping projects और reproducible builds की सबसे शानदार बातों में से एक यही है
      theoretical रूप से, सिर्फ individual parts से बहुत simple computer खुद बनाया जा सकता है
      वह बड़ा, inefficient और बेहद slow होगा, लेकिन उसे किसी खास instruction set architecture का पालन करने वाला बनाया जा सकता है, और उस पर bootstrap program build किया जा सकता है
      फिर आप दावा कर सकते हैं कि पूरी तरह समझ में आने वाले खराब computer से मिला result उस modern hardware से मिले result जैसा ही है जिस पर आप पूरी तरह भरोसा नहीं करते
    • मानव सभ्यता के स्तर पर भी यह एक दिलचस्प विचार है। अगर मानवता somehow आज के समय से stone age में लौट जाए, तो क्या हम फिर से मौजूदा स्तर तक बना पाएंगे?
      यह भी एक तरह की bootstrapping problem है। उदाहरण के लिए, आज के oil reserves 100 साल पहले की तुलना में extract करना ज्यादा कठिन हैं; सोचता हूं कि क्या हम वहां तक फिर से bootstrap कर पाएंगे
  • बूटस्ट्रैपिंग के फायदे समझाने वाला high-level rationale ढूँढने के लिए लिंक 4 बार follow करना पड़ा, इसलिए थोड़ा irritate हुआ
    उम्मीद थी कि title में “Why” वाला हिस्सा यही cover करेगा
    https://bootstrappable.org/benefits.html

    • बूटस्ट्रैपिंग क्यों महत्वपूर्ण है, यह समझाना मुश्किल हो सकता है। इसलिए मैंने अपने बूटस्ट्रैपिंग compiler README में भी “Why?” सेक्शन जोड़ा है
      security एक बड़ा कारण है और bootstrappable team मुख्य रूप से इसी पर जोर देती है
      trusting trust problem और हाल की xz backdoor जैसी attacks से बचने के लिए, हर चीज़ को pure source code से bootstrap कर पाना चाहिए
      वे pre-generated files तक हटा देते हैं ताकि सिर्फ हाथ से लिखी और audit की जा सकने वाली चीज़ों पर निर्भर रहें। उदाहरण के लिए Python bootstrapping काफी जटिल हो जाता है क्योंकि source में Python scripts से generated code शामिल होता है
      मेरी दिलचस्पी इसके बजाय cultural preservation वाले पहलू में ज्यादा है। Arctic World Archive जैसी जगहों पर future archaeologists के लिए modern media preserve करना चाहता हूँ, लेकिन अगर उसे decode करने का तरीका न हो तो उसका कोई मतलब नहीं
      specifications preserve किए जा सकते हैं, लेकिन उनसे यह उम्मीद नहीं की जा सकती कि वे x265 और जरूरी सारी चीज़ें scratch से implement कर लेंगे। binaries preserve करने पर हजार साल पुराने hardware को चलाना या हजार साल पुराने CPU को virtualize करना पड़ेगा
      एक simple Lisp definition और उसके ऊपर चलने वाला code दिया जा सकता है, लेकिन basic Lisp में x265 कौन implement करेगा। यह realistic नहीं है
      इसलिए मेरे project में मैंने एक simple virtual machine बनाई, और उसके ऊपर C को bootstrap किया
      इसे current architecture ही नहीं, future या alien architectures पर भी बहुत आसानी से port किया जा सकता है। future archaeologists या alien civilization एक दिन में VM implement कर सकते हैं, उस पर C bootstrap चला सकते हैं, फिर ffmpeg आदि compile करके हमारा media decode कर सकते हैं
      कोई black box नहीं है, सब कुछ debug किया जा सकने वाला, audit किया जा सकने वाला और open, हाथ से लिखा source code है
      https://github.com/ludocode/onramp?tab=readme-ov-file#why-bo...
      https://en.wikipedia.org/wiki/Arctic_World_Archive
  • थोड़ा confusing है। article के बीच में जाकर ही यह वजह आती है कि title वाली journey शुरू क्यों की गई; core बात यह है कि bootstrap chain में C++ आने तक bootstrap लगभग खत्म हो चुका होता है, इसलिए उससे पहले Rust इस्तेमाल करना चाहें तो भी तरीका नहीं है
    इसलिए लगता है कि उद्देश्य यह है कि C में, खास तौर पर ऐसे system पर जहाँ अभी कोई useful tools नहीं हैं, TinyCC से bootstrap किया जा सकने वाला Rust compiler हो तो अच्छा होगा
    लेकिन यह शुरुआती premise से contradict करता है। rustc में 1.80.0 को 1.79.0 से, 1.79.0 को 1.78.0 से compile किया जाता है और ऐसे ही 0.7 तक पीछे जाया जा सकता है, और उस समय का compiler OCaml में लिखा गया था
    साथ ही यह भी कहा गया था कि Guile से OCaml compiler को successfully compile करने वाला project है, और Guile interpreter C में लिखा है
    तो लेखक जो C++-free path चाहता है, वह पहले से मौजूद है; बस यह rustc team द्वारा रोजमर्रा में इस्तेमाल किया जाने वाला path नहीं है
    आखिर motivation clear नहीं है। क्या वे बेहतर C-based bootstrap process बनाना चाहते हैं, या उसे rustc का routine bootstrap तरीका बनाना चाहते हैं, C++ step क्यों हटाना चाहते हैं, C step को क्यों prefer करते हैं—समझ नहीं आया
    सिर्फ करने का मन है इसलिए कर रहे हैं तो ठीक है, लेकिन काफी लंबा article पढ़ने के बाद भी इसके अलावा उद्देश्य समझ नहीं आया

    • Rust को Guile और Rust 0.7 compiler से bootstrap करना technically possible तो है, लेकिन Rust compiler को करीब 100 बार फिर से compile करना पड़ेगा
      हर step में कई घंटे लगते हैं, और 1.80 को 1.79 चाहिए, 1.79 को 1.78 चाहिए—इस तरह 0.7 तक कोई भी step skip नहीं किया जा सकता
      पूरी तरह automated होने पर भी इस bootstrap में महीनों लग सकते हैं
      इसके अलावा, मेरी जानकारी में शुरुआती rustc versions सिर्फ LLVM output करते थे, इसलिए LLVM compile करने के लिए फिर भी C++ compiler bootstrap करना पड़ेगा
      अगर C++ compiler है, तो सीधे mrustc compile कर सकते हैं। अभी mrustc सिर्फ rustc 1.54 तक support करता है, इसलिए फिर भी लगभग 35 versions से होकर compile करना पड़ेगा
      यह पूरा process practical नहीं है। Dozer का goal एक छोटा C compiler bootstrap करना, Dozer compile करना, और फिर latest rustc को सीधे compile करना है
      इससे C++ या intermediate steps bootstrap किए बिना सीधे Rust मिल सकता है
  • अगर GCC 4 और binutils को उनके original build script से अलग किया जा सके, तो लगता है list का करीब आधा हिस्सा काटा जा सकता है
    वहाँ मौजूद कई items बस autoconf-family और उसकी dependencies को बार-बार rebuild करने के लिए हैं
    https://github.com/fosslinux/live-bootstrap/blob/master/part...

  • point ठीक से समझ नहीं आया। target machine पर चलने वाली नई binary बनाने के लिए rustc को target architecture support करना होगा
    अगर आपने वह support rustc में add कर दिया है, तो बस rustc से खुद को build करवा लें

    • नई architecture support से ज्यादा, मुद्दा कहीं छोटा और audit किया जा सकने वाला bootstrap process रखने का है
  • कभी-कभी Scheme में C++ interpreter या compiler लिखने की कल्पना करता हूँ
    Scheme से सीधे current GCC तक जाना बहुत बड़ा shortcut हो सकता है
    लेकिन आम धारणा के हिसाब से C++ compiler लिखना लगभग असंभव के करीब माना जाता है। फिर भी सीखने में मदद मिल सकती है

  • सब-असेंबलर से लेकर पूरे stack को देखें, तो क्या यह trusting trust समस्या को बाइपास करने का तरीका हो सकता है?
    https://www.cs.cmu.edu/~rdriley/487/papers/Thompson_1984_Ref...

    • यह तभी संभव है जब हर चीज़ का audit किया जाए और पूरी प्रक्रिया खुद चलाई जाए
      फिर भी https://en.m.wikipedia.org/wiki/Underhanded_C_Contest जैसी चीज़ें हैं, और उनमें से कुछ entries ऐसी लगती हैं जिन्हें मैं audit करता तो भी शायद चूक जाता
    • क्या वही मुख्य बात नहीं थी?
  • जब मैं थोड़ा C सीख रहा था, तो मैंने देखा था कि लोग C में C++ जैसी चीज़ें कैसे करते हैं, और objects, exceptions, concurrency जैसी implementations देखीं
    अगर mrustc C++ में लिखा है, तो क्या ऐसे C++-style C primitives का इस्तेमाल करके काम करने वाले C++ code को C में port करना ज़्यादा आसान नहीं हो सकता?
    C++ और C के बीच मजबूत interoperability का इस्तेमाल करके थोड़ा-थोड़ा करके move करने का तरीका भी संभव लगता है
    बेशक, मुझे पता है कि यह कई pitfalls वाला कठिन porting काम है। बस यह याद रखना चाहिए कि तुलना जिस चीज़ से है, वह C में Rust compiler को नए सिरे से लिखना है
    पुराने समय के C++ to C compilers भी याद आते हैं। पता नहीं वे अभी भी मौजूद हैं या नहीं
    आज भी Rust to C/C++ और C++ to human-readable C compiler उपयोगी लगते हैं। क्योंकि इससे एक तरफ़ के safety benefits और दूसरी तरफ़ के tool ecosystem को जोड़ा जा सकता है