如何将MkDocs与pybind11模块结合生成API文档?
如何基于MkDocs为pybind11生成的Python API构建文档站点
背景
我需要为通过pybind11封装的Python API搭建MkDocs文档站点,对应的C++ API已经能正常生成文档。此前使用Sphinx搭配Doxygen生成静态HTML文档,现在团队切换到MkDocs,需要通过mkdocs.yaml提取API文档。
现有代码
C++通用头文件(PybindCommon.h)
#include <pybind11/pybind11.h> namespace App::Binding { namespace py = pybind11; }
Python API绑定头文件(AppBindings.h)
#pragma once #include "PybindCommon.h" namespace App::Binding { /** * @brief Bindings for IApp API */ void bindApp(py::module_& m); } // namespace App::Binding
Python API绑定实现文件(AppBindings.cpp)
#include "IApp.h" #include "AppBindings.h" #include <pybind11/stl.h> /** * @brief Bindings for IApp API */ namespace App::Binding { // Custom deleter for unique_ptr<IApp> objects to call release() on the object when the object is GC'd in Python struct AppDeleter { void operator()(IApp* app) { if(app) { app->release(); } } }; void bindApp(py::module_& m) { // python constructor will be binded to a unique_ptr<IApp> object with a custom deleter on C++ side py::class_<IApp, std::unique_ptr<IApp, AppDeleter>>(m, "App", R"pbdoc( The main entry point for accessing the App. Exposes general app metadata objects for accessing specific data from the app. )pbdoc") .def(py::init([](const char* config_path, LibType lib_type) { IApp* app = initApp(config_path, lib_type); if(app == nullptr) { throw std::runtime_error( "Can only construct one app per process. Multi-app support planned in future versions."); } return std::unique_ptr<IApp, AppDeleter>(app); }), py::arg("config_path"), py::arg("lib"), R"pbdoc( Create an app object Args: config_path (:obj:`str`): Path to the configuration file for the app. lib (:obj:`LibType`): Type of shared-object to use the app with. Returns: :obj:`App`: App object. Raises: RuntimeError: If an App was already previously created in the same process. Will be fixed in future versions. )pbdoc") .def( "get_range", [](const IApp& self) { uint32_t first, last; self.getRange(first, last); return py::make_tuple(first, last); }, R"pbdoc( Get the App legal range Returns: :obj:`tuple`: A tuple containing: - first (:obj:`int`): First range value. - last (:obj:`int`): Last range value. )pbdoc") .def("get_version", &IApp::getVersion, R"pbdoc( Get the created App version Returns: :obj:`str`: SHA of the App version. )pbdoc") .def("get_fps", &IApp::getAppFps, R"pbdoc( Get the FPS of the App Returns: :obj:`int`: App's system FPS. )pbdoc") .def("get_available_frames", &IApp::getAvailableFrames, R"pbdoc( Get the available frames for the primary app sensor Returns: :obj:`list`: List of available frames for the primary sensor. )pbdoc") .def("get_available_frame_configs", &IApp::getAvailableFrameConfigs, py::arg("frame"), R"pbdoc( Get all the available configurations for a specific frame type. Args: frame (:obj:`FrameType`): Type of frame. Returns: :obj:`list`: List of available configurations. )pbdoc"); } } // namespace App::Binding
已尝试的方案
- 使用
mkdocstrings插件结合Python处理器,以pybind生成的带文档字符串的.so文件作为输入 - 将Sphinx作为预处理器,用
sphinx-build -M xml生成XML文件,再作为mkdoxy插件的输入 - 用
sphinx-build -M json生成.fjson文件,配合mkdocstrings插件,但解析失败 - 通过Python脚本解析
.cpp文件生成带常规文档字符串的.py文件,但不利于CI自动化且维护成本高 - 尝试markdown扩展,但因Jinja2语法或
{eval-rst}问题未能成功
当前mkdocs.yaml配置
site_name: "App Docs" repo_url: <company_site>/app.git repo_name: app edit_uri: edit/master/include/ dev_addr: 0.0.0.0:38000 docs_dir: . plugins: - mkdoxy: projects: App: src-dirs: include doxy-cfg: FILE_PATTERNS: "*.cpp *.h* *.md" RECURSIVE: YES INPUT: include GENERATE_XML: YES EXTRACT_ALL: YES OPTIMIZE_OUTPUT_FOR_C: YES pyDAST: src-dirs: docs/build/json/python doxy-cfg: FILE_PATTERNS: "*.fjson" RECURSIVE: NO INPUT: docs/build/json/python GENERATE_XML: YES EXTRACT_ALL: YES OPTIMIZE_OUTPUT_FOR_JAVA: YES save-api: .mkdoxy full-doc: True debug: False ignore-errors: False - search - mkdocstrings - open-in-new-tab - autorefs - same-dir - awesome-pages - include-markdown theme: name: material features: - navigation.tabs - navigation.tabs.sticky - navigation.indexes - navigation.path - navigation.top - navigation.tracking palette: - media: "(prefers-color-scheme: dark)" scheme: default primary: blue accent: indigo toggle: icon: material/toggle-switch name: Switch to light mode - media: "(prefers-color-scheme: light)" scheme: slate toggle: icon: material/toggle-switch-off-outline name: Switch to dark mode extra_javascript: - https://cdn.jsdelivr.net/gh/rod2ik/cdn@main/mkdocs/javascripts/massilia-graphviz.js markdown_extensions: - extra - tables - mkdocs_graphviz - attr_list - mdx_truly_sane_lists - mdx_math: use_gitlab_delimiters: True # for $`...`$ style math - toc: permalink: true - pymdownx.highlight - pymdownx.superfences - def_list - admonition - pymdownx.details - markdown.extensions.md_in_html - pymdownx.snippets: check_paths: true - pymdownx.blocks.admonition: types: - new - settings - note - abstract - info - tip - success - question - warning - failure - danger - bug - example - quote - pymdownx.blocks.details: - pymdownx.blocks.html: - pymdownx.blocks.definition: - pymdownx.blocks.tab: - pymdownx.tabbed: alternate_style: true - pymdownx.emoji: emoji_index: !!python/name:material.extensions.emoji.twemoji emoji_generator: !!python/name:materialx.emoji.to_svg use_directory_urls: True nav: ...
问题
请问有没有合适的插件或方法可以实现MkDocs与pybind11的结合,顺利生成Python API文档?
内容的提问来源于stack exchange,提问作者mayanco
相关产品推荐
相关产品推荐

