2P by GN⁺ | ★ favorite | 댓글 1개
  • fish-shell의 Rust 포트는 “대부분” 완료된 상태이며, 계산 방식에 따라 C++ SLOC 제거 기준 60% 에서 Rust SLOC 대 C++ SLOC 기준 74% 까지 진행된 것으로 집계됨
  • 남은 가장 큰 작업은 reader와 입력 시스템 이식이며, reader 3.5k줄, screen handling 1.3k줄, input 1k줄, pager 700줄이 서로 강하게 결합돼 있음
  • 모든 C++ 코드는 제거될 예정이며, 중간에 부분 Rust 릴리스를 내지 않고 fish 4.0 같은 릴리스는 Rust만 포함하고 C++은 0인 형태를 목표로 함
  • Windows 포트는 계획된 적이 없으며, Rust 전환은 Windows 지원 문제의 해법이 아니고 MSYS2/cygwin 환경 사용자는 Rust의 해당 타깃 부재가 업데이트를 막을 수 있다고 우려함
  • 완성된 포트의 성능은 아직 확정되지 않았고 초기 결과는 고무적이지만 일부 경우 약 20% 느려질 가능성도 있으며, 첫 Rust 릴리스에는 베타가 필요하다고 판단함

Rust 포트 진행 상황

  • fish-shell의 Rust 재작성은 “대부분” 완료된 상태임
  • 진행률은 어떤 기준으로 세느냐에 따라 달라짐
    • C++ SLOC 제거 기준으로는 60%
    • Rust SLOC 대 C++ SLOC 기준으로는 74%
  • 일부 코드는 마지막 호출자가 사라지면 제거할 수 있는 중복된 스캐폴딩임
    • 예로 wgetopt는 이미 Rust로 번역됐지만, 마지막 C++ 호출자가 이식될 때까지 C++ 버전을 남겨둠
    • 모든 C++ 호출자에 변환용 코드를 붙이는 것보다 이 방식이 더 단순함
  • 마지막 호출자가 사라진 뒤 중복 코드가 제거되면 도미노처럼 정리되는 부분이 있음

아직 남은 큰 작업

  • 가장 큰 잔여 구성요소는 reader와 입력 시스템
  • 관련 코드는 서로 강하게 결합돼 있음
    • reader: 3.5k줄
    • screen handling: 1.3k줄
    • input: 1k줄
    • pager: 700줄
  • 그 뒤에는 일부 남은 코드와 빌드 시스템의 탈 C++화가 남음
    • cmake 제거
    • cargo가 필요한 작업을 모두 처리하도록 전환
    • 문서와 completion 파일 빌드·설치까지 cargo가 담당해야 함
  • fish 빌드는 Rust 코드 컴파일만이 아니라 여러 보조 산출물을 포함하기 때문에 단순한 전환이 아님
  • 이 작업은 “drive-by contribution”에 적합한 종류의 작업은 아님

릴리스 계획과 버전 흐름

  • fish-shell은 부분 Rust 릴리스를 내지 않을 계획임
  • 예를 들어 fish 4.0은 완전히 Rust로만 구성되고 C++은 0인 형태가 됨
  • 일반적으로 베타와 릴리스 후보를 중단했지만, 이번 전환은 베타를 낼 만한 변화로 판단됨
    • 기존에는 베타와 릴리스 후보가 충분한 테스트를 받지 못해 중단했음
  • Rust 버전으로 넘어가기 전에 C++ 기반 3.7.0 중간 릴리스도 원함
    • Rust 버전을 처리할 수 없는 플랫폼을 위한 더 나은 출발점으로 삼기 위함
    • 3.7.0은 3.6.1에 일부 변경을 백포트한 형태임
  • 3.7.0 작업은 Integration_3.7.0 branch에서 진행됨
    • 예비 CHANGELOG도 있음
    • 주요 변경으로 키 조합 타임아웃, history-pager 개선, 렌더링 글리치 수정, 더 빠른 glob이 포함됨

남은 파일과 구체적 범위

  • 2023년 12월 1일 기준 남은 파일 목록은 다음과 같음
