15
15
"""Rules for generating documentation with `rustdoc` for Bazel built crates"""
16
16
17
17
load ("//rust/private:common.bzl" , "rust_common" )
18
- load ("//rust/private:rustc.bzl" , "add_crate_link_flags " , "add_edition_flags " )
19
- load ("//rust/private:utils.bzl" , "dedent" , "find_toolchain" )
18
+ load ("//rust/private:rustc.bzl" , "collect_deps " , "collect_inputs" , "construct_arguments " )
19
+ load ("//rust/private:utils.bzl" , "dedent" , "find_cc_toolchain" , " find_toolchain" )
20
20
21
- def _rust_doc_impl ( ctx ):
22
- """The implementation of the `rust_doc` rule
21
+ def _strip_crate_info_output ( crate_info ):
22
+ """Set the CrateInfo.output to None for a given CrateInfo provider.
23
23
24
24
Args:
25
- ctx (ctx): The rule's context object
25
+ crate_info (CrateInfo): A provider
26
+
27
+ Returns:
28
+ CrateInfo: A modified CrateInfo provider
26
29
"""
30
+ return rust_common .create_crate_info (
31
+ name = crate_info .name ,
32
+ type = crate_info .type ,
33
+ root = crate_info .root ,
34
+ srcs = crate_info .srcs ,
35
+ deps = crate_info .deps ,
36
+ proc_macro_deps = crate_info .proc_macro_deps ,
37
+ aliases = crate_info .aliases ,
38
+ # This crate info should have no output
39
+ output = None ,
40
+ edition = crate_info .edition ,
41
+ rustc_env = crate_info .rustc_env ,
42
+ is_test = crate_info .is_test ,
43
+ compile_data = crate_info .compile_data ,
44
+ )
27
45
28
- if ctx .attr .crate and ctx .attr .dep :
29
- fail ("{} should only use the `crate` attribute. `dep` is deprecated" .format (
30
- ctx .label ,
31
- ))
46
+ def rustdoc_compile_action (
47
+ ctx ,
48
+ toolchain ,
49
+ crate_info ,
50
+ output = None ,
51
+ rustdoc_flags = []):
52
+ """Create a struct of information needed for a `rustdoc` compile action based on crate passed to the rustdoc rule.
32
53
33
- crate = ctx .attr .crate or ctx .attr .dep
34
- if not crate :
35
- fail ("{} is missing the `crate` attribute" .format (ctx .label ))
54
+ Args:
55
+ ctx (ctx): The rule's context object.
56
+ toolchain (rust_toolchain): The currently configured `rust_toolchain`.
57
+ crate_info (CrateInfo): The provider of the crate passed to a rustdoc rule.
58
+ output (File, optional): An optional output a `rustdoc` action is intended to produce.
59
+ rustdoc_flags (list, optional): A list of `rustdoc` specific flags.
36
60
37
- crate_info = crate [rust_common .crate_info ]
38
- dep_info = crate [rust_common .dep_info ]
61
+ Returns:
62
+ struct: A struct of some `ctx.actions.run` arguments.
63
+ """
39
64
40
- toolchain = find_toolchain (ctx )
65
+ # If an output was provided, ensure it's used in rustdoc arguments
66
+ if output :
67
+ rustdoc_flags = [
68
+ "--output" ,
69
+ output .path ,
70
+ ] + rustdoc_flags
41
71
42
- rustdoc_inputs = depset (
43
- [c .output for c in dep_info .transitive_crates .to_list ()] +
44
- [toolchain .rust_doc ],
45
- transitive = [
46
- crate_info .srcs ,
47
- toolchain .rustc_lib .files ,
48
- toolchain .rust_lib .files ,
49
- ],
72
+ cc_toolchain , feature_configuration = find_cc_toolchain (ctx )
73
+
74
+ dep_info , build_info , linkstamps = collect_deps (
75
+ label = ctx .label ,
76
+ deps = crate_info .deps ,
77
+ proc_macro_deps = crate_info .proc_macro_deps ,
78
+ aliases = crate_info .aliases ,
50
79
)
51
80
52
- output_dir = ctx .actions .declare_directory (ctx .label .name )
53
- args = ctx .actions .args ()
54
- args .add (crate_info .root .path )
55
- args .add ("--crate-name" , crate_info .name )
56
- args .add ("--crate-type" , crate_info .type )
57
- if crate_info .type == "proc-macro" :
58
- args .add ("--extern" )
59
- args .add ("proc_macro" )
60
- args .add ("--output" , output_dir .path )
61
- add_edition_flags (args , crate_info )
62
-
63
- # nb. rustdoc can't do anything with native link flags; we must omit them.
64
- add_crate_link_flags (args , dep_info )
65
-
66
- args .add_all (ctx .files .markdown_css , before_each = "--markdown-css" )
67
- if ctx .file .html_in_header :
68
- args .add ("--html-in-header" , ctx .file .html_in_header )
69
- if ctx .file .html_before_content :
70
- args .add ("--html-before-content" , ctx .file .html_before_content )
71
- if ctx .file .html_after_content :
72
- args .add ("--html-after-content" , ctx .file .html_after_content )
81
+ compile_inputs , out_dir , build_env_files , build_flags_files , linkstamp_outs = collect_inputs (
82
+ ctx = ctx ,
83
+ file = ctx .file ,
84
+ files = ctx .files ,
85
+ linkstamps = linkstamps ,
86
+ toolchain = toolchain ,
87
+ cc_toolchain = cc_toolchain ,
88
+ feature_configuration = feature_configuration ,
89
+ crate_info = crate_info ,
90
+ dep_info = dep_info ,
91
+ build_info = build_info ,
92
+ )
73
93
74
- ctx .actions .run (
75
- executable = toolchain .rust_doc ,
76
- inputs = rustdoc_inputs ,
77
- outputs = [output_dir ],
78
- arguments = [args ],
79
- mnemonic = "Rustdoc" ,
80
- progress_message = "Generating rustdoc for {} ({} files)" .format (
81
- crate_info .name ,
82
- len (crate_info .srcs .to_list ()),
83
- ),
94
+ # Since this crate is not actually producing the output described by the
95
+ # given CrateInfo, this attribute needs to be stripped to allow the rest
96
+ # of the rustc functionality in `construct_arguments` to avoid generating
97
+ # arguments expecting to do so.
98
+ rustdoc_crate_info = _strip_crate_info_output (crate_info )
99
+
100
+ args , env = construct_arguments (
101
+ ctx = ctx ,
102
+ attr = ctx .attr ,
103
+ file = ctx .file ,
104
+ toolchain = toolchain ,
105
+ tool_path = toolchain .rust_doc .path ,
106
+ cc_toolchain = cc_toolchain ,
107
+ feature_configuration = feature_configuration ,
108
+ crate_info = rustdoc_crate_info ,
109
+ dep_info = dep_info ,
110
+ linkstamp_outs = linkstamp_outs ,
111
+ output_hash = None ,
112
+ rust_flags = rustdoc_flags ,
113
+ out_dir = out_dir ,
114
+ build_env_files = build_env_files ,
115
+ build_flags_files = build_flags_files ,
116
+ emit = [],
117
+ remap_path_prefix = None ,
118
+ force_link = True ,
84
119
)
85
120
86
- # This rule does nothing without a single-file output, though the directory should've sufficed.
87
- _zip_action (ctx , output_dir , ctx .outputs .rust_doc_zip )
121
+ return struct (
122
+ executable = ctx .executable ._process_wrapper ,
123
+ inputs = depset ([crate_info .output ], transitive = [compile_inputs ]),
124
+ env = env ,
125
+ arguments = args .all ,
126
+ tools = [toolchain .rust_doc ],
127
+ )
88
128
89
- def _zip_action (ctx , input_dir , output_zip ):
129
+ def _zip_action (ctx , input_dir , output_zip , crate_label ):
90
130
"""Creates an archive of the generated documentation from `rustdoc`
91
131
92
132
Args:
93
133
ctx (ctx): The `rust_doc` rule's context object
94
134
input_dir (File): A directory containing the outputs from rustdoc
95
135
output_zip (File): The location of the output archive containing generated documentation
136
+ crate_label (Label): The label of the crate docs are being generated for.
96
137
"""
97
138
args = ctx .actions .args ()
98
139
args .add (ctx .executable ._zipper )
@@ -104,9 +145,70 @@ def _zip_action(ctx, input_dir, output_zip):
104
145
inputs = [input_dir ],
105
146
outputs = [output_zip ],
106
147
arguments = [args ],
148
+ mnemonic = "RustdocZip" ,
149
+ progress_message = "Creating RustdocZip for {}" .format (crate_label ),
107
150
tools = [ctx .executable ._zipper ],
108
151
)
109
152
153
+ def _rust_doc_impl (ctx ):
154
+ """The implementation of the `rust_doc` rule
155
+
156
+ Args:
157
+ ctx (ctx): The rule's context object
158
+ """
159
+
160
+ if ctx .attr .crate and ctx .attr .dep :
161
+ fail ("{} should only use the `crate` attribute. `dep` is deprecated" .format (
162
+ ctx .label ,
163
+ ))
164
+
165
+ crate = ctx .attr .crate or ctx .attr .dep
166
+ if not crate :
167
+ fail ("{} is missing the `crate` attribute" .format (ctx .label ))
168
+
169
+ crate_info = crate [rust_common .crate_info ]
170
+ dep_info = crate [rust_common .dep_info ]
171
+
172
+ output_dir = ctx .actions .declare_directory ("{}.rustdoc" .format (ctx .label .name ))
173
+
174
+ # Add the current crate as an extern for the compile action
175
+ rustdoc_flags = [
176
+ "--extern" ,
177
+ "{}={}" .format (crate_info .name , crate_info .output .path ),
178
+ ]
179
+
180
+ action = rustdoc_compile_action (
181
+ ctx = ctx ,
182
+ toolchain = find_toolchain (ctx ),
183
+ crate_info = crate_info ,
184
+ output = output_dir ,
185
+ rustdoc_flags = rustdoc_flags ,
186
+ )
187
+
188
+ ctx .actions .run (
189
+ mnemonic = "Rustdoc" ,
190
+ progress_message = "Generating Rustdoc for {}" .format (crate .label ),
191
+ outputs = [output_dir ],
192
+ executable = action .executable ,
193
+ inputs = action .inputs ,
194
+ env = action .env ,
195
+ arguments = action .arguments ,
196
+ tools = action .tools ,
197
+ )
198
+
199
+ # This rule does nothing without a single-file output, though the directory should've sufficed.
200
+ _zip_action (ctx , output_dir , ctx .outputs .rust_doc_zip , crate .label )
201
+
202
+ return [
203
+ DefaultInfo (
204
+ files = depset ([ctx .outputs .rust_doc_zip ]),
205
+ ),
206
+ OutputGroupInfo (
207
+ rustdoc_dir = depset ([output_dir ]),
208
+ rustdoc_zip = depset ([ctx .outputs .rust_doc_zip ]),
209
+ ),
210
+ ]
211
+
110
212
rust_doc = rule (
111
213
doc = dedent ("""\
112
214
Generates code documentation.
@@ -179,17 +281,31 @@ rust_doc = rule(
179
281
doc = "CSS files to include via `<link>` in a rendered Markdown file." ,
180
282
allow_files = [".css" ],
181
283
),
284
+ "_cc_toolchain" : attr .label (
285
+ doc = "In order to use find_cpp_toolchain, you must define the '_cc_toolchain' attribute on your rule or aspect." ,
286
+ default = "@bazel_tools//tools/cpp:current_cc_toolchain" ,
287
+ ),
182
288
"_dir_zipper" : attr .label (
289
+ doc = "A tool that orchestrates the creation of zip archives for rustdoc outputs." ,
183
290
default = Label ("//util/dir_zipper" ),
184
291
cfg = "exec" ,
185
292
executable = True ,
186
293
),
294
+ "_process_wrapper" : attr .label (
295
+ doc = "A process wrapper for running rustdoc on all platforms" ,
296
+ default = Label ("@rules_rust//util/process_wrapper" ),
297
+ executable = True ,
298
+ allow_single_file = True ,
299
+ cfg = "exec" ,
300
+ ),
187
301
"_zipper" : attr .label (
302
+ doc = "A Bazel provided tool for creating archives" ,
188
303
default = Label ("@bazel_tools//tools/zip:zipper" ),
189
304
cfg = "exec" ,
190
305
executable = True ,
191
306
),
192
307
},
308
+ fragments = ["cpp" ],
193
309
outputs = {
194
310
"rust_doc_zip" : "%{name}.zip" ,
195
311
},
0 commit comments