잡학다식/IT 컬럼

C를 버리고 Rust로: tmux 전체 코드를 수작업으로 옮긴 개발자의 6개월 여정

파파누보 2025. 7. 4. 18:23
728x90
반응형

 

tmux는 터미널 사용자에게 강력한 세션 관리 기능을 제공하는 도구입니다. 하지만, 그 핵심 코드는 수십 년간 C 언어로 작성돼 왔습니다. 이 오래된 코드를 더 안전하고 유지보수하기 쉬운 Rust로 옮긴다면 어떨까요?

이 블로그에서는 한 개발자가 직접 tmux의 전체 C 코드를 Rust로 포팅하면서 겪은 기술적 도전과 해결 과정을 정리했습니다. 자동화 툴의 한계, 빌드 구조 재설계, 메모리 오류 수정, yacc 파서 변환 등 현실적인 문제들과 그 해결책을 통해, Rust로의 실전 포팅 과정이 어떤 모습인지 생생히 보여줍니다.

반응형

tmux-rs 프로젝트 개요

tmux-rs는 약 6만7천 줄의 tmux C 코드를 약 8만1천 줄의 Rust 코드로 이식한 프로젝트입니다. 개발자는 개인 취미로 이 작업을 진행했으며, 자동 변환보다는 수작업 리팩토링을 통해 더 나은 코드 품질을 추구했습니다. 최종 목표는 완전한 safe Rust 기반의 tmux 복제본입니다.

자동 변환 툴 C2Rust의 한계

처음에는 C2Rust를 사용해 자동 이식을 시도했습니다. 하지만, 다음과 같은 문제가 있었습니다:

  • 코드 크기가 3배 이상 증가
  • 상수명 손실, 불필요한 형 변환
  • 가독성과 유지보수성의 극단적 저하

결국 C2Rust는 프로토타입 검증에만 활용하고, 본격적인 포팅은 직접 수작업으로 진행했습니다.

빌드 시스템 재설계

  • 초기에는 Rust 라이브러리를 기존 C 바이너리에 링크
  • 이후 Rust가 주가 되면서, C 코드를 라이브러리로 Rust 바이너리에 링크
  • build.sh, build.rs를 통해 점진적 빌드 확인 가능
  • 구조체 시그니처 누락, 헤더 선언 오류 등을 함수 단위로 단계적 해결

번역 중 마주친 주요 버그 사례

1. 포인터 반환 오류
암시적 선언으로 인해 함수 반환값의 상위 바이트가 잘려 오류 발생. → 명시적 프로토타입 선언으로 해결.

2. 구조체 필드 타입 불일치
C에서는 포인터, Rust에서는 정수로 해석해 메모리 오프셋 불일치 발생. → 구조체 정의 일치시켜 해결.

C 고유 패턴을 Rust로 포팅한 방식

  • Raw Pointer 사용: 안전성 위반을 피하기 위해 대부분의 포인터는 *mut, *const로 처리
  • goto 문 변환: labeled block + break 또는 labeled loop + continue로 치환
  • 매크로 기반 자료구조: red-black 트리 및 링크드 리스트를 trait과 iterator로 재현
  • yacc 파서 → lalrpop 변환: yacc 문법을 Rust용 lalrpop으로 이식 + C lexer 연동용 어댑터 작성

개발 도구 및 환경

  • neovim 매크로: 반복 작업 자동화 (예: ptr == NULL → ptr.is_null())
  • 자동화 도구(Cursor): 일부 도움은 되었지만, 코드 품질 저하로 리뷰 부담 증가
  • 생산성 측면: 매뉴얼 중심의 작업이 더 신뢰성 있었음

728x90

이 프로젝트는 단순한 코드 변환 작업을 넘어서, C에서 Rust로의 이식이 어떤 기술적 고려와 노력을 요구하는지 잘 보여줍니다. 자동화 툴이 초기 실험에는 유용할 수 있지만, 결국 실전에서는 수작업 리팩토링이 필요하다는 교훈도 얻을 수 있죠.

아직은 unsafe Rust 기반이지만, 점차 safe Rust로의 전환을 목표로 하고 있으며, 이 과정에 관심 있는 Rust 개발자들의 피드백과 협업이 매우 중요합니다.

tmux나 Rust 시스템 프로그래밍에 관심 있다면, 이 프로젝트는 실전 기술 학습의 훌륭한 출발점이 될 것입니다.

https://richardscollin.github.io/tmux-rs/

 

Introducing tmux-rs

A Rust port of tmux

richardscollin.github.io

728x90
반응형