GN⁺: Fish 4.0: Theseus의 Fish
(fishshell.com)#9512 - Rewrite It in Rust
- Fish 쉘이 Rust로 재작성됨. C++ 코드가 전혀 없고 거의 100% 순수 Rust로 구성
- 약 2년 전 Fish를 C++에서 Rust로 전환하는 PR(#9512)을 열었음
- Fish는 과거에도 C에서 C++로 전환한 경험이 있지만, Rust로의 전환은 훨씬 더 큰 프로젝트였음
C++에서의 문제점
- 도구 및 컴파일러 차이: C++의 도구는 좋지 않으며, 최신 C++ 표준을 채택하는 것은 패키저와 기여자들에게 복잡함을 초래함.
- 스레드 안전성: Fish의 내부 명령어 실행은 현재 직렬로 이루어지며, 비동기 프롬프트나 비차단 완성 기능을 추가하기 위해서는 병렬 처리가 필요함.
- 언어의 복잡성: C++의 헤더 파일, 템플릿, 문자열 처리 등이 복잡하고 안전하지 않음.
- 커뮤니티: C++는 많은 기여자를 끌어들이지 못함.
- 의존성 문제: 특정 C 라이브러리(curses)의 불안정성과 빌드 문제로 인해 번거로움이 있었음
Rust 선택 이유
- 재미와 흥미: Fish는 취미 프로젝트로, 재미있고 흥미로운 언어가 필요함. Rust는 기여자들에게 더 매력적임.
-
훌륭한 도구:
rustup
으로 간단히 컴파일러를 설치 가능하며, 오류 메시지가 명확함 -
에르고노믹스: 명시적인
use
시스템과Option
및Result
같은 안전한 기능 제공 - 좋은 언어 설계: Rust의 포인터와 옵션 시스템은 C++보다 훨씬 안전함
- 병렬 처리 지원: Rust의 Send와 Sync는 안전한 병렬 처리를 가능하게 함.
- 의존성 관리: YAML, JSON 등 외부 형식 지원을 쉽게 추가할 수 있음
플랫폼 지원
- 대부분의 주요 플랫폼(macOS, Linux, BSD 등)이 지원되며, Windows의 네이티브 지원은 목표가 아님
- Fish는 UNIX 중심의 쉘로, Windows 환경보다는 UNIX API와 스크립팅 언어에 초점을 맞춤
포팅 과정
- Fish는 "Theseus의 물고기" 방식으로 C++에서 Rust로 단계적으로 전환함. 컴포넌트를 하나씩 Rust로 이전하며, C++와 Rust가 공존하도록 설정
- 테세우스의 배(Ship of Theseus) : “한 배의 모든 나무 판자를 새것으로 교체한다면, 그것은 여전히 같은 배인가?”
- FFI 활용: autocxx를 사용하여 C++와 Rust 간의 바인딩을 생성하고, 한 번에 하나의 컴포넌트를 포팅함.
- 대규모 포팅: 특정 부분(예: I/O 처리 등)은 단독으로 이전하여 복잡한 FFI 코드를 줄임
-
도구 개선: 포팅 과정에서 Rust와 C++ 간 상호 운용성 문제를 해결하기 위해
autocxx
를 커스터마이징
타임라인
- 2023년 1월: 초기 PR 열림
- 2024년 1월: C++ 코드 완전히 제거
- 2024년 12월: Fish 4.0 베타 버전 출시
Rust와의 마찰
-
이식성 문제: Rust의
#[cfg(...)]
접근 방식이 낮은 수준에서 시스템 차이를 처리하는 데 비효율적임 - 로컬라이제이션: Rust의 포맷 문자열은 컴파일 시간에 확인되지만 번역 불가능
- 빌드 시간: LTO와 디폴트 릴리스 빌드 사용으로 인해 빌드 시간이 길어질 수 있음
- 포팅 과정에서 몇 가지 실수를 저질렀지만, 대부분 쉽게 해결됨.
주요 성과
- curses 제거: terminfo 데이터베이스를 Rust crate로 대체하여 글로벌 상태 및 빌드 문제 해결
-
단일 실행 파일: 모든 종속성을 포함한 Fish 바이너리 생성 가능
- Fish 패키지를 자체 설치 가능하게 만들어, 사용자가 쉽게 사용할 수 있게 함
- 성능 개선: 메모리 사용 최적화 및 새로운 기능 추가 용이
제한점
- CMake를 완전히 제거하지 못함
- Cygwin 지원 중단: Rust 타겟이 없기 때문
- Windows에서는 여전히 WSL을 통해서만 실행 가능
현재와 미래
- Fish 4.0은 성공적으로 포팅되었으며, 성능이 향상됨.
- Fish는 여전히 UNIX 셸로, Rust로의 전환을 통해 새로운 기능을 추가할 수 있게 됨.
- 이제 Rust로 완전히 전환된 코드베이스를 보유하고 기존보다 유지 보수 및 기능 추가가 더 쉬워짐. Rust의 장점을 활용하여 새로운 기능 추가 가능
- 이번 전환은 성공적으로 완료되었으며, 기여자와 사용자 모두에게 긍정적인 영향을 미침
fish의 사용성이 부럽지만 호환성, 성능 등의 문제 때문에 zsh를 최대한 fish와 비슷하게 설정하여 사용하고 있습니다. 바뀐 fish는 어떨지 기대되네요 👀
Hacker News 의견
-
Fish 팀에 축하를 전하며, 프로젝트의 세부 사항이 흥미로움. C++에서 Rust로 완전히 전환한 가장 큰 프로젝트인지 궁금함. 다른 프로젝트에 유용한 교훈이 될 수 있음
- Fish는 C++과 Rust의 하이브리드 프로그램으로 출시되지 않았음. 최종 테스트 단계가 완료되지 않았기 때문임
- C++ 기능을 Rust에 추가하는 동기를 이해하지 못한 사람들이 있지만, 이는 좋은 사례 연구가 될 수 있음
- 새로운 Rust 코드를 C++ 코드베이스에 작성할 수 있으면 좋겠다는 의견이 있음
-
Rust의 주요 불만 사항은 버전 감지 지원임. 기능 감지가 배포판, 웹 브라우저, 컴파일러에 더 나음
- 버전/이름 감지는 Chrome과 IE가 Mozilla인 척하는 이유이며, Clang이 GCC인 척하는 이유임. 기능 감지는 이러한 문제를 일으키지 않음
-
포트의 목표 중 하나는 CMake 제거였으나 실패함. Cargo는 빌드에는 훌륭하지만 설치에는 단순함. Fish는 많은 스크립트와 문서가 있어 Cargo의 사용 사례에 맞지 않음
- Cargo가 이러한 사용 사례로 확장되기보다는 다른 도구가 구현되기를 선호함
-
몇 년 전 bash에서 zsh로 전환했을 때 만족했으나, 새로운 컴퓨터에서 fish를 사용해보니 zsh가 번거롭고 구식으로 느껴졌음. fish를 몇 주간 사용해볼 것을 추천함
-
Cygwin을 지원하지 않는 것이 아쉬움. Rust가 Cygwin을 빌드 대상으로 지원하기를 희망함
-
Fish 팀의 노력에 감탄하며, 프로젝트가 어떻게 발전할지 기대됨
-
배포 패키저들이 Rust-fish를 Debian 지침에 따라 패키징하는 것이 얼마나 수월한지 궁금함
-
Fish 팀에 축하를 전하며, 최고의 쉘이 더 나아졌다는 의견임. 프로젝트의 태그라인을 "Finally, a shell for the 00s!"로 업데이트하는 것이 어떨지 제안함
-
zsh에서 Fish로 전환한 후 설정이 간단해졌으며, Fish가 기대대로 작동하여 다시 변경할 생각이 없음
-
cfg!
매크로는 true/false로 컴파일되므로,if
가드 내의 코드는 컴파일되어야 함.my_feature
없이 컴파일하면 실패할 수 있음 -
Fish는 자동 완성 및 구문 강조를 위해 스레드를 사용하며, 언어에 동시성을 추가하는 장기 프로젝트가 있음