Rust 컴파일러 개발 관련 명령어 모음집

notJoon @joonnot@hackers.pub

개요

러스트 컴파일러에 기여하면서 자주 사용하는 명령어와 일반적인 흐름에 대해 정리한 글입니다.

1. 기본 빌드 명령어

1.1 컴파일러 빌드

전체 컴파일러 빌드

./x.py build --stage 1

전체 컴파일러를 처음부터 빌드하거나 큰 변경사항 적용 시 사용. 하드웨어에 따라 다르지만 대략 5~10분 정도 소요됨.

특정 컴포넌트만 빌드

어떤 모듈만 수정/개발하는 경우 특정 컴포넌트만 빌드하는 것도 가능. 이 경우 전체 빌드보다 압도적으로 적은 시간 소요.

./x.py build --stage 1 compiler/rustc_[component_name]
# 예: ./x.py build --stage 1 compiler/rustc_parse

1.2 테스트 실행

기본 테스트 실행

# 특정 테스트 파일 실행
./x.py test tests/ui/[category]/[test-name].rs

# 여러 테스트 실행 (와일드카드 사용)
./x.py test tests/ui/[category]/[pattern]*.rs

# Stage 명시 (기본은 stage 2)
./x.py test tests/ui/[category]/[test-name].rs --stage 1

--bless 플래그

# 테스트의 예상 출력을 자동으로 업데이트
./x.py test tests/ui/[category]/[test-name].rs --bless

사용 사례:

  1. 새 테스트 작성 시: .stderr 파일 자동 생성
  2. 에러 메시지 개선 시: 변경된 출력으로 예상값 업데이트
  3. 진단 메시지 추가 시: 새로운 help/note 메시지 반영

작동 방식:

  • 실제 컴파일러 출력을 .stderr 파일로 저장
  • 기존 .stderr 파일이 있으면 덮어씀

--force-rerun 플래그

테스트 결과 캐시를 무시하고 항상 재실행함.

./x.py test tests/ui/[category]/[test-name].rs --force-rerun

아래 상황에서 주로 사용:

  • 테스트가 "ignored N up-to-date test" 메시지로 스킵될 때
  • 캐시 문제가 의심될 때
  • 동일 테스트를 연속으로 실행해야 할 때

2. Stage 시스템

2.1 Stage별 설명

  • Stage 0: 미리 컴파일된 부트스트랩 컴파일러

    • 다음 단계 컴파일러를 빌드하는 데 사용
    • 로컬 변경사항 반영 안됨
    • 부트스트래핑 과정에만 사용
  • Stage 1: Stage 0으로 빌드한 컴파일러

    • 변경사항이 여기서부터 반영됨
    • 일반적인 개발과 테스트 과정에서 사용
  • Stage 2: Stage 1으로 빌드한 컴파일러

    • 부트스트래핑 검증용 최종본
    • Stage 1과 동일해야 함 (부트스트래핑 성공 확인)
    • CI나 PR 제출 전 최종 검증용으로 사용

2.2 Stage별 사용 가이드

Stage 0 (부트스트랩 컴파일러)

# 경고: 테스트에 직접 사용하지 마세요!
./x.py test tests/ui/[test].rs --stage 0  # ❌ 실패할 가능성 높음

초기에 Stage 1 컴파일러를 빌드하는 도구로만 사용하고 이후 쓸 일은 없음.

Stage 1 (개발용 컴파일러)

# 일반적인 개발 워크플로우
./x.py build --stage 1
./x.py test tests/ui/[category]/ --stage 1

빠른 빌드 시간, 즉각적인 피드백이 필요한 일상적인 개발 과정 대부분에서 사용하게 됨.

Stage 2 (검증용 컴파일러)

# PR 제출 전 최종 검증
./x.py build --stage 2
./x.py test tests/ui/[category]/  # 기본값이 stage 2

Stage 1으로 빌드한 컴파일러로 부트스트래핑 일관성을 검증할 때 사용함. PR 올리기 전 최종 확인 용도로 사용하면 좋음.

3. UI 테스트 작성 가이드

3.1 테스트 파일 구조

// tests/ui/[category]/[descriptive-test-name].rs
fn main() {
    // 버그를 재현하거나 기능을 테스트하는 코드
    let problematic_code = example();
    //~^ ERROR [expected error message]
    //~| HELP [expected help message]
    //~| NOTE [expected note message]
}

파일명 규칙:

  • issue-12345.rs: 특정 이슈 관련 테스트
  • feature-name.rs: 특정 기능 테스트
  • pattern-description.rs: 특정 패턴이나 케이스 테스트

3.2 에러 주석 문법

주석 기호와 의미

//~^ ERROR  : 바로 위 줄에서 에러 예상
//~| HELP   : 같은 에러의 도움말 메시지
//~| NOTE   : 같은 에러의 노트 메시지
//~^^ ERROR : 2줄 위에서 에러 예상
//~v ERROR  : 바로 아래 줄에서 에러 예상

각 주석의 역할:

  • ERROR: 컴파일 에러 메시지 검증
  • HELP: 수정 제안 메시지 검증
  • NOTE: 추가 설명 메시지 검증
  • WARNING: 경고 메시지 검증

3.3 stderr 파일 생성/업데이트

# 새 테스트 작성 후 stderr 파일 생성
./x.py test tests/ui/[category]/[test-name].rs --bless

# 결과: tests/ui/[category]/[test-name].stderr 파일 자동 생성

stderr 파일의 역할:

  • 컴파일러의 정확한 출력을 기록
  • 회귀 테스트의 기준점 역할
  • 에러 메시지 개선 추적

4. 디버깅 명령어

4.1 직접 컴파일러 실행

기본 실행