src/fish_indent_common.cpp
src/fish_indent.cpp
src/fish_key_reader.cpp
src/builtins/bind.cpp
src/builtins/commandline.cpp
src/fish_tests.cpp
src/pager.cpp
src/reader.cpp
  • 이 목록은 남은 C++ 이식 범위를 파일 단위로 보여줌

오해 정정과 제약

  • 모든 C++ 코드는 제거될 예정임
  • Windows 포트는 계획되지 않았고, 과거에도 계획된 적이 없음
    • C++도 Windows에서 잘 지원되므로 Rust 자체가 Windows 포트 문제를 해결하지 않음
    • Windows 포트의 문제는 언어가 아니라 Windows가 Unix가 아니라는 점임
  • 이름과 마스코트는 바꾸지 않음
  • 태그라인에 “written in Rust”를 추가하지 않을 가능성이 높음
    • fishshell.com에는 Rust로 작성됐다는 점을 언급할 수도 있음
    • 2024년 9월 추가 논의에서 태그라인에 “written in rust”를 넣지 않는다는 입장이 재확인됨
  • 완성된 포트의 성능은 아직 알 수 없음
    • 초기 결과는 고무적임
    • 일부 경우 약 20% 느려질 가능성도 있음
    • 초기 포트가 끝나도 프로젝트가 끝나는 것은 아니며, 할 일이 많이 남아 있음

Windows와 MSYS2/cygwin 사용자의 우려

  • 한 사용자는 MSYS2 환경에서 fish를 사용하고 있으며, MSYS2가 POSIX 유틸리티를 제공해 fish가 잘 동작한다고 설명함
  • Rust는 cygwin 또는 MSYS2 타깃을 제공하지 않기 때문에 Rust 재작성 이후 fish를 cygwin 또는 MSYS2 타깃으로 컴파일할 수 없다고 우려함
  • 이 사용자는 Rust 전환이 일부 Windows fish 사용자의 업데이트를 막을 수 있다고 봄
  • 해당 우려는 작업이나 언어를 비난하는 것이 아니라, Windows가 Unix가 아니라는 제약을 상기시키는 내용으로 제시됨

댓글과 토론

