의존성 디버깅 및 테스트
의존성 그래프 테스트하기
의존성 그래프에 대한 테스트를 작성하는 방법은 여러 가지가 있습니다. 가장 간단한 메커니즘은 #[rustc_if_this_changed] 및 #[rustc_then_this_would_need] 어노테이션입니다. 이들은 ui 테스트에서 예상되는 경로 집합이 의존성 그래프에 존재하는지 테스트하는 데 사용됩니다.
예시로 tests/ui/dep-graph/dep-graph-caller-callee.rs 또는 아래의 테스트를 참고하십시오.
#[rustc_if_this_changed]
fn foo() { }
#[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK
fn bar() { foo(); }
이는 다음과 같이 읽어야 합니다.
이것(
foo)이 변경되면, 이것(즉,bar)의 TypeckTables도 변경되어야 합니다.
기술적으로는, 이 줄과 연관된 문자열 “OK“를 테스트가 stderr에 출력할 것으로 기대되는 방식으로 동작합니다.
다음 줄을 추가할 수도 있습니다.
#[rustc_then_this_would_need(TypeckTables)] //~ ERROR no path
fn baz() { }
그 의미는 다음과 같습니다.
foo가 변경되더라도baz의 TypeckTables는 변경될 필요가 없습니다. 매크로는 오류를 발생시켜야 하며, 오류 메시지에는 “no path”(경로 없음)가 포함되어야 합니다.
//~ ERROR OK는 테스트 대상인 Rust 코드의 관점에서는 주석이지만, 테스트 자체의 관점에서는 의미를 가진다는 점을 기억하십시오.
의존성 그래프 디버깅하기
그래프 덤프하기
컴파일러는 디버깅을 돕기 위해 의존성 그래프를 덤프하는 기능도 제공합니다. 이를 위해서는 -Z dump-dep-graph 플래그를 전달하십시오. 그래프는 현재 디렉터리의 dep_graph.{txt,dot}에 덤프됩니다. RUST_DEP_GRAPH 환경 변수로 파일 이름을 재정의할 수 있습니다.
하지만 전체 의존성 그래프는 너무 방대해서 그다지 도움이 되지 않는 경우가 많습니다. 따라서 컴파일러는 그래프를 필터링하는 기능도 제공합니다. 다음 세 가지 방법으로 필터링할 수 있습니다.
- 특정 노드 집합(보통 단일 노드)에서 시작하는 모든 간선.
- 특정 노드 집합에 도달하는 모든 간선.
- 주어진 시작 노드와 끝 노드 사이에 있는 모든 간선.
필터링하려면 RUST_DEP_GRAPH_FILTER 환경 변수를 사용하십시오. 이 변수는 다음 중 하나의 형태여야 합니다.
source_filter // nodes originating from source_filter
-> target_filter // nodes that can reach target_filter
source_filter -> target_filter // nodes in between source_filter and target_filter
source_filter와 target_filter는 &로 구분된 문자열 목록입니다. 노드의 레이블에 해당 문자열이 모두 나타나면 그 노드는 필터와 일치하는 것으로 간주됩니다. 예를 들어 다음과 같이 작성하면
RUST_DEP_GRAPH_FILTER='-> TypeckTables'
모든 TypeckTables 노드의 선행 노드를 선택합니다. 하지만 보통은 특정 함수의 TypeckTables 노드가 필요하므로 다음과 같이 작성할 수 있습니다.
RUST_DEP_GRAPH_FILTER='-> TypeckTables & bar'
이렇게 하면 이름에 bar가 들어간 함수의 TypeckTables 노드의 선행 노드만 선택됩니다.
foo를 변경하면 bar를 다시 타입 검사해야 하는데, 그럴 필요가 없다고 생각할 때가 있을 수 있습니다. 그런 경우에는 다음과 같이 할 수 있습니다.
RUST_DEP_GRAPH_FILTER='Hir & foo -> TypeckTables & bar'
이렇게 하면 Hir(foo)에서 TypeckTables(bar)로 이어지는 모든 노드가 덤프되며, 이를 통해 (바라건대) 잘못된 간선이 어디서 생겼는지 확인할 수 있습니다.
잘못된 간선 추적하기
의존성 그래프를 덤프한 뒤, 존재해서는 안 되는 경로를 발견했지만 그 경로가 어떻게 생겼는지 잘 모를 때가 있습니다. 컴파일러가 디버그 단언을 켠 상태로 빌드되었다면, 컴파일러가 이를 추적하는 데 도움을 줄 수 있습니다. RUST_FORBID_DEP_GRAPH_EDGE 환경 변수를 필터로 설정하기만 하면 됩니다. 의존성 그래프에서 생성되는 모든 간선이 그 필터와 대조되며, 일치하면 bug!가 보고되므로 백트레이스(RUST_BACKTRACE=1)를 쉽게 확인할 수 있습니다.
이 필터들의 구문은 이전 절에서 설명한 것과 같습니다. 다만 앞 절과 달리 이 필터는 각 간선에 적용되며, 그래프의 더 긴 경로는 처리하지 않는다는 점에 유의하십시오.
예시:
foo의 Hir에서 bar의 타입 검사로 이어지는 경로가 있는데, 그런 경로가 있어서는 안 된다고 생각한다고 합시다. 앞 절에서 설명한 대로 의존성 그래프를 덤프하고 dep-graph.txt를 열면 다음과 같은 내용이 보입니다.
Hir(foo) -> Collect(bar)
Collect(bar) -> TypeckTables(bar)
첫 번째 간선이 의심스러워 보입니다. 그래서 RUST_FORBID_DEP_GRAPH_EDGE를 Hir&foo -> Collect&bar로 설정하고 다시 실행한 다음 백트레이스를 살펴봅니다. 짜잔, 버그가 고쳐졌습니다!