# 빌드된 컴파일러로 직접 테스트
./build/[target-triple]/stage1/bin/rustc [test-file].rs
# 예: ./build/x86_64-unknown-linux-gnu/stage1/bin/rustc test.rs
  • 테스트 프레임워크 없이 빠른 검증
  • 간단한 동작 확인, 에러 메시지 직접 확인

디버그 어설션 활성화

RUSTFLAGS="-C debug-assertions=yes" ./build/[target]/stage1/bin/rustc [file].rs
  • debug_assert! 매크로 활성화로 내부 불변성 검사
  • 컴파일러 내부 로직 문제 디버깅 용도로 사용.

백트레이스 활성화

RUST_BACKTRACE=1 ./build/[target]/stage1/bin/rustc [file].rs
RUST_BACKTRACE=full ./build/[target]/stage1/bin/rustc [file].rs  # 전체 백트레이스
  • 패닉이나 ICE(Internal Compiler Error) 발생 시 스택 추적
  • 컴파일러 크래시 원인 파악

5. 작업 흐름 예시

5.1 컴파일러 버그 수정 워크플로우

1단계: 문제 재현

# 이슈 재현을 위한 최소 테스트 케이스 작성.
#
# 만약 이슈에 Minimal reproduction이 있다면
echo '[problematic code]' > test.rs

# 현재 컴파일러 동작 확인
./build/[target]/stage1/bin/rustc test.rs

2단계: 코드 수정

말 그대로 코드 수정 단계. 작은 단위로 수정하고 자주 테스트하는 것이 가장 확실한 방법.

3단계: 빠른 빌드 및 검증

# 수정된 컴포넌트만 빌드 (빠름)
./x.py build --stage 1 compiler/rustc_[component]

# 수정 효과 즉시 확인
./build/[target]/stage1/bin/rustc test.rs

4단계: UI 테스트 작성

# 테스트 파일 생성
cat > tests/ui/[category]/issue-[number].rs << 'EOF'

// 문제를 재현하는 코드
[test code]
//~^ ERROR [expected error]
//~| HELP [expected help]
EOF

# stderr 파일 자동 생성
./x.py test tests/ui/[category]/issue-[number].rs --bless

중요: 회귀 방지를 위한 테스트 필수

5단계: 테스트 실행

# 단일 테스트 실행
./x.py test tests/ui/[category]/issue-[number].rs

# 관련 카테고리 전체 테스트
./x.py test tests/ui/[category]/

확인사항: 새 테스트 통과 + 기존 테스트 무결성

6단계: 최종 검증 (PR 제출 전)

# Stage 2 전체 빌드
./x.py build --stage 2

# 전체 테스트 스위트 실행
./x.py test tests/ui/[category]/

# 포맷 확인 (선택사항)
./x.py fmt --check

최소한의 CI 실패 요소 사전 검증 목적

6. 자주 발생하는 문제와 해결법

6.1 "Stage 0 runs on precompiled compiler" 에러

# ❌ 문제 상황
./x.py test tests/ui/[test].rs --stage 0

# ✅ 해결 방법
./x.py test tests/ui/[test].rs --stage 1

원인: Stage 0은 로컬 변경사항이 반영되지 않은 부트스트랩 컴파일러
해결: Stage 1 이상 사용

6.2 "ignored N up-to-date test" 메시지

# ❌ 문제 상황
./x.py test tests/ui/[test].rs
# 출력: "ignored 1 up-to-date test"

# ✅ 해결 방법
./x.py test tests/ui/[test].rs --force-rerun

원인: 테스트 결과가 캐시되어 있음
해결: --force-rerun으로 캐시 무시

6.3 테스트 실패 후 stderr 업데이트

# ❌ 문제 상황
# 에러 메시지 변경으로 테스트 실패

# ✅ 해결 방법
./x.py test tests/ui/[test].rs --bless

원인: 컴파일러 출력이 변경되어 예상값과 불일치
해결: --bless로 새로운 출력을 예상값으로 설정

6.4 빌드 시간 단축 방법

특정 컴포넌트만 빌드

# 느림: 전체 빌드
./x.py build --stage 1

# 빠름: 수정한 컴포넌트만 빌드
./x.py build --stage 1 compiler/rustc_[component]

빌드 병렬화

# CPU 코어 수 지정 (기본값: 자동 감지)
./x.py build --stage 1 -j [num_cores]

시스템 코어 수 - 1 정도가 적절

증분 빌드 활용

# 작은 변경사항은 증분 빌드로 충분
# clean 빌드는 큰 구조 변경 시에만
./x.py clean  # 필요시에만 사용

7. 환경 변수

7.1 디버깅용 환경 변수

백트레이스 제어

RUST_BACKTRACE=1           # 기본 백트레이스
RUST_BACKTRACE=full        # 전체 백트레이스 (모든 프레임)
  • 패닉이나 ICE 발생 시 원인 추적
  • 컴파일러 크래시 디버깅시 사용

디버그 어설션

RUSTFLAGS="-C debug-assertions=yes"  # debug_assert! 활성화
  • 컴파일러 내부 불변성 검사

컴파일러 로깅

RUSTC_LOG=rustc_[component]=debug  # 특정 컴포넌트 로그
RUSTC_LOG=debug                    # 전체 디버그 로그
RUSTC_LOG=info                     # 정보 수준 로그

출력량이 매우 많을 수 있기 때문에 가능하다면 클로드 코드 같은 언어 모델에 맡기는걸 추천.

8

No comments

If you have a fediverse account, you can comment on this article from your own instance. Search https://hackers.pub/ap/articles/0198a3ad-bca5-7c2b-babe-5fb258cf40b4 on your instance and reply to it.