Hacker News 의견들
  • 제대로 이해했다면, C++에서 Rust로 점진적 재작성을 하면서도 끝까지 동작하는 상태를 유지한다는 게 놀라움
    진행 속도도 매우 빠르고, 아직 fish를 안 써봤다면 꼭 써보길 권함. 기본값이 좋아서 커스터마이즈하지 않아도 쓰기 편한 셸이고, 몇 년 전 bash에서 옮긴 뒤로 돌아갈 생각이 안 듦
    덤으로, 드물게 쓰는 데다 직관적이지도 않은 bash의 for 루프 문법을 매번 구글링하지 않아도 됨

    • 점진적으로 하는 건 아닌 것 같음
      “부분적으로 Rust가 섞인 릴리스는 하지 않을 계획”이고, 예를 들어 fish 4.0은 완전 Rust, C++ 0% 로 낼 생각이라고 함. 중간에 C++만 쓰는 3.7.0도 내서 Rust 버전을 감당 못 하는 플랫폼을 위한 더 나은 출발점으로 삼으려는 듯함
      https://github.com/fish-shell/fish-shell/discussions/10123#d...
    • 스크립트는 여전히 Bash로 쓰거나 그냥 Python/Perl을 꺼내 쓰는 편이지만, 터미널 사용에는 확실히 Fish가 더 좋음
    • 기억하기 쉬운 Bash 루프 예시로, 증가 인덱스는 for ((i = 0; i < 10; i++)); do echo $i; done처럼 쓰면 됨
      배열 순회는 foo[0]=a, foo[1]=b를 둔 뒤 for i in ${foo[@]}; do echo $i; done 형태로 가능함
  • 재작성 동기가 더 자세히 나와 있음
    https://github.com/fish-shell/fish-shell/pull/9512#issuecomm...

    • 관리자의 글이 성숙하고 논리적이면서도 적당히 유머가 있고 단호해서, 그동안 Fish를 써볼까만 하던 마음이 훌륭한 프로젝트를 놓치고 있었던 것 같다는 쪽으로 바뀜
    • C++17로 포팅하는 건 “너무 번거롭다”고 보면서, 새 언어로 전부 다시 쓰는 건 괜찮다고 보는 게 꽤 많은 걸 드러냄
      결국 개발 세계 전반의 새롭고 반짝이는 것 추종이라는 이야기를 이기긴 어렵다고 봄. 그래도 Fish를 쓰진 않지만 잘되길 바람
  • Fish를 약 4개 운영체제에서 매일 쓰고 좋아하는 입장에서, 이 재작성은 정말 기대되고 코드베이스 규모와 복잡도를 생각하면 진행 속도가 놀라움
    나를 포함해 많은 사람이 기여하기 쉬워지는 효과도 있을 것 같음. 덜 주목받았지만 더 기대되는 건 향후 fish가 wchar_t 대신 UTF-8을 쓰도록 바뀌는 계획임. UCS2와 UTF-16은 소프트웨어에 골칫거리였고, Rust는 UTF-8 다루기가 훨씬 편함

    • 여러 컴파일러를 한 코드베이스에서 지원하려면 더 복잡해짐
      sizeof(wchar_t)가 MSVC에서는 2바이트라 UTF-16이고, gcc에서는 4바이트라 UTF-32임
  • Fish는 과소평가된 셸임
    POSIX 호환성 포기 같은 강한 선택을 하는데, 결과적으로 매우 좋은 셸이 됨. 10년 넘게 쓰고 있고 아직도 좋아함
    Fish 셸 스크립팅도 쓰기 아주 편해서, 인체공학적인 bash 같은 느낌임. 어떤 프로젝트든 흠은 있지만, 내가 하려던 일을 실제로 막은 적은 없음

  • zsh + spaceship을 쓰는 입장에서, Fish를 메인 셸로 옮기면 어떤 이점이 있는지 궁금함
    bash 스크립트는 많이 쓰지 않아서 스크립팅 쪽은 덜 중요함

    • 이미 zsh를 원하는 대로 설정해뒀다면 큰 이점은 많지 않을 듯함
      Fish의 큰 장점은 설정 없이 바로 이상적인 셸에 가깝다는 것임. 자동완성이 바로 동작하고, 기록 탐색이 쉽고, 기록 기반 명령 완성도 되며, 프롬프트 선택도 브라우저를 여는 정도로 간단함. zsh처럼 깊게 커스터마이즈할 수 있지만, 기본값만으로도 꽤 좋은 셸이 됨
    • 2017년에 zsh 대신 Fish를 고른 이유는 원하는 기능이 기본 포함돼 있고, 체감상 훨씬 빨랐기 때문임
      그 뒤로 셸 설정 유지보수에 거의 시간을 쓰지 않게 돼서 좋았음
    • 속도 때문임
      Fish는 zsh에서 플러그인이 필요했던 많은 일을 기본으로 해줌. zsh 플러그인은 느려서 셸 시작이 3초가 넘었는데, Fish는 플러그인을 넣어도 훨씬 빨리 시작함
    • 처음으로 올바른 디렉터리에 fish_prompt.fish 파일을 만들고, 그 안에 fish_prompt 함수를 작성해 문자열을 표준 출력으로 내보내서 직접 셸 프롬프트를 만들었을 때 zsh를 지울 뻔했음
      $PS1에 이것저것 밀어 넣고 잘 되길 바라던 방식으로 돌아가기 어렵게 됨. 며칠만이라도 써보길 권함. 당연하게 여기던 것 중 무엇이 셸별 기능인지 보이기 때문임. 최악의 경우에도 “내 취향은 아니네”라고 하고 bash/zsh 등 좋아하는 셸로 돌아가면 됨
    • 몇 년 전 zsh에서 Fish로 옮겼고 기능은 거의 비슷한데, Fish 설정 파일은 zsh 설정의 10% 정도 크기임
      원하는 것 대부분이 기본으로 제공되고, 지금은 fzf.fish 플러그인 하나만 씀
  • 가장 빠른 셸 중 하나가 더 빨라질 가능성이 큼
    zsh에서 Fish로 옮긴 뒤 터미널 생산성이 많이 올랐음

    • 거기에 걸지는 않겠음
      링크에 따르면 완성된 포트의 성능이 어떨지 실제로는 모른다고 함. 초기 결과는 고무적이지만, 어떤 경우에는 약 20% 느려질 가능성도 충분히 있음
    • C++와 Rust 사이에 성능 차이가 그렇게 크진 않다고 봄
      거의 맞붙는 수준이고 명확한 승자는 없을 가능성이 큼
    • 셸 성능이 어떤 작업 흐름에서는 병목이 되는지 궁금함
      보통은 일을 다른 곳으로 넘겨주는 접착 코드에 가깝다고 생각했음. 파이프 효율 문제일 수도 있고, bash로 전체 프로그램을 쓰는 괴짜들 때문일 수도 있겠지만, Fish가 제공하는 삶의 질 개선이 많은데 속도를 핵심 장점으로 꼽는 건 조금 특이해 보임
    • C, C++, Rust, 다른 언어 차이가 의미 있을 만큼 빠르게 타이핑하고 작업을 관리하진 않을 텐데, Fish가 제공하는 게 뭔가 더 있는 건지 궁금함
  • Fish를 1년 써왔음
    gvm, nvm 같은 일부 스크립트가 안 돌아가도록 표준 호환성을 깨는 점은 마음에 안 들지만, zsh에서 보통 직접 설정하던 기능이 전부 들어 있음. 여러 머신에서 zsh 설정을 시도하다가 포기하고 전부 기본 Fish로 바꿈
    이미 잘 동작하는데 Rust로 포팅해서 얻는 게 뭔지는 잘 모르겠음. 보안 때문이라면, Fish를 악의적으로 건드릴 수 있는 무언가가 이미 시스템에 올라와 있는 것 아닌가 싶음

    • 원래 Rust 논의에 나온 것처럼 Rust로 옮기는 이유는 여러 가지임
      주로 기여자 확보와, 유지보수자들이 안심할 수 있는 비동기/병렬 모드 추가 쪽에 가까움
      [1] https://github.com/fish-shell/fish-shell/pull/9512
  • Fish가 좋음
    ZSH+Prezto에서 그냥 Fish만 쓰는 쪽으로 바꿨는데 아쉬운 게 없고 훨씬 빠름. 서버에는 전부 bash가 있고 bash 스크립트도 여전히 쓰지만, 일상적인 터미널 작업은 Fish로 충분함

  • Fish가 늘 궁금했지만 POSIX 비호환이라 꺼려졌음
    이 부분에서 겪은 문제와 우회 방법을 공유해줄 사람이 있는지 궁금함

    • Fish는 bash/shell 스크립트 대체용이 아니라 대화형 셸로 쓰기 위한 것이어서, POSIX 준수 여부는 실제로 큰 문제가 아님
      단점은 약간의 문맥 전환이 필요하다는 것임. 특히 평생 bash/zsh를 써왔다면 더 그럴 수 있음. 셸을 사용자 인터페이스로 쓰는 때와 bash/sh를 인터프리터로 쓰는 때를 구분하는 건 개인적으로 쉽지만, 모두에게 직관적이진 않을 수 있음
      또 POSIX 호환 셸을 일상 셸로 쓰지 않게 된 뒤로는, 예전 같으면 bash로 해결했을 스크립트를 더 빨리 범용 언어로 승격시키게 됨
    • Bash/zsh 스크립트는 그냥 Bash/zsh로 실행하면 됨: bash script.sh
      처음 Fish를 쓸 때는 POSIX 비호환이 걸렸지만, 다른 문법을 조금 배워서 벗어나고 나니 Fish의 더 sane한 문법이 들인 노력만큼 가치 있다고 봄. 지금은 터미널을 훨씬 더 즐겁게 씀
      게다가 90%의 시간에는 POSIX 호환을 지킬 필요가 없고, 요즘 많은 스크립트나 확장도 Fish를 지원함. 기업 환경에서는 표준인 Bash/zsh를 계속 씀
  • 왜 Rust로 바꾸는지 궁금함
    C++ 코드베이스가 감당하기 어려워지고 있었던 건가?