Reputation: 393
I have been using https://github.com/TendTo/rules_doxygen/tree/main from the BCR to generate docs. I am trying to figure out how to get bazel to walk the dependency graph of a target so I can extract a list of all the headers to feed to doxygen for documentation. So far, I have only been able to get doxygen to work if I specify everything in a glob - but that kind of assumes everything sits in one place. I'd like to have something like:
cc_binary MAIN - main.cpp
|
cc_library A - A.cpp, A.hpp
|
cc_library B - B.cpp, B.hpp
|
cc_library C - C.cpp, C.hpp
Now - something like this works:
doxygen(
name = "doxygen", # Name of the rule, can be anything
srcs = glob(["A/*.hpp", "B/*.hpp", "C/*.hpp"]),
project_brief = "Example project for doxygen", # Brief description of the project
project_name = "base", # Name of the project
configurations = [ # Additional configurations to add to the Doxyfile
"GENERATE_HTML = YES", # They are the same as the Doxyfile options,
"GENERATE_LATEX = NO", # and will override the default values
"EXTRACT_ALL = YES",
],
tags = ["manual"] # Tags to add to the target. This way the target won't run unless explicitly called
)
But I should be able to wrap that so that I could do something like:
my_doxygen(
name = "my_cool_docs",
deps = [":main"] ( or maybe in a docs folder "//:main" )
)
bazel build //:my_cool_docs or bazel build //docs:my_cool_docs
Have it walk the deps of main, keep a list of files, and then supply to doxygen under the hood.
So far, I have figured out how to make this work on all cc_library and cc_binary files inside a BUILD file using aspects:
load("//:cc_srcs.bzl", "CcSrcs", "cc_srcs_aspect")
def _gather_src_files_impl(ctx):
srcs = []
hdrs = []
for dep in ctx.attr.deps:
srcs.extend(dep[CcSrcs].srcs.to_list())
hdrs.extend(dep[CcInfo].compilation_context.direct_headers)
hdrs = [h for h in hdrs if h.is_source]
src_list = srcs + hdrs
info = [DefaultInfo(files=depset(src_list))]
return info
_gather_src_files = rule(
implementation = _gather_src_files_impl,
fragments = ["cpp"],
attrs = {
"deps": attr.label_list(providers = [CcInfo], aspects = [cc_srcs_aspect]),
},
toolchains = ["@bazel_tools//tools/cpp:toolchain_type"],
)
def gather_src_files(name = "gather_src_files"):
rule_types = [rule["kind"] for rule in native.existing_rules().values()]
if "_gather_src_files" in rule_types:
fail("rule already defined")
deps = []
for rule_name, rule in native.existing_rules().items():
print(rule_name + ":" + rule["kind"])
if rule["kind"] in ["cc_binary", "cc_library"]:
deps.append(rule_name)
_gather_src_files(
name = name,
deps = deps
)
cc_srcs.bazel
CcSrcs = provider(
fields = {
"srcs": "depset of top-level cpp sources",
"package": "the package root",
},
)
def extract_cc_files(target, ctx):
srcs_target_list = getattr(ctx.rule.attr, "srcs", [])
srcs_file_list = [f for t in srcs_target_list for f in t.files.to_list()]
return srcs_file_list
def extract_cc_srcs(target, ctx):
return [s for s in extract_cc_files(target, ctx) if s.extension in ["c", "cc", "cpp", "cxx", "c++", "C"]]
def _cc_srcs_aspect_impl(target, ctx):
srcs = []
if CcInfo in target: srcs = extract_cc_srcs(target, ctx)
# Get the root name: either ws root for external repos, or package for internal repos
root_name = ctx.label.workspace_root
if not root_name: root_name = ctx.label.package
return [CcSrcs(
srcs = depset(srcs, order = "topological"),
package = depset([root_name]),
)]
cc_srcs_aspect = aspect(
implementation = _cc_srcs_aspect_impl,
)
But I can not figure out how to access / walk the dependency graph of a given target - and I am not even sure what terms to look for in the Bazel docs at this point.
Any ideas? Thanks!
Upvotes: 0
Views: 137
Reputation: 393
After looking closer at the example - I figured out all I needed to do was add:
FileCountInfo = provider(
fields = {
'count' : 'number of files',
'srcs' : 'depset of files' <-----
}
)
def _file_count_aspect_impl(target, ctx):
count = 0
srcs = []
# Make sure the rule has a srcs attribute.
print("Fudge")
if hasattr(ctx.rule.attr, 'srcs'):
# Iterate through the sources counting files
for src in ctx.rule.attr.srcs:
for f in src.files.to_list():
if ctx.attr.extension == '*' or ctx.attr.extension == f.extension:
count = count + 1
srcs.append(f) <-----------
# Get the counts from our dependencies.
for dep in ctx.rule.attr.deps:
count = count + dep[FileCountInfo].count
a = dep[FileCountInfo].srcs
srcs.extend(dep[FileCountInfo].srcs.to_list()) <----------
return [FileCountInfo(count = count, srcs=depset(srcs))] <--------
enter code here
Between that and what I already have - I think I have a slightly more solid base.
It's a process, and I don't think Bazel has met a problem it hasn't solved with another layer of indirection yet.
Upvotes: 1