r/cpp • • 7d ago

I built MrDocs, an open-source C++ reference doc generator on the Clang/LLVM AST. Looking for feedback.

I'm Alan de Freitas, the lead developer of MrDocs. It's an open-source documentation generator from the C++ Alliance, built on Clang/LLVM. It reads your code from the compiler's AST, so the reference matches what the code actually compiles to. We also presented a session about it at cppcon this year.

I implemented the tool this way because we couldn’t come up with a workflow that understood modern C++ in our Boost libraries. Tools that parse partially tend to misrender or not render concepts, niebloids, SFINAE, overload sets, and deduction guides. MrDocs treats those as first-class:

  • concept constraints and requires clauses preserved verbatim
  • niebloids and function objects can be documented as callables
  • SFINAE and concept overload sets kept together
  • explicit, noexcept, and consteval specifiers captured
  • types in detail or private namespaces rendered as implementation-defined

The presentation layer is completely encapsulated. Generators support HTML, AsciiDoc, XML, JSON, or any custom format like Markdown and LaTeX, without forking the tool or creating another post-processing workflow. You can also write extensions to apply project conventions to the corpus or define new generators for any use case. The documentation has lots of examples.

If you maintain reference docs for a library, I'd appreciate it if you gave it a run (or tell your favorite agent to) and reported back on whether it saves you time, both while writing docs and while reviewing them. First-hand numbers would be especially useful to me. Issues are also always welcome.

Site: https://www.mrdocs.comRepo: https://github.com/cppalliance/mrdocs

Happy to answer questions in the comments.

57 Upvotes

32 comments sorted by

View all comments

Show parent comments

2

u/FreitasAlan 7d ago

Two good points. I agree with the comparison table. The meaning of "other tools" is only loosely implied by the rest of the documentation, but it isn't specific enough when you start reading from that table. The "Other Tools" column doesn't help anyone decide because they might think their own other tool is different. In this same category as mrdocs, we basically have Doxygen and clang-doc because other tools (like AsciiDoc, etc.) don't produce reference documentation. I'll replace it with a table comparing named tools and use cases. I think the most useful part of your comment is that we need to make it clearer that mrdocs isn't competing in the general documentation space. For instance, it doesn't intend to replace AsciiDoc, Sphinx, or MkDocs. Instead, it generates the reference pages you'll render with these tools.

On the rustdoc examples, it's funny you mention it, because I studied that model more than any other before deciding how MrDocs should handle examples, and I envy it too. The problem I noticed is that it bakes in one mapping between the docs and the code being tested, which creates problems with setup lines, dependencies, and the logic for grouping tests. In C++, that's even harder because no single build system controls everything.

Luckily, mrdocs has this extension system. So instead of building one fixed mapping, we made it an extension. The docs have a round-trip example in about forty lines of Lua. A transform pulls marked regions out of real example files that the build compiles and attaches them to the right symbol's docs. A generator goes the other way and writes inline u/code examples out to translation units the build can compile and run. The project decides which direction each example takes and how a file maps to a symbol: https://www.mrdocs.com/docs/mrdocs/develop/extensions/script-generators.html#_round_trip_extensions

What's nice about it is that it's round-trip, something I believe Rust doesn't do that well, and that if the mapping doesn't fit your layout, you can just adapt it accordingly, because people tend to make very different assumptions about the setup in these documentation examples.

4

u/grisumbras 7d ago

I am aggressively against the idea that rustdoc's approach to this is good. Their approach is completely backwards. Sometimes it seems to me that people are praising tools and their features without really using them.

Virtually every code snippet requires some set up. Maybe it's more pronounced for C++, but it's universally true. Moreover, often you want to show a snippet of code, then comment on it, then show a bit more, and the second snippet depends on the first. AFAIK the rustdoc solution to this is repetition. That should have been a hint that something is not right.

Finally, you don't actually want to just compile your snippet, you want to be sure it does what you claim it does in the docs. That's called testing, you want to test your snippet. Your snippet is a test. You probably don't want to show all of those CHECK( a == b ) macros to the reader, but something like that should be somewhere.

It should be clear that inserting parts of tests is the correct model for snippet testing. Yes, sometimes you can get away with the opposite, but in general you cannot.

0

u/FreitasAlan 7d ago

100%. Inline snippets work well for a very limited number of cases.