- Cpp2Rust clang AST आधारित syntax-driven translator है, जो C++ input को अपने-आप पूरी तरह सुरक्षित Rust code में बदलता है
- translation प्रक्रिया में C++ file को clang से parse करके AST बनाया जाता है, AST traverse करते हुए Rust code को string के रूप में generate किया जाता है, और फिर
rustfmt से एक single .rs file output की जाती है
- default reference counting model है, और debugging व performance comparison के लिए
--model=unsafe से unsafe Rust generation भी संभव है
- generated code
libcc2rs runtime library पर निर्भर करता है, और C pointers को null, arithmetic, aliasing model करने वाले Ptr<T> में convert किया जाता है
- पूरे program translation के लिए
compile_commands.json की जरूरत होती है, और CMake project इसे CMAKE_EXPORT_COMPILE_COMMANDS=ON flag से generate कर सकते हैं
C++ से सुरक्षित Rust में automatic conversion
Translation pipeline
- input C++ file को पहले clang से parse करके AST generate किया जाता है
- इसके बाद AST को traverse करते हुए Rust code को string के रूप में output किया जाता है
- जरूरत पड़ने पर
libcc2rs runtime library calls insert की जाती हैं
- इसका example raw pointer semantics handling है
- अंत में
rustfmt का उपयोग करके Rust code को एक single .rs file में व्यवस्थित किया जाता है
Safe Rust और unsafe Rust model
- default behavior reference counting model का उपयोग करता है, और पूरी तरह सुरक्षित Rust output generate करता है
- unsafe Rust generator भी उपलब्ध है
- command-line argument
--model=unsafe है
- इसका उपयोग debugging और performance comparison के लिए है
libcc2rs runtime library
- generated code translation प्रक्रिया को सरल बनाने के लिए design की गई runtime library पर निर्भर करता है
- C pointers को
libcc2rs द्वारा उपलब्ध कराए गए Ptr<T> type में convert किया जाता है
Ptr<T> C pointer semantics को model करता है
- null
- pointer arithmetic
- aliasing
- Rust का borrow checker checked runtime operations के जरिए संतुष्ट होता है
Build और execution flow
- Ubuntu dependency installation example में
libclang-22-dev, clang++-22, ninja-build, cmake, ruff शामिल हैं
- build
cmake -GNinja .., ninja, ninja check क्रम में किया जाता है
- single-file translation command इस रूप में है
./build/cpp2rust/cpp2rust --file=<file>.cpp -o=<file>.rs
- unsafe Rust generate करने के लिए इसे ऐसे चलाएं
./build/cpp2rust/cpp2rust --file=<file>.cpp -o=<file>.rs --model=unsafe
Minimal example और whole-program translation
hello.cpp में printf("hello world\n") example Rust के println!("hello world") को शामिल करने वाले code में convert होता है
- converted
hello.rs को इस तरह compile और run किया जाता है
rustc hello.rs -L ../libcc2rs/target/debug
./hello
- whole-program translation के लिए
compile_commands.json की जरूरत होती है
- CMake में नीचे दिए flag से
compile_commands.json generate किया जाता है
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ..
- whole-program translation command इस रूप में है
./build/cpp2rust/cpp2rust --dir=<dir> -o <output>.rs
<dir> वह directory होनी चाहिए जिसमें compile_commands.json मौजूद हो
Test commands
- पूरी test suite
ninja check से चलती है
- unit tests
ninja check-unit से चलते हैं
libcc2rs unit tests ninja check-libcc2rs से चलते हैं
libcc2rs-macros unit tests ninja check-libcc2rs-macros से चलते हैं
- जानबूझकर बदलाव करने के बाद expected output regenerate करने के लिए
REPLACE_EXPECTED=1 ninja check-unit का उपयोग करें
1 टिप्पणियां
Lobste.rs की टिप्पणियां
इस साल फरवरी में Dan Wallach की presentation सुनी थी, जिसमें उन्होंने DARPA के TRACTOR(Translating All C to Rust) project को introduce किया था [1] [2] [3]
बताया गया कि research program की testing और evaluation MIT Lincoln Laboratory की team कर रही है
मेरी जानकारी में यह अभी research stage में है, लेकिन इस topic में मेरी काफी रुचि है और यह देखना काफी दिलचस्प होगा कि ऐसे tools और ideas किस तरह सामने आते हैं
लगता है कि memory management से आने वाले कई “छोटे-मोटे” bugs को यह सच में खत्म कर सकता है
[1] https://www.darpa.mil/research/programs/translating-all-c-to-rust
[2] https://github.com/DARPA-TRACTOR-Program
[3] https://ll.mit.edu/r-d/projects/…
दिलचस्प है। अगर authors ने इससे convert किए हुए library या app demos के एक-दो example दिखाए होते, जिन्हें वे खुद भी interesting मानते हों, तो बहुत अच्छा होता
मसलन https://github.com/Cpp2Rust/cpp2rust-testsuite/… देखें, तो यह safe Rust हो सकता है, लेकिन इसे idiomatic Rust कहना निश्चित रूप से मुश्किल है
मुझे ठीक से समझ नहीं आ रहा कि conversion step की जरूरत क्यों है। अगर memory-safe Rust में convert करने लायक पर्याप्त जानकारी है, तो क्या C++ को भी static analysis से safe guarantee करने लायक जानकारी नहीं होनी चाहिए?
widely deployed software security vulnerabilities में करीब 70% C और C++ जैसी languages के memory safety bugs से आती हैं, और static analysis, sanitizers, hardware isolation जैसे mitigations पर दशकों के investment के बावजूद attackers अब भी unsafe memory operations का फायदा उठाते हैं
लंबे समय में promising solution मौजूदा C++ codebases को Rust जैसी memory-safe languages में ले जाना है, लेकिन manual तरीके से करना बहुत महंगा और error-prone है, ऐसा समझाया गया है
Cpp2Rust दावा करता है कि यह C++ programs को functionally equivalent और memory-safe Rust code में automatically convert कर सकने वाला पहला system है
performance का कुछ हिस्सा security के बदले trade करते हुए, C++ के unrestricted aliasing references और Rust के ownership model के बीच fundamental mismatch को runtime ownership और mutability checks insert करके solve करता है, ताकि semantics preserve रहें और safety guarantee हो
dynamic check overhead कम करने के लिए Rust code के लिए source-to-source optimizations भी बनाए गए हैं, और redundant ownership operations हटाकर खोई हुई performance का काफी हिस्सा recover किया जाता है
इसलिए motivation सिर्फ safety prove करना नहीं, बल्कि Rust में port करना और आगे की development को Rust में ले जाना आसान बनाना है
ऐसे projects का idea idiomatic Rust में आगे refactor करने के लिए एक starting point बनाना है, जिससे code को analyzable बनाया जा सके
उम्मीद है कि converted code से runtime checks या unsafe हिस्से भी हटाए जा सकेंगे
कोई कह सकता है कि C++ को “Rust-जैसे shape” में refactor करके उसी तरह analyzable क्यों न बना दिया जाए, लेकिन C++ की semantics अलग है जो ज्यादा flexibility allow करती है, इसलिए analyze करने वाले paths exponentially बढ़ सकते हैं या static analysis ambiguous dead ends में फंस सकता है
आपको वादा करना होगा कि आप static analyzer के लिए मुश्किल काम नहीं करेंगे और edge cases का फायदा नहीं उठाएंगे; इसके लिए अधिक restricted semantics और extra annotations वाला C++ dialect बनाया जा सकता है
Circle/Safe C++ ने संभावना दिखाई थी, लेकिन C++ WG ने उस direction को strongly reject कर दिया, इसलिए विकल्प यही बचता है कि unsupported Rust-जैसा C++ dialect खुद इस्तेमाल करें या बस Rust इस्तेमाल करें
अगर input code खुद ही unsafe हो तो यह exactly कैसे काम करता है?