1313load ("@bazel_skylib//rules:common_settings.bzl" , "BuildSettingInfo" )
1414load ("@rules_cc//cc:find_cc_toolchain.bzl" , "find_cc_toolchain" , "use_cc_toolchain" )
1515load ("@rules_cc//cc/common:cc_common.bzl" , "cc_common" )
16+ load ("@rules_cc//cc/common:cc_info.bzl" , "CcInfo" )
17+
18+ # Providers and aspects used to adapt C/C++ targets for the parser action.
1619
1720def _extract_files_from_attr (attr , attr_name ):
1821 files = []
@@ -21,7 +24,13 @@ def _extract_files_from_attr(attr, attr_name):
2124 files .extend (src .files .to_list ())
2225 return files
2326
24- SourceFilesInfo = provider (fields = ["files" , "inputs" ])
27+ SourceFilesInfo = provider (
28+ doc = "Source files and transitive inputs collected for parser actions." ,
29+ fields = {
30+ "files" : "depset of source files to parse for this target." ,
31+ "inputs" : "depset of source and header inputs needed by the parser action." ,
32+ },
33+ )
2534
2635def _cc_sources_aspect_impl (target , ctx ):
2736 direct_srcs = _extract_files_from_attr (ctx .rule .attr , "srcs" )
@@ -64,7 +73,15 @@ CompilationFlagsInfo = provider(
6473 },
6574)
6675
67- def _collect_from_cc_info (target ):
76+ CppParserInfo = provider (
77+ doc = "Outputs generated by the C/C++ parser." ,
78+ fields = {
79+ "class_fbs" : "Class diagram FlatBuffer output file." ,
80+ "debug_json" : "Debug JSON sidecar output file. (Optional)" ,
81+ },
82+ )
83+
84+ def _collect_from_cc_info (target , ctx ):
6885 flags = []
6986
7087 if CcInfo in target :
@@ -90,7 +107,7 @@ def _compilation_flags_aspect_impl(target, ctx):
90107 if CompilationFlagsInfo in dep :
91108 transitive .append (dep [CompilationFlagsInfo ].flags )
92109
93- direct_flags = _collect_from_cc_info (target )
110+ direct_flags = _collect_from_cc_info (target , ctx )
94111
95112 return [
96113 CompilationFlagsInfo (
@@ -103,6 +120,53 @@ compilation_flags_aspect = aspect(
103120 attr_aspects = ["deps" ],
104121)
105122
123+ # Public integration helpers for rules that want to reuse the parser action.
124+
125+ def cpp_parser_target_aspects ():
126+ """Return aspects required on attrs whose targets will be parsed."""
127+
128+ return [cc_sources_aspect , compilation_flags_aspect ]
129+
130+ def has_cpp_parser_inputs (target ):
131+ """Check whether a target has the providers needed by run_cpp_parser_action."""
132+
133+ return (CcInfo in target and
134+ SourceFilesInfo in target and
135+ CompilationFlagsInfo in target and
136+ bool (target [SourceFilesInfo ].files .to_list ()))
137+
138+ def cpp_parser_action_internal_attrs ():
139+ """Return private attrs required by run_cpp_parser_action callers."""
140+
141+ return {
142+ "_tool" : attr .label (
143+ default = Label ("//cpp/libclang:clang_rs_parser" ),
144+ executable = True ,
145+ cfg = "exec" ,
146+ doc = "Internal libclang-based parser backend." ,
147+ ),
148+ "_libclang" : attr .label (
149+ allow_single_file = True ,
150+ default = "@llvm_toolchain_llvm//:lib/libclang.so" ,
151+ ),
152+ "_llvm_cxx_builtin_include" : attr .label (
153+ default = "@llvm_toolchain_llvm//:cxx_builtin_include" ,
154+ doc = "LLVM toolchain filegroup containing the libc++ header directory (include/c++) " +
155+ "and the clang resource include directory (lib/clang/<version>/include)." ,
156+ ),
157+ "_llvm_extra_config_site" : attr .label (
158+ default = "@llvm_toolchain_llvm//:extra_config_site" ,
159+ doc = "LLVM toolchain filegroup containing the arch-specific __config_site file " +
160+ "(include/<triple>/c++/v1/__config_site) used to locate the ABI include path." ,
161+ ),
162+ "_log_level" : attr .label (
163+ default = Label ("//cpp/libclang:log_level" ),
164+ doc = "Build setting that controls clang_rs_parser log level." ,
165+ ),
166+ }
167+
168+ # Parser action implementation.
169+
106170def _detect_standard_from_flags (ctx ):
107171 """
108172 Fall back: compile the action's compile flags and look for -std=.
@@ -190,58 +254,87 @@ def _collect_required_llvm_include_args(cxx_builtin_include_files, extra_config_
190254
191255 return result
192256
193- def _cpp_parser_impl (ctx ):
194- output_dir = ctx .actions .declare_directory (
195- ctx .label .name + "_result" ,
257+ def run_cpp_parser_action (
258+ ctx ,
259+ * ,
260+ target ,
261+ output_prefix ,
262+ tool ,
263+ libclang ,
264+ llvm_cxx_builtin_include ,
265+ llvm_extra_config_site ,
266+ log_level ,
267+ extra_args = [],
268+ emit_debug_json = False ):
269+ """Register the libclang parser action and return its declared outputs.
270+
271+ The target must be analyzed with cpp_parser_target_aspects() before this
272+ helper is called. Use has_cpp_parser_inputs() when the caller accepts mixed
273+ implementation target types.
274+ """
275+
276+ class_fbs_output = ctx .actions .declare_file (
277+ "{}_{}" .format (output_prefix , "class_diagram.fbs.bin" ),
196278 )
197- libclang = ctx .file ._libclang
198279
199- args = []
280+ debug_json_output = None
281+ if emit_debug_json :
282+ debug_json_output = ctx .actions .declare_file (
283+ "{}_{}" .format (output_prefix , "debug.json" ),
284+ )
285+
286+ tool_files_to_run = tool [DefaultInfo ].files_to_run
200287
288+ args = []
201289 args += [
202- "--output-dir " ,
203- output_dir .path ,
290+ "--class-fbs-output " ,
291+ class_fbs_output .path ,
204292 ]
205293
206- if ctx .attr .emit_debug_json :
207- args .append ("--json" )
294+ if debug_json_output :
295+ args += [
296+ "--debug-json-output" ,
297+ debug_json_output .path ,
298+ ]
208299
209- target_compilation_flags_list = ctx . attr . target [CompilationFlagsInfo ].flags .to_list ()
300+ target_compilation_flags_list = target [CompilationFlagsInfo ].flags .to_list ()
210301
211- cxx_builtin_include_files = ctx . attr . _llvm_cxx_builtin_include .files .to_list ()
212- extra_config_site_files = ctx . attr . _llvm_extra_config_site .files .to_list ()
302+ cxx_builtin_include_files = llvm_cxx_builtin_include .files .to_list ()
303+ extra_config_site_files = llvm_extra_config_site .files .to_list ()
213304 llvm_include_args = _collect_required_llvm_include_args (cxx_builtin_include_files , extra_config_site_files )
214305
215- extra_args = [
306+ parser_extra_args = [
216307 _detect_standard_from_flags (ctx ),
217308 "-nostdinc++" ,
218309 ]
219- extra_args += llvm_include_args
220- extra_args += target_compilation_flags_list + ctx . attr . extra_args
221- for ea in extra_args :
310+ parser_extra_args += llvm_include_args
311+ parser_extra_args += target_compilation_flags_list + extra_args
312+ for ea in parser_extra_args :
222313 args += ["--extra-arg" , ea ]
223314
224- target_source_files_info = ctx . attr . target [SourceFilesInfo ]
315+ target_source_files_info = target [SourceFilesInfo ]
225316 target_source_files_list = target_source_files_info .files .to_list ()
226317 target_source_inputs_list = target_source_files_info .inputs .to_list ()
227318
228- # extend args with input sources
229- if SourceFilesInfo in ctx .attr .target :
230- args += [file .path for file in target_source_files_list ]
319+ args += ["--input" ] + [file .path for file in target_source_files_list ]
231320
232321 inputs = [
233322 libclang ,
234323 ] + target_source_inputs_list + cxx_builtin_include_files + extra_config_site_files
235324
325+ outputs = [class_fbs_output ]
326+ if debug_json_output :
327+ outputs .append (debug_json_output )
328+
236329 ctx .actions .run (
237330 inputs = inputs ,
238- outputs = [ output_dir ] ,
239- executable = ctx .executable . tool ,
240- tools = [ctx . attr . tool [ DefaultInfo ]. files_to_run ],
331+ outputs = outputs ,
332+ executable = tool_files_to_run .executable ,
333+ tools = [tool_files_to_run ],
241334 arguments = args ,
242335 env = {
243336 "LIBCLANG_PATH" : libclang .dirname ,
244- "LIBCLANG_LOG" : ctx . attr . _log_level [ BuildSettingInfo ]. value ,
337+ "LIBCLANG_LOG" : log_level ,
245338 },
246339 mnemonic = "CppAnalyze" ,
247340 # this is required to parse some system headers
@@ -251,49 +344,62 @@ def _cpp_parser_impl(ctx):
251344 progress_message = "Running C++ AST analysis: %s" % ctx .label ,
252345 )
253346
254- return DefaultInfo (
255- files = depset ([ output_dir ]) ,
256- runfiles = ctx . runfiles ( files = [ output_dir ]) ,
347+ return struct (
348+ class_fbs = class_fbs_output ,
349+ debug_json = debug_json_output ,
257350 )
258351
259- cpp_parser = rule (
260- implementation = _cpp_parser_impl ,
261- attrs = {
262- "target" : attr .label (
263- aspects = [cc_sources_aspect , compilation_flags_aspect ],
264- mandatory = True ,
265- ),
266- "tool" : attr .label (
267- executable = True ,
268- cfg = "exec" ,
269- mandatory = True ,
270- ),
271- "extra_args" : attr .string_list (
272- default = [],
273- ),
274- "emit_debug_json" : attr .bool (
275- default = False ,
276- doc = "Emit debug.json alongside the FlatBuffer output. Intended for tests/debugging." ,
277- ),
278- "_libclang" : attr .label (
279- allow_single_file = True ,
280- default = "@llvm_toolchain_llvm//:lib/libclang.so" ,
281- ),
282- "_llvm_cxx_builtin_include" : attr .label (
283- default = "@llvm_toolchain_llvm//:cxx_builtin_include" ,
284- doc = "LLVM toolchain filegroup containing the libc++ header directory (include/c++) " +
285- "and the clang resource include directory (lib/clang/<version>/include)." ,
286- ),
287- "_llvm_extra_config_site" : attr .label (
288- default = "@llvm_toolchain_llvm//:extra_config_site" ,
289- doc = "LLVM toolchain filegroup containing the arch-specific __config_site file " +
290- "(include/<triple>/c++/v1/__config_site) used to locate the ABI include path." ,
352+ # cpp_parser rule
353+
354+ def _cpp_parser_impl (ctx ):
355+ outputs = run_cpp_parser_action (
356+ ctx ,
357+ target = ctx .attr .target ,
358+ output_prefix = ctx .label .name ,
359+ tool = ctx .attr ._tool ,
360+ libclang = ctx .file ._libclang ,
361+ llvm_cxx_builtin_include = ctx .attr ._llvm_cxx_builtin_include ,
362+ llvm_extra_config_site = ctx .attr ._llvm_extra_config_site ,
363+ log_level = ctx .attr ._log_level [BuildSettingInfo ].value ,
364+ extra_args = ctx .attr .extra_args ,
365+ emit_debug_json = ctx .attr .emit_debug_json ,
366+ )
367+
368+ runfiles_files = [outputs .class_fbs ]
369+ if outputs .debug_json :
370+ runfiles_files .append (outputs .debug_json )
371+
372+ return [
373+ DefaultInfo (
374+ files = depset ([outputs .class_fbs ]),
375+ runfiles = ctx .runfiles (files = runfiles_files ),
291376 ),
292- "_log_level" : attr . label (
293- default = Label ( "//cpp/libclang:log_level" ) ,
294- doc = "Build setting that controls clang_rs_parser log level." ,
377+ CppParserInfo (
378+ class_fbs = outputs . class_fbs ,
379+ debug_json = outputs . debug_json ,
295380 ),
296- },
381+ ]
382+
383+ _cpp_parser_attrs = {
384+ "target" : attr .label (
385+ aspects = cpp_parser_target_aspects (),
386+ mandatory = True ,
387+ ),
388+ "extra_args" : attr .string_list (
389+ default = [],
390+ ),
391+ "emit_debug_json" : attr .bool (
392+ default = False ,
393+ doc = "Emit debug.json alongside the FlatBuffer output. Intended for tests/debugging." ,
394+ ),
395+ }
396+
397+ _cpp_parser_attrs .update (cpp_parser_action_internal_attrs ())
398+
399+ # BUILD-facing parser rule: wraps run_cpp_parser_action and exposes CppParserInfo.
400+ cpp_parser = rule (
401+ implementation = _cpp_parser_impl ,
402+ attrs = _cpp_parser_attrs ,
297403 toolchains = use_cc_toolchain (),
298404 fragments = ["cpp" ],
299405)
0 commit comments