Skip to content

feat: support plugins - #1256

Open
gennaroprota wants to merge 3 commits into
cppalliance:developfrom
gennaroprota:feat/support_plugins
Open

feat: support plugins#1256
gennaroprota wants to merge 3 commits into
cppalliance:developfrom
gennaroprota:feat/support_plugins

Conversation

@gennaroprota

Copy link
Copy Markdown
Collaborator

This PR adds support for plugins, i.e. shared libraries written in C++ that can be written and compiled without needing Clang/LLVM headers.

Changes

  • Source:
    • A public header, mrdocs/Plugin.hpp. It says what a plugin has to export (an entry point, the interface version, a toolchain tag) and what MrDocs passes in (PluginContext). It also provides MRDOCS_PLUGIN_MAIN, a macro that writes those exported functions for the plugin author.
    • The loader. It finds the libraries in each addon root, in order, checks the version and the toolchain, and calls the entry point.
    • One call to the loader while the tool starts up, before any generator is looked up by id.
    • Export attributes. They now expand to a real attribute when MrDocs itself is built. They also move to a header of their own, because Platform.hpp includes Assert.hpp before it could define them.
  • Tests: discovery unit tests, a stats example plugin run by ctest, and a link test under tests/plugin-api.
  • Build:
    • The mrdocs target sets ENABLE_EXPORTS. It also lists, on its interface, the include directories and compile options a plugin needs.
    • The example plugin and the link test are built as module libraries. The example is built into an addon root that its own test passes to MrDocs.

Testing

Each test checks something the others cannot.

  • The discovery unit tests check which files are loaded, in what order, and that a library reachable through two roots is loaded once. Those rules are part of the documented behavior, so they should not change by accident.
  • The stats example runs MrDocs with a configuration that asks for generator: stats. That name only exists if the plugin was found, loaded, and installed its generator, so the test fails if any step in that chain breaks.
  • The link test checks that the API a plugin uses is really exported. A plugin compiles its own copy of every inline and template member, and those copies call functions that live in the tool and need an export attribute. If one of them is missing, the plugin does not link, and no other test would notice.

Writing the link test found a real problem. The comparison operators of the symbol kinds were not exported, so a plugin that sorts members could not link. The first commit fixes that.

The two ctest tests run in suites that CI already runs. The link test has no ctest entry, because it does not need one: it is a library, and a missing symbol makes the build fail. So CI needs no change.

The link test only detects a missing export on Windows, where a plugin gets its symbols from the tool's export table. On Linux and macOS, it still checks that the public headers compile the way a plugin compiles them, and that such a library links against the executable.

One thing is not tested: the cases where the loader refuses a plugin, that is, a wrong interface version, a wrong toolchain, or a missing entry point. Testing those needs a library built the wrong way on purpose.

Documentation

A new Plugins page under Extensions covers where plugins live, the entry point, the generator, and how to build one. Its code comes from the example through tag includes, so the page cannot drift from something that compiles. The plugins directory that ships with MrDocs gets a README saying what belongs in it.

Closes #58.

`MRDOCS_DECL` expanded to nothing in a static build, so it marked
nothing and its misuse went unnoticed: it was applied to some classes
*and* some of their members, which MSVC rejects. `MRDOCS_TOOL`, which
says MrDocs itself is being built, now comes first in every library that
exports part of the API, so the symbols a plugin calls end up in the
tool's export table, while a static consumer still sees plain
declarations. `assert_failed`, the out-of-line members of `Corpus`, and
the comparison operators a plugin reaches through the headers gain an
attribute instead, since nothing else marks them and a plugin cannot
call what the tool does not export. Exporting the API also makes MSVC
warn about the standard library members of the exported types, which the
libraries now suppress as mrdocs-core already did. The attributes move
to an include of their own because Platform.hpp includes Assert.hpp
first.
@github-actions

github-actions Bot commented Aug 11, 2026

Copy link
Copy Markdown

🧾 Changes by Scope

