Rustdoc 개요
rustdoc는 컴파일러 및 표준 라이브러리와 함께 같은 소스 트리 안에 있습니다. 이 장에서는 rustdoc가 어떻게 동작하는지 설명합니다. Rustdoc의 기능과 사용법에 대한 정보는 Rustdoc 책을 참고하십시오. rustdoc의 동작 방식에 대한 자세한 내용은 “Rustdoc 내부 구조” 장을 참고하십시오.
rustdoc는 rustc 내부 구조(그리고 당연히 표준 라이브러리)를 사용하므로, rustdoc를 빌드하려면 먼저 컴파일러와 std를 한 번 빌드해야 합니다.
Rustdoc는 전적으로 librustdoc 크레이트 안에 구현되어 있습니다. Rustdoc는 크레이트의 내부 표현(HIR)을 얻고 아이템의 타입에 관한 몇 가지 쿼리를 실행할 수 있는 시점까지 컴파일러를 실행합니다. HIR과 쿼리는 링크된 장에서 다룹니다.
그 후 librustdoc는 문서를 렌더링하기 위해 두 가지 주요 단계를 수행합니다.
- AST를 문서 생성에 더 적합한 형태(그리고 컴파일러의 잦은 변경에 조금 더 강한 형태)로 “정리(clean)“합니다.
- 이렇게 정리된 AST를 사용하여 크레이트의 문서를 한 페이지씩 렌더링합니다.
물론 실제로는 이것보다 더 많은 일이 일어나며 위 설명은 많은 세부 사항을 생략한 것이지만, 개략적인 개요는 이와 같습니다.
(참고: librustdoc는 라이브러리 크레이트입니다! rustdoc 바이너리는 src/tools/rustdoc에 있는 프로젝트를 사용하여 만들어집니다. 다만 그 프로젝트가 하는 일은 말 그대로 이 크레이트의 lib.rs에 있는 main()을 호출하는 것뿐이라는 점에 유의하십시오.)
치트 시트
- 시작하기 전에
./x setup tools를 실행하십시오. 이 명령은 rustdoc 및 기타 도구 개발에 알맞은 설정으로x를 구성하며, 여기에는 rustc를 직접 빌드하는 대신 사본을 내려받는 설정도 포함됩니다. - 컴파일 오류를 빠르게 확인하려면
./x check rustdoc를 사용하십시오. - 다른 프로젝트에서 실행할 수 있는 rustdoc를 만들려면
./x build library rustdoc를 사용하십시오.rustdoc --test를 사용하려면library/test를 추가하십시오.- rustup 환경에
stage2라는 사용자 정의 툴체인을 추가하려면rustup toolchain link stage2 build/host/stage2를 실행하십시오. 이 명령을 실행한 후에는 어느 디렉터리에서든cargo +stage2 doc를 실행하면 로컬에서 컴파일한 rustdoc로 빌드합니다.
- 이 rustdoc로 표준 라이브러리 문서를 생성하려면
./x doc library를 사용하십시오.- 완성된 문서는
build/host/doc(core,alloc,std아래)에서 확인할 수 있습니다. - 이 문서를 웹 서버에 복사하려면
build/host/doc전체를 복사하십시오. CSS, JS, 글꼴, 랜딩 페이지가 모두 그곳에 있기 때문입니다. - 프런트엔드를 디버깅할 때는
bootstrap.toml에서rust.docs-minification옵션을 비활성화하십시오.
- 완성된 문서는
- stage1 rustdoc로 테스트를 실행하려면
./x test tests/rustdoc*를 사용하십시오.- 테스트에 대한 자세한 내용은 Rustdoc 내부 구조를 참고하십시오.
- rustdoc의 JavaScript 검사(
eslint,es-check,tsc)를 실행하려면./x test tidy --extra-checks=js를 사용하십시오.
참고:
./x test tidy는 JS/TS 소스가 변경되면 이미 이 검사들을 자동으로 실행합니다.--extra-checks=js는 이 검사들을 명시적으로 강제 실행합니다.
JavaScript CI 검사
Rustdoc의 JavaScript와 TypeScript는 CI 과정에서 compiletest가 아니라 eslint, es-check, tsc로 검사합니다. 이 검사들은 tidy 작업의 일부로 실행됩니다.
./x test tidy --extra-checks=js
--extra-checks=js 플래그를 사용하면 CI에서 실행되는 프런트엔드 린트를 활성화합니다.
코드 구조
이 절의 모든 경로는 rust-lang/rust 저장소의 src/librustdoc/를 기준으로 한 상대 경로입니다.
- HTML 출력 코드의 대부분은
html/format.rs와html/render/mod.rs에 있습니다. 이 코드는impl std::fmt::Display를 반환하는 여러 함수로 이루어져 있습니다. - 위에서 언급한 함수들이 렌더링하는 데이터 타입은
clean/types.rs에 정의되어 있습니다.HIR와rustc_middle::tyIR로부터 이 타입들을 생성하는 함수는clean/mod.rs에 있습니다. - rustdoc을 테스트 하네스로 사용하는 데 특화된 부분은
doctest.rs에 있습니다. - Markdown 렌더러는
html/markdown.rs에서 로드되며, 여기에는 주어진 Markdown 블록에서 doctest를 추출하는 함수도 포함되어 있습니다. - 프런트엔드 CSS와 JavaScript는
html/static/에 저장되어 있습니다.- 참고로, JavaScript의 경우 타입 주석은 TypeScript 방식의 JSDoc 주석과 외부
.d.ts파일을 사용하여 작성합니다. 이렇게 하면 코드 자체는 평범하고 유효한 JavaScript로 유지됩니다.tsc는 린터로만 사용합니다.
- 참고로, JavaScript의 경우 타입 주석은 TypeScript 방식의 JSDoc 주석과 외부
테스트
rustdoc의 통합 테스트는 여러 테스트 스위트에 나뉘어 있습니다. 자세한 내용은 Rustdoc 테스트 스위트를 참고하십시오.
제약
JavaScript가 비활성화된 경우와 로컬 파일을 탐색하는 경우에도 rustdoc이 적절히 동작하도록 노력하고 있습니다. 지원하는 브라우저 목록이 있습니다.
로컬 파일(file:/// URL)을 지원하면 예상치 못한 제약이 몇 가지 생깁니다. localStorage나 Service Worker처럼 보안 출처(secure origin)가 필요한 일부 브라우저 기능은 안정적으로 동작하지 않습니다. 이러한 기능을 여전히 사용할 수는 있지만, 그 기능이 없어도 페이지를 사용할 수 있도록 해야 합니다.
Rustdoc은 함수 본문의 타입 검사를 하지 않습니다. 이는 typeck을 위한 내장 쿼리를 재정의하고, 이름 해석 오류를 무시하며, 불투명 타입을 해석하지 않는 방식으로 동작합니다. 여기에는 몇 가지 주의 사항이 따릅니다. 특히 rustdoc은 본문의 타입 검사가 필요한 컴파일러의 어떤 부분도 실행할 수 없습니다. 예를 들어 .rlib 파일을 생성하거나 대부분의 린트를 실행할 수 없습니다. 언젠가는 이 모델에서 벗어나고자 하지만, 이 모델을 사용하는 사람들을 위한 대안이 필요합니다. 여러 이전 Zulip 논의를 참고하십시오. 이 우회 방식을 제거하면 동작하지 않는 코드의 예시는 tests/rustdoc-ui/error-in-impl-trait를 참고하십시오.
동일한 출력 디렉터리에서 여러 번 실행하기
Rustdoc은 출력 디렉터리를 동일하게 설정한 채로 서로 다른 입력에 대해 여러 번 실행할 수 있습니다. cargo는 이 방식으로 현재 크레이트의 의존성 문서를 생성합니다. 사용자가 관심 있는 문서를 모두 담은 큰 문서 묶음을 원한다면 이 작업을 수동으로 할 수도 있습니다.
HTML은 크레이트마다 독립적으로 생성되지만, 출력 디렉터리에 크레이트를 추가할 때마다 갱신하는 크레이트 간 정보도 일부 있습니다.
crates<SUFFIX>.js에는 출력 디렉터리에 있는 모든 크레이트의 목록이 들어 있습니다.search-index<SUFFIX>.js에는 검색 가능한 모든 항목의 목록이 들어 있습니다.- 각 트레이트마다
implementors/.../trait.TraitName.js아래에 해당 트레이트 구현자의 목록을 담은 파일이 있습니다. 구현자는 트레이트와 다른 크레이트에 있을 수 있으며, 새 구현자를 발견할 때마다 JS 파일이 갱신됩니다.
사용 사례
rustdoc 작업 시 염두에 두어야 할 주요 사용 사례가 몇 가지 있습니다.
표준 라이브러리 문서
이 문서는 Rust 릴리스 과정의 일부로 https://doc.rust-lang.org/std에 게시됩니다. 안정 릴리스는 https://doc.rust-lang.org/1.57.0/std/처럼 버전이 지정된 특정 URL에도 업로드됩니다. 베타 문서와 나이틀리 문서는 https://doc.rust-lang.org/beta/std/와 https://doc.rust-lang.org/nightly/std/에 게시됩니다. 문서는 promote-release 도구로 업로드되며 CloudFront를 통해 S3에서 제공됩니다.
표준 라이브러리 문서에는 alloc, core, proc_macro, std, test의 다섯 크레이트가 포함되어 있습니다.
docs.rs
크레이트가 crates.io에 게시되면 docs.rs가 자동으로 해당 문서를 빌드하여 게시합니다. 예를 들어 https://docs.rs/serde/latest/serde/에 게시됩니다. docs.rs는 항상 현재 nightly rustdoc으로 빌드하므로, rustdoc에 반영한 모든 변경은 docs.rs에 즉시 공개적으로 영향을 미친다는 점에서 “즉시 안정(insta-stable)“합니다. 오래된 문서는 가끔씩만 다시 빌드되므로, docs.rs에서 오래된 릴리스를 둘러보면 UI가 조금씩 다르다는 것을 알 수 있습니다. 크레이트 작성자는 재빌드를 요청할 수 있으며, 재빌드는 최신 rustdoc으로 실행됩니다.
Docs.rs는 저장 공간을 절약하고 상단에 탐색 바를 표시하기 위해 rustdoc의 출력에 몇 가지 변환을 수행합니다. 특히 main.js나 rustdoc.css 같은 일부 정적 파일은 같은 버전의 rustdoc을 여러 번 호출할 때 공유될 수 있습니다. crates.js나 sidebar-items.js 같은 다른 파일은 호출마다 달라집니다. 글꼴 같은 나머지 파일은 결코 변경되지 않습니다. 이러한 범주는 src/librustdoc/html/render/write_shared.rs에 있는 SharedResource 열거형으로 구분됩니다.
docs.rs의 문서는 항상 한 번에 하나의 크레이트에 대해서만 생성되므로, 검색 기능과 사이드바 기능에는 현재 크레이트의 의존성이 포함되지 않습니다.
로컬에서 생성한 문서
크레이트 작성자는 로컬에 체크아웃한 크레이트에서 cargo doc --open을 실행하여 문서를 볼 수 있습니다. 이는 작성 중인 문서가 유용한지, 올바르게 표시되는지 확인하는 데 유용합니다. 직접 작성하지는 않았지만 사용하려는 크레이트의 문서를 보려는 사람에게도 유용할 수 있습니다. 두 경우 모두 --document-private-items Cargo 플래그를 사용하면 평소에는 표시되지 않는 비공개 메서드, 필드 등을 볼 수 있습니다.
기본적으로 cargo doc은 크레이트와 그 모든 의존성의 문서를 생성합니다. 이로 인해 문서 번들이 매우 커지고, 검색 코퍼스도 커져 검색이 느려질 수 있습니다. Cargo 플래그 --no-deps를 사용하면 이 동작을 막고 해당 크레이트의 문서만 생성합니다.
자체 호스팅 프로젝트 문서
일부 프로젝트는 자체적으로 문서를 호스팅합니다. 로컬에서 문서를 생성한 뒤 웹 서버에 복사하기만 하면 되므로 쉽게 할 수 있습니다. Rustdoc의 HTML 출력은 플래그를 통해 폭넓게 사용자 정의할 수 있습니다. 사용자는 테마를 추가하거나, 기본 테마를 설정하거나, 임의의 HTML을 삽입할 수 있습니다. 자세한 내용은 rustdoc --help를 참조하십시오.