Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

LLVM 업데이트하기

Rust는 여러 LLVM 버전을 대상으로 빌드하는 것을 지원합니다.

  • 현재 LLVM 개발 브랜치의 트리 최신 상태(tip-of-tree)는 보통 며칠 이내에 지원됩니다. 이러한 수정을 위한 PR에는 llvm-main 태그가 붙습니다.
  • 가장 최근에 릴리스된 메이저 버전은 항상 지원됩니다.
  • 그 이전의 한두 개 메이저 버전은 빌드에 성공하고 대부분의 테스트를 통과할 것으로 기대된다는 의미에서 보통 지원됩니다. 하지만 잘못된 컴파일(miscompilation)에 대한 수정은 과거 LLVM 버전으로 백포트되지 않는 경우가 많으므로, 오래된 버전의 LLVM과 함께 rustc를 사용하면 건전성(soundness) 버그의 위험이 커집니다. 최신 버전의 LLVM을 사용할 것을 강력히 권장합니다.

기본적으로 Rust는 rust-lang/llvm-project 저장소에 있는 자체 포크를 사용합니다. 이 포크는 업스트림 프로젝트의 release/$N.x 브랜치를 기반으로 하며, 여기서 $N은 가장 최근에 릴리스된 메이저 버전이거나 릴리스 후보 단계에 있는 현재 메이저 버전입니다. 이 포크는 절대 main 개발 브랜치를 기반으로 하지 않습니다.

저희 LLVM 포크는 다음만 받아들입니다.

  • 이미 업스트림에 반영된 변경 사항의 백포트.
  • 저희 CI 환경에 영향을 주는 빌드 문제에 대한 우회책.

SGX 활성화를 위해 예외적으로 유지되어 온 패치 하나를 제외하면, 먼저 업스트림에 반영되지 않은 기능적 패치는 받아들이지 않습니다.

LLVM 업데이트에는 절차가 서로 다른 세 가지 유형이 있습니다.

  • 현재 LLVM 메이저 버전이 지원되는 동안의 백포트.
  • 현재 LLVM 메이저 버전이 더 이상 지원되지 않는 동안의 백포트(또는 변경 사항이 업스트림 백포트 대상이 아닌 경우).
  • 새 LLVM 메이저 버전으로의 업데이트.

백포트(업스트림 지원 중)

현재 LLVM 메이저 버전이 업스트림에서 지원되는 동안에는 수정 사항을 먼저 업스트림에 백포트한 다음, 릴리스 브랜치를 Rust 포크로 다시 병합해야 합니다.

  1. 버그 수정이 업스트림 LLVM에 반영되어 있는지 확인하십시오.
  2. 아직 반영되지 않았다면 업스트림 릴리스 브랜치로의 백포트를 요청하십시오. LLVM 커밋 권한이 있다면 백포트 절차를 따르십시오. 그렇지 않다면 백포트를 요청하는 이슈를 여십시오. 백포트가 승인되고 병합되면 다음 단계로 진행하십시오.
  3. rustc가 현재 사용하고 있는 브랜치를 확인하십시오. src/llvm-project 서브모듈은 항상 rust-lang/llvm-project 저장소의 한 브랜치에 고정되어 있습니다.
  4. rust-lang/llvm-project 저장소를 포크하십시오.
  5. 적절한 브랜치(보통 rustc/a.b-yyyy-mm-dd 형식의 이름)를 체크아웃하십시오.
  6. git remote add upstream https://github.com/llvm/llvm-project.git를 사용하여 업스트림 저장소를 리모트로 추가하고, git fetch upstream을 사용하여 가져오십시오.
  7. upstream/release/$N.x 브랜치를 병합하십시오.
  8. 이 브랜치를 여러분의 포크에 푸시하십시오.
  9. 이전과 같은 브랜치를 대상으로 rust-lang/llvm-project에 풀 리퀘스트를 보내십시오. PR 설명에 수정하려는 Rust 및/또는 LLVM 이슈를 반드시 언급하십시오.
  10. PR이 병합될 때까지 기다리십시오.
  11. 버그 수정을 반영하도록 src/llvm-project 서브모듈을 업데이트하는 PR을 rust-lang/rust에 보내십시오. 이 작업은 보통 로컬에서 git submodule update --remote src/llvm-project로 수행할 수 있습니다.
  12. PR이 병합될 때까지 기다리십시오.

PR 예시: #59089

백포트(업스트림에서 지원하지 않는 경우)