Scope Lines Δ% Lines Δ Lines + Lines - Files Δ Files + Files ~ Files ↔ Files -
🛠️ Source 61% 1047 981 66 30 6 24 - -
📚 Examples 12% 197 197 - 5 4 1 - -
🧪 Unit Tests 11% 192 192 - 1 1 - - -
📄 Docs 8% 137 127 10 3 1 2 - -
📦 Other 7% 120 118 2 3 2 1 - -
🏗️ Build 1% 12 12 - 1 - 1 - -
Total 100% 1705 1627 78 43 14 29 - -

Legend: Files + (added), Files ~ (modified), Files ↔ (renamed), Files - (removed)

🔝 Top Files

  • include/mrdocs/Plugin.hpp (Source): 293 lines Δ (+293 / -0)
  • src/mrdocs/Support/PluginLoader.cpp (Source): 254 lines Δ (+254 / -0)
  • tests/unit/Support/PluginLoader.cpp (Unit Tests): 192 lines Δ (+192 / -0)

Generated by 🚫 dangerJS against a8fc0fc

@codecov

codecov Bot commented Aug 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 83.12%. Comparing base (faea11b) to head (a8fc0fc).

Additional details and impacted files
@@           Coverage Diff            @@
##           develop    #1256   +/-   ##
========================================
  Coverage    83.12%   83.12%           
========================================
  Files           35       35           
  Lines         3662     3662           
  Branches       844      844           
========================================
  Hits          3044     3044           
  Misses         410      410           
  Partials       208      208           
Flag Coverage Δ
bootstrap 83.12% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@cppalliance-bot

cppalliance-bot commented Aug 11, 2026

Copy link
Copy Markdown

An automated preview of the documentation is available at https://1256.mrdocs.prtest2.cppalliance.org/index.html

If more commits are pushed to the pull request, the docs will rebuild at the same URL.

2026-08-17 19:55:35 UTC

@gennaroprota gennaroprota changed the title Feat/support plugins feat: support plugins Aug 12, 2026
@gennaroprota
gennaroprota force-pushed the feat/support_plugins branch 2 times, most recently from 73371cd to b22ac45 Compare August 12, 2026 14:28
MrDocs loads the shared libraries in the plugins subdirectory of each
addon root as it starts up, and lets each one install a generator. A
plugin resolves the MrDocs symbols it calls against the tool, so writing
an output format takes the MrDocs headers and nothing else: no LLVM, no
Clang, no separate library to ship.

Closes cppalliance#58.
A plugin could install a generator, so it could add an output format but
not change what any format sees. This adds support for corpus
transforms, filling the gap with extension scripts.

Plugin transforms run before the script ones, since a plugin is loaded
before any script is read.
@alandefreitas

Copy link
Copy Markdown
Collaborator

I think the doc preview isn't working. We need to debug that for this PR. In any case, I read the adoc file, and I'm not sure I understand the user workflow. As far as I understand, the user would need an mrdocs installation and a way to link whatever they need to their own project to write a plugin. And tests would have to emulate that. This can't be tested from the inside before mrdocs is installed.

@gennaroprota

Copy link
Copy Markdown
Collaborator Author

It seems that the doc preview stopped working around 5-6 June 2026.

About the user workflow, your reading is right: the author needs an install. But I'm not sure what you mean by "can't be tested from the inside"; isn't that what tests/plugin-api does?

However, I noticed that the docs prescribe find_package(mrdocs REQUIRED CONFIG) in two places, which fails for everyone. The generated config expands @DUKTAPE_PACKAGE_NAME@, which is now undefined, into a bare find_dependency(), which is a hard CMake error, so both sets of instructions have been broken the whole time. find_dependency(fmt) is dead too: nothing in the project links fmt any more. That leaves LLVM and Clang, legitimate for mrdocs-core consumers, but not for plugin authors. I will fix the config here, and add an install-and-consume test that builds a plugin against a staged prefix alone.

@alandefreitas

alandefreitas commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

I will fix the config here and add an install-and-consume test that builds a plugin against a staged prefix alone.

Please hang on a little bit then, because I've been already working on precisely this issue for the last two weeks. My fork is nothing but CI tests for test/cmake-package lately.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add plugins/generators via DLL

3 participants