Skip to content

Commit 4b076f6

Browse files
committed
manishearth nits + stabilize crate-info.json
* Explain default behavior of rustdoc in Reference-level explanation * Flag summary in Guide-level explanation * Say that crate-info.json is stable because build systems need to rely on it * t,s,i -> trait-crate, struct-crate, index-crate * T, S -> Trait, Struct
1 parent b0dc37d commit 4b076f6

File tree

1 file changed

+106
-76
lines changed

1 file changed

+106
-76
lines changed

text/0000-mergeable-rustdoc-cross-crate-info.md

Lines changed: 106 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -25,109 +25,133 @@ These considerations motivate adding an option for outputting partial CCI (parts
2525

2626
# Guide-level explanation
2727

28-
In this example, there is a crate `t` which defines a trait `T`, and a crate `s` which defines a struct `S` that implements `T`. Our goal in this demo is for `S` to appear as an implementer in `T`'s docs, even if `s` and `t` are documented independently. This guide will be assuming that we want a crate `i` that serves as our documentation index. See the Unresolved questions section for ideas that do not require an index crate.
28+
## New flag summary
29+
30+
More details are in the Reference-level explanation.
31+
32+
* `--parts-out-dir=doc.parts/<crate-name>`: Write information from the current crate to a provided directory.
33+
* `--include-parts-dir=doc.parts/<crate-name>`: Include cross-crate information from these previously written `doc.parts` directories into a collection that will be written by the current invocation of rustdoc.
34+
* `--merge=none`: Do not write cross-crate information to the `--out-dir`.
35+
* `--merge=shared`: Read cross-crate information from the `--out-dir`, and write cross-crate information from the current crate and any crates included via `--include-parts-dir` to the `--out-dir`.
36+
* `--merge=finalize`: Write cross-crate information from the current crate and any crates included via `--include-parts-dir`, overwriting conflicting files in the `--out-dir`.
37+
38+
## Example
39+
40+
In this example, there is a crate `trait-crate` which defines a trait `Trait`, and a crate `struct-crate` which defines a struct `Struct` that implements `Trait`. Our goal in this demo is for `Struct` to appear as an implementer in `Trait`'s docs, even if `struct-crate` and `trait-crate` are documented independently. This guide will be assuming that we want a crate `index-crate` that serves as our documentation index. See the Unresolved questions section for ideas that do not require an index crate.
2941

3042
```shell
31-
mkdir -p t/src s/src i/src merged/doc
32-
echo "pub trait T {}" > t/src/lib.rs
33-
echo "pub struct S; impl t::T for S {}" > s/src/lib.rs
43+
mkdir -p trait-crate/src struct-crate/src index-crate/src merged/doc
44+
echo "pub trait Trait {}" > trait-crate/src/lib.rs
45+
echo "pub struct Struct; impl trait-crate::Trait for Struct {}" > struct-crate/src/lib.rs
3446
MERGED=file://$(realpath merged/doc)
3547
```
3648

37-
[Actively use](https://doc.rust-lang.org/rustc/command-line-arguments.html#--extern-specify-where-an-external-library-is-located) `t` and `s` in `i`. The `extern crate` declarations are not needed if the crates are otherwise referenced in the index; intra-doc links are enough.
49+
[Actively use](https://doc.rust-lang.org/rustc/command-line-arguments.html#--extern-specify-where-an-external-library-is-located) `trait-crate` and `struct-crate` in `index-crate`. The `extern crate` declarations are not needed if the crates are otherwise referenced in the index; intra-doc links are enough.
3850

3951
```shell
40-
echo "extern crate t; extern crate s;" > i/src/lib.rs
52+
echo "extern crate trait-crate; extern crate struct-crate;" > index-crate/src/lib.rs
4153
```
4254

4355
Compile the crates.
4456

4557
```shell
46-
rustc --crate-name=t --crate-type=lib --edition=2021 --emit=metadata --out-dir=t/target t/src/lib.rs
47-
rustc --crate-name=s --crate-type=lib --edition=2021 --emit=metadata --out-dir=s/target --extern t=t/target/libt.rmeta s/src/lib.rs
58+
rustc \
59+
--crate-name=trait-crate \
60+
--crate-type=lib \
61+
--edition=2021 \
62+
--emit=metadata \
63+
--out-dir=trait-crate/target \
64+
trait-crate/src/lib.rs
65+
rustc \
66+
--crate-name=struct-crate \
67+
--crate-type=lib \
68+
--edition=2021 \
69+
--emit=metadata \
70+
--out-dir=struct-crate/target \
71+
--extern trait-crate=trait-crate/target/libt.rmeta struct-crate/src/lib.rs
4872
```
4973

50-
Document `s` and `t` independently, providing `--merge=none`, `--parts-out-dir`.
74+
Document `struct-crate` and `trait-crate` independently, providing `--merge=none`, `--parts-out-dir`.
5175

5276
```shell
5377
rustdoc \
5478
-Z unstable-options \
55-
--crate-name=t \
79+
--crate-name=trait-crate \
5680
--crate-type=lib \
5781
--edition=2021 \
58-
--out-dir=t/target/doc \
59-
--extern-html-root-url t=$MERGED \
82+
--out-dir=trait-crate/target/doc \
83+
--extern-html-root-url trait-crate=$MERGED \
6084
--merge=none \
61-
--parts-out-dir=t/target/doc.parts/t \
62-
t/src/lib.rs
85+
--parts-out-dir=trait-crate/target/doc.parts/trait-crate \
86+
trait-crate/src/lib.rs
6387
rustdoc \
6488
-Z unstable-options \
65-
--crate-name=s \
89+
--crate-name=struct-crate \
6690
--crate-type=lib \
6791
--edition=2021 \
68-
--out-dir=s/target/doc \
69-
--extern-html-root-url s=$MERGED \
70-
--extern-html-root-url t=$MERGED \
92+
--out-dir=struct-crate/target/doc \
93+
--extern-html-root-url struct-crate=$MERGED \
94+
--extern-html-root-url trait-crate=$MERGED \
7195
--merge=none \
72-
--parts-out-dir=s/target/doc.parts/s \
73-
--extern t=t/target/libt.rmeta \
74-
s/src/lib.rs
96+
--parts-out-dir=struct-crate/target/doc.parts/struct-crate \
97+
--extern trait-crate=trait-crate/target/libt.rmeta \
98+
struct-crate/src/lib.rs
7599
```
76100

77-
Link everything with a final invocation of rustdoc on `i`. We will provide `--merge=finalize`, `--include-parts-dir`, and `--include-rendered-docs`. See the Reference-level explanation about these flags.
101+
Link everything with a final invocation of rustdoc on `index-crate`. We will provide `--merge=finalize`, `--include-parts-dir`, and `--include-rendered-docs`. See the Reference-level explanation about these flags.
78102

79103
```shell
80104
rustdoc \
81105
-Z unstable-options \
82-
--crate-name=i \
106+
--crate-name=index-crate \
83107
--crate-type=lib \
84108
--edition=2021 \
85109
--enable-index-page \
86-
--out-dir=i/target/doc \
87-
--extern-html-root-url s=$MERGED \
88-
--extern-html-root-url t=$MERGED \
89-
--extern-html-root-url i=$MERGED \
110+
--out-dir=index-crate/target/doc \
111+
--extern-html-root-url struct-crate=$MERGED \
112+
--extern-html-root-url trait-crate=$MERGED \
113+
--extern-html-root-url index-crate=$MERGED \
90114
--merge=finalize \
91-
--include-parts-dir=t/target/doc.parts/t \
92-
--include-parts-dir=s/target/doc.parts/s \
93-
--extern t=t/target/libt.rmeta \
94-
--extern s=s/target/libs.rmeta \
95-
--include-rendered-docs=t/target/doc/t \
96-
--include-rendered-docs=s/target/doc/s \
97-
-L t/target \
98-
i/src/lib.rs
115+
--include-parts-dir=trait-crate/target/doc.parts/trait-crate \
116+
--include-parts-dir=struct-crate/target/doc.parts/struct-crate \
117+
--extern trait-crate=trait-crate/target/libt.rmeta \
118+
--extern struct-crate=struct-crate/target/libs.rmeta \
119+
--include-rendered-docs=trait-crate/target/doc/trait-crate \
120+
--include-rendered-docs=struct-crate/target/doc/struct-crate \
121+
-L trait-crate/target \
122+
index-crate/src/lib.rs
99123
```
100124

101125
Browse `merged/doc/index.html` with cross-crate information.
102126

103-
In general, instead of two crates in the environment (`s` and `t`) you could have thousands. Upon any changes, only the index and the crates that are changed have to be re-documented.
127+
In general, instead of two crates in the environment (`struct-crate` and `trait-crate`) you could have thousands. Upon any changes, only the index and the crates that are changed have to be re-documented.
104128

105129
<details>
106130
<summary>Click here for a directory listing after running the example above.</summary>
107131

108132
<pre>
109133
$ tree . -a
110134
.
111-
├── i
135+
├── index-crate
112136
│ ├── src
113137
│ │ └── lib.rs
114138
│ └── target
115139
│ └── doc
116140
│ ├── crates.js
117141
│ ├── help.html
118-
│ ├── i
142+
│ ├── index-crate
119143
│ │ ├── all.html
120144
│ │ ├── index.html
121145
│ │ └── sidebar-items.js
122146
│ ├── index.html
123147
│ ├── .lock
124148
│ ├── search.desc
125-
│ │ └── i
126-
│ │ └── i-desc-0-.js
149+
│ │ └── index-crate
150+
│ │ └── index-crate-desc-0-.js
127151
│ ├── search-index.js
128152
│ ├── settings.html
129153
│ ├── src
130-
│ │ └── i
154+
│ │ └── index-crate
131155
│ │ └── lib.rs.html
132156
│ ├── src-files.js
133157
│ ├── static.files
@@ -145,48 +169,48 @@ $ tree . -a
145169
│ │ └── unwind_safe
146170
│ │ ├── trait.RefUnwindSafe.js
147171
│ │ └── trait.UnwindSafe.js
148-
│ └── t
149-
│ └── trait.T.js
172+
│ └── trait-crate
173+
│ └── trait.Trait.js
150174
├── merged
151175
│ └── doc
152176
│ ├── crates.js
153177
│ ├── help.html
154-
│ ├── i
178+
│ ├── index-crate
155179
│ │ ├── all.html
156180
│ │ ├── index.html
157181
│ │ └── sidebar-items.js
158182
│ ├── index.html
159-
│ ├── s
183+
│ ├── struct-crate
160184
│ │ ├── all.html
161185
│ │ ├── index.html
162186
│ │ ├── sidebar-items.js
163-
│ │ └── struct.S.html
187+
│ │ └── struct.Struct.html
164188
│ ├── search.desc
165-
│ │ ├── i
166-
│ │ │ └── i-desc-0-.js
167-
│ │ ├── s
168-
│ │ │ └── s-desc-0-.js
169-
│ │ └── t
170-
│ │ └── t-desc-0-.js
189+
│ │ ├── index-crate
190+
│ │ │ └── index-crate-desc-0-.js
191+
│ │ ├── struct-crate
192+
│ │ │ └── struct-crate-desc-0-.js
193+
│ │ └── trait-crate
194+
│ │ └── trait-crate-desc-0-.js
171195
│ ├── search-index.js
172196
│ ├── settings.html
173197
│ ├── src
174-
│ │ ├── i
198+
│ │ ├── index-crate
175199
│ │ │ └── lib.rs.html
176-
│ │ ├── s
200+
│ │ ├── struct-crate
177201
│ │ │ └── lib.rs.html
178-
│ │ └── t
202+
│ │ └── trait-crate
179203
│ │ └── lib.rs.html
180204
│ ├── src-files.js
181205
│ ├── static.files
182206
│ │ ├── COPYRIGHT-23e9bde6c69aea69.txt
183207
│ │ ├── favicon-2c020d218678b618.svg
184208
│ │ └── <rest of the contents excluded>
185-
│ ├── t
209+
│ ├── trait-crate
186210
│ │ ├── all.html
187211
│ │ ├── index.html
188212
│ │ ├── sidebar-items.js
189-
│ │ └── trait.T.html
213+
│ │ └── trait.Trait.html
190214
│ └── trait.impl
191215
│ ├── core
192216
│ │ ├── marker
@@ -198,52 +222,52 @@ $ tree . -a
198222
│ │ └── unwind_safe
199223
│ │ ├── trait.RefUnwindSafe.js
200224
│ │ └── trait.UnwindSafe.js
201-
│ └── t
202-
│ └── trait.T.js
203-
├── s
225+
│ └── trait-crate
226+
│ └── trait.Trait.js
227+
├── struct-crate
204228
│ ├── src
205229
│ │ └── lib.rs
206230
│ └── target
207231
│ ├── doc
208232
│ │ ├── help.html
209233
│ │ ├── .lock
210-
│ │ ├── s
234+
│ │ ├── struct-crate
211235
│ │ │ ├── all.html
212236
│ │ │ ├── index.html
213237
│ │ │ ├── sidebar-items.js
214-
│ │ │ └── struct.S.html
238+
│ │ │ └── struct.Struct.html
215239
│ │ ├── search.desc
216-
│ │ │ └── s
217-
│ │ │ └── s-desc-0-.js
240+
│ │ │ └── struct-crate
241+
│ │ │ └── struct-crate-desc-0-.js
218242
│ │ ├── settings.html
219243
│ │ └── src
220-
│ │ └── s
244+
│ │ └── struct-crate
221245
│ │ └── lib.rs.html
222246
│ ├── doc.parts
223-
│ │ └── s
247+
│ │ └── struct-crate
224248
│ │ └── crate-info.json
225249
│ └── libs.rmeta
226-
└── t
250+
└── trait-crate
227251
├── src
228252
│ └── lib.rs
229253
└── target
230254
├── doc
231255
│ ├── help.html
232256
│ ├── .lock
233257
│ ├── search.desc
234-
│ │ └── t
235-
│ │ └── t-desc-0-.js
258+
│ │ └── trait-crate
259+
│ │ └── trait-crate-desc-0-.js
236260
│ ├── settings.html
237261
│ ├── src
238-
│ │ └── t
262+
│ │ └── trait-crate
239263
│ │ └── lib.rs.html
240-
│ └── t
264+
│ └── trait-crate
241265
│ ├── all.html
242266
│ ├── index.html
243267
│ ├── sidebar-items.js
244-
│ └── trait.T.html
268+
│ └── trait.Trait.html
245269
├── doc.parts
246-
│ └── t
270+
│ └── trait-crate
247271
│ └── crate-info.json
248272
└── libt.rmeta
249273
</pre>
@@ -280,11 +304,15 @@ When a user documents the final crate, they will provide `--include-parts-dir=<
280304

281305
The existing cross-crate information files, like `search-index.js`, all are lists of elements, rendered in an specified way (e.g. as a JavaScript file with a JSON array or an HTML index page containing an unordered list). The current rustdoc (in `write_shared`) pushes the current crate's version of the CCI into the one that is already found in `doc`, and renders a new version. The rest of the proposal uses the term **part** to refer to the pre-merged, pre-rendered element of the CCI. This proposal does not add any new CCI or change their contents (modulo sorting order, whitespace).
282306

283-
## New directory: `doc.parts`
307+
## New directory: `doc.parts/<crate-name>/crate-info.json`
284308

285309
`doc.parts` is a directory that holds the partial contents and destination of several cross-crate information files. It only encodes information about a single-crate. This file is written if `--parts-out-dir` is provided. The current crate's information and any `doc.parts` added through `--include-parts-dir` are merged and rendered if `--merge=shared` or `--merge=finalize` are provided.
286310

287-
The content of `doc.parts` is unstable. Rustdoc only guarantees that it will accept `doc.parts` files written by the same version of rustdoc, and rustdoc is the only explicitly supported consumer of `doc.parts`. Only the presence of `doc.parts` is stabilized. Non-normatively, there are several pieces of information that `doc.parts` may contain:
311+
The directory `doc.parts` contains subdirectories for each crate. The crate names are chosen by the caller that invokes rustdoc, and are `--include-parts-dir` and `--parts-out-dir`. These crate names are arbitrary from the perspective of rustdoc, with the constraint that they must be unique. Rustdoc will write a file called `crate-info.json`, whose contents are unstable, to the subdirectory provided to `--parts-out-dir`. Even though the contents of `crate-info.json` are only intended to be consumed by rustdoc, its existence must be stabilized due to the fact that it may be declared to build systems.
312+
313+
This directory structure may change with a new edition.
314+
315+
Rustdoc only guarantees that it will accept `doc.parts` files written by the same version of rustdoc, and rustdoc is the only explicitly supported consumer of `doc.parts`. Only the presence of `doc.parts`, and its opaque child `crate-info.json`, are stabilized. Non-normatively, there are several pieces of information that `doc.parts` may contain:
288316

289317
* Partial source file index for generating `doc/src-files.js`.
290318
* Partial search index for generating `doc/search-index.js`.
@@ -303,6 +331,8 @@ Crates `--include-parts-dir`ed will not appear in `doc.parts`, as `doc.parts` on
303331

304332
If this flag is not provided, no `doc.parts` will be written.
305333

334+
The output generated by this flag may be consumed by a future invocation to rustdoc that provides `--include-parts-dir=<path/to>/doc.parts/<crate-name>`.
335+
306336
## New flag: `--include-parts-dir=<path/to/doc.parts/crate-name>`
307337

308338
If this flag is provided, rustdoc will expect that a previous invocation of rustdoc was made with `--parts-out-dir=<path/to/doc.parts/crate-name>`. It will append the parts from the previous invocation to the ones it will render in the doc root (`--out-dir`). The info that's included is not written to its own `doc.parts`, as `doc.parts` only holds the CCI parts for the current crate.
@@ -323,7 +353,7 @@ When `write_rendered_cci` is active, rustdoc will output the rendered parts to t
323353

324354
When `read_rendered_cci` is active, rustdoc will look in the `--out-dir` for rendered cross-crate info files. These files will be used as the base. Any new parts that rustdoc generates with its current invocation and any parts fetched with `include-parts-dir` will be appended to these base files. When it is disabled, the cross-crate info files start empty and are populated with the current crate's info and any crates fetched with `--include-parts-dir`.
325355

326-
* `--merge=shared` (`read_rendered_cci && write_rendered_cci`) is the default, and reflects the current behavior of rustdoc.
356+
* `--merge=shared` (`read_rendered_cci && write_rendered_cci`) is the default, and reflects the current behavior of rustdoc. Rustdoc will look in its `--out-dir` for pre-existing cross-crate information files, and append information to these files from the current crate and any crates referenced through `--include-parts-dir`.
327357
* `--merge=none` (`!read_rendered_cci && !write_rendered_cci`) means that rustdoc will ignore the cross-crate files in the doc root. Only generate item docs.
328358
* `--merge=finalize` (`!read_rendered_cci && write_rendered_cci`) outputs crate info based only on the current crate and `--include-parts-dir`'ed crates.
329359
* A (`read_rendered_cci && !write_rendered_cci`) mode would be useless, since the data that is read would be ignored and not written.

0 commit comments

Comments
 (0)