업스트림 LLVM 릴리스는 GA 릴리스 이후 두세 달 동안만 지원됩니다. 업스트림에서 더 이상 백포트를 받지 않으면, 변경 사항을 우리 포크에 직접 체리픽해야 합니다.

  1. 버그 수정이 업스트림 LLVM에 들어가 있는지 확인하십시오.
  2. rustc가 현재 사용하는 브랜치를 확인하십시오. src/llvm-project 서브모듈은 항상 rust-lang/llvm-project 저장소의 한 브랜치에 고정되어 있습니다.
  3. rust-lang/llvm-project 저장소를 포크하십시오.
  4. 적절한 브랜치(보통 rustc/a.b-yyyy-mm-dd라는 이름)를 체크아웃하십시오.
  5. git remote add upstream https://github.com/llvm/llvm-project.git를 사용해 업스트림 저장소를 리모트로 추가하고, git fetch upstream으로 페치하십시오.
  6. git cherry-pick -x를 사용해 관련 커밋을 체리픽하십시오.
  7. 이 브랜치를 여러분의 포크에 푸시하십시오.
  8. 이전과 같은 브랜치를 대상으로 rust-lang/llvm-project에 풀 리퀘스트를 보내십시오. PR 설명에 수정하려는 Rust 및/또는 LLVM 이슈를 반드시 언급하십시오.
  9. PR이 병합될 때까지 기다리십시오.
  10. 버그 수정을 반영하도록 src/llvm-project 서브모듈을 업데이트하는 PR을 rust-lang/rust에 보내십시오. 이 작업은 보통 로컬에서 git submodule update --remote src/llvm-project로 수행할 수 있습니다.
  11. PR이 병합될 때까지 기다리십시오.

PR 예시: #59089

새 LLVM 릴리스로 업데이트하기

