- Cpp2Rust는 clang AST 기반의 구문 주도 번역기로, C++ 입력을 자동으로 완전히 안전한 Rust 코드로 변환함
- 번역 과정은 clang으로 C++ 파일을 파싱해 AST를 만들고, AST를 순회하며 Rust 코드를 문자열로 생성한 뒤 rustfmt로 단일 .rs 파일을 출력함
- 기본값은 참조 카운팅 모델이며, 디버깅과 성능 비교를 위해 --model=unsafe로 unsafe Rust 생성도 가능함
- 생성된 코드는 libcc2rs 런타임 라이브러리에 의존하며, C 포인터는 null, 산술, 별칭을 모델링하는 Ptr<T>로 변환됨
- 전체 프로그램 번역에는 compile_commands.json이 필요하며, CMake 프로젝트는 CMAKE_EXPORT_COMPILE_COMMANDS=ON 플래그로 생성할 수 있음
C++에서 안전한 Rust로 자동 변환
번역 파이프라인
- 입력 C++ 파일을 먼저 clang으로 파싱해 AST를 생성함
- 이후 AST를 순회하며 Rust 코드를 문자열로 출력함
- 필요한 경우 libcc2rs 런타임 라이브러리 호출을 삽입함
- 예시는 raw pointer semantics 처리임
- 마지막으로 rustfmt를 사용해 Rust 코드를 단일 .rs 파일로 정리함
안전한 Rust와 unsafe Rust 모델
- 기본 동작은 참조 카운팅 모델을 사용하며, 완전히 안전한 Rust 출력을 생성함
- unsafe Rust 생성기도 제공됨
- 명령행 인자는 --model=unsafe
- 용도는 디버깅과 성능 비교임
libcc2rs 런타임 라이브러리
- 생성된 코드는 번역 과정을 단순화하기 위해 설계된 런타임 라이브러리에 의존함
- C 포인터는 libcc2rs가 제공하는 Ptr<T> 타입으로 변환됨
- Ptr<T>는 C 포인터 의미를 모델링함
- Rust의 borrow checker는 검사된 런타임 연산을 통해 만족함
빌드와 실행 흐름
- Ubuntu 의존성 설치 예시는 libclang-22-dev, clang++-22, ninja-build, cmake, ruff를 포함함
- 빌드는 cmake -GNinja .., ninja, ninja check 순서로 진행함
- 단일 파일 번역 명령은 다음 형태임
./build/cpp2rust/cpp2rust --file=<file>.cpp -o=<file>.rs
- unsafe Rust를 생성하려면 다음처럼 실행함
./build/cpp2rust/cpp2rust --file=<file>.cpp -o=<file>.rs --model=unsafe
최소 예제와 전체 프로그램 번역
- hello.cpp의 printf("hello world\n") 예제는 Rust의 println!("hello world")를 포함한 코드로 변환됨
- 변환된 hello.rs는 다음처럼 컴파일하고 실행함
rustc hello.rs -L ../libcc2rs/target/debug
./hello
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ..
./build/cpp2rust/cpp2rust --dir=<dir> -o <output>.rs
- <dir>는 compile_commands.json이 들어 있는 디렉터리여야 함
테스트 명령
- 전체 테스트는 ninja check로 실행함
- 단위 테스트는 ninja check-unit로 실행함
- libcc2rs 단위 테스트는 ninja check-libcc2rs로 실행함
- libcc2rs-macros 단위 테스트는 ninja check-libcc2rs-macros로 실행함
- 의도적으로 변경한 뒤 예상 출력을 재생성하려면 REPLACE_EXPECTED=1 ninja check-unit을 사용함