버그 수정과 달리, 새 LLVM 릴리스로 업데이트하려면 보통 훨씬 더 많은 작업이 필요합니다. 이 경우에는 커밋을 이전 버전으로 체리픽하는 것이 현실적이지 않으므로 전체 업데이트를 해야 합니다. 여기서 할 일이 많으니 각 단계를 하나씩 자세히 살펴봅시다.

  1. LLVM이 최신 릴리스 버전의 브랜치를 생성했다고 발표합니다. 이는 llvm/llvm-project 저장소에 보통 release/$N.x라는 이름의 브랜치로 나타나며, 여기서 $N은 릴리스되는 LLVM의 버전입니다.

  2. 이 release/$N.x 브랜치를 기반으로 rust-lang/llvm-project 저장소에 새 브랜치를 만들고, 이름을 rustc/a.b-yyyy-mm-dd로 지정하십시오. 여기서 a.b는 브랜치를 만드는 시점에 트리 내에 있는 LLVM의 현재 버전 번호이고, 나머지 부분은 현재 날짜입니다.

  3. llvm-project 저장소에 Rust 전용 패치를 적용하십시오. 모든 기능과 버그 수정은 업스트림에 반영되어 있지만, 업스트림에 반영하기에는 적절하지 않은 특이한 빌드 관련 패치가 종종 있습니다. 이러한 패치는 일반적으로 rustc가 현재 사용하고 있는 rust-lang/llvm-project 브랜치의 가장 최근 패치들입니다.

  4. rust 저장소에서 새 LLVM을 빌드하십시오. 이를 위해서는 src/llvm-project 저장소를 여러분이 만든 브랜치와 리비전으로 업데이트해야 합니다. 또한 일반적으로 .gitmodules를 LLVM 서브모듈의 새 브랜치 이름으로 업데이트하는 것이 좋습니다. 서브모듈 업데이트가 되돌려지지 않도록 src/llvm-project에 대한 변경 사항을 반드시 커밋하십시오. 실행해야 하는 몇 가지 명령은 다음과 같습니다.

    • ./x build src/llvm-project - LLVM이 여전히 빌드되는지 테스트합니다
    • ./x build - rustc의 나머지 부분을 빌드합니다

    업데이트된 LLVM 바인딩으로 컴파일되도록 llvm-wrapper/*.cpp를 업데이트해야 할 가능성이 높습니다. 이전 LLVM 버전에서도 바인딩이 계속 컴파일되도록 #ifdef 등을 사용해야 한다는 점에 유의하십시오.

    profile = "compiler" 및 ./x setup이 설정하는 기타 기본값은 LLVM을 소스에서 빌드하는 대신 CI에서 다운로드한다는 점에 유의하십시오. 여러분의 변경 사항이 실제로 사용되도록 하려면 이 기능을 일시적으로 비활성화해야 합니다. 이는 bootstrap.toml에 다음 설정을 추가하여 수행합니다.

    llvm.download-ci-llvm = false
    
  5. 다른 플랫폼에서 회귀가 발생하는지 테스트하십시오. LLVM에는 tier 1이 아닌 아키텍처에 대한 버그가 적어도 하나는 있는 경우가 많으므로, bors에 보내기 전에 테스트를 좀 더 해 두는 것이 좋습니다! 하지만 리소스가 부족하다면 지금 PR을 그대로 bors에 보내도 되며, 어차피 테스트가 진행됩니다.

    이상적으로는 LLVM을 빌드하여 몇 가지 플랫폼에서 테스트하십시오.

    • Linux
    • macOS
    • Windows

    그런 다음, CI에서도 실행하는 몇 가지 docker 컨테이너를 실행하십시오.

    • ./src/ci/docker/run.sh wasm32
    • ./src/ci/docker/run.sh arm-android
    • ./src/ci/docker/run.sh dist-various-1
    • ./src/ci/docker/run.sh dist-various-2
    • ./src/ci/docker/run.sh armhf-gnu
  6. rust-lang/rust에 보낼 PR을 준비하십시오. rust-lang/llvm-project의 메인테이너와 협력하여 여러분의 커밋을 해당 저장소의 브랜치에 반영한 다음, rust-lang/rust에 PR을 보내면 됩니다. 최소한 src/llvm-project를 변경하게 되며, llvm-wrapper도 변경하게 될 가능성이 높습니다.

    선행 사례로 참고할 만한 이전 LLVM 업데이트는 다음과 같습니다.

    실제로 src/llvm-project를 업데이트하기 전에 llvm-wrapper 호환성 작업을 먼저 PR로 반영하는 것이 가장 쉬운 경우도 있다는 점에 유의하십시오. 이렇게 하면 여러분이 LLVM 문제를 해결하는 동안, 새 LLVM을 시험해 보려는 다른 사람들도 여러분이 C++ 바인딩을 업데이트한 작업의 혜택을 받을 수 있습니다.

  7. 이후 몇 달 동안 LLVM은 release/a.b 브랜치에 계속해서 커밋을 푸시합니다. 우리는 이러한 버그 수정도 함께 반영하고 싶은 경우가 많습니다. 이를 위한 병합 절차는 git merge 자체를 사용하여 LLVM의 release/a.b 브랜치를 2단계에서 만든 브랜치에 병합하는 것입니다. 이 작업은 LLVM의 릴리스 브랜치가 안정화되는 동안 필요할 때마다 보통 여러 번 수행됩니다.

  8. 그런 다음 LLVM이 a.b 버전의 릴리스를 발표합니다.

  9. LLVM이 공식 릴리스된 후에는 rust-lang/llvm-project 저장소에 새 브랜치를 만드는 절차를 다시 따르며, 이번에는 새 날짜를 사용합니다. 그제야 비로소 Rust가 해당 버전을 사용하도록 업데이트하는 PR이 병합됩니다.

    git rebase를 수행하므로 rust-lang/llvm-project의 커밋 기록은 훨씬 깔끔해 보일 것이며, 기본 LLVM 릴리스 브랜치 위에 Rust 전용 커밋 몇 개만 쌓인 형태가 됩니다.

주의 사항 및 함정

위의 지침대로 순조롭게 진행되는 것이 이상적이지만, 진행하면서 염두에 두어야 할 몇 가지 주의 사항은 다음과 같습니다.

  • LLVM 버그는 찾기 어려우므로 주저하지 말고 도움을 요청하십시오! 여기서는 이분 탐색(bisection)이 확실히 큰 도움이 됩니다(네, LLVM은 빌드하는 데 한참 걸리지만, 그래도 이분 탐색은 여전히 큰 도움이 됩니다). 기여자에게 고성능 하드웨어에 대한 원격 접근을 제공하는 계획인 Dev Desktops를 활용할 수 있다는 점에 유의하십시오.
  • 일반적인 질문이 있다면 wg-llvm에서 도움을 받을 수 있습니다.
  • GitHub에서 브랜치 생성은 권한이 필요한 작업이므로, 대개 쓰기 권한이 있는 사람에게 브랜치 생성을 부탁해야 할 것입니다.