Sphinx 找不到 Doxygen 导出的 xml 中的内容的解决方法

Sphinx + Breathe + Doxygen + CMake 的教程看这个就够了

https://devblogs.microsoft.com/cppblog/clear-functional-c-documentation-with-sphinx-breathe-doxygen-cmake/

但是他还是少写了一些东西,所以还是有一些小坑的

这些坑会导致 Sphinx 找不到 Doxygen 导出的 xml 中的内容,或者是报错

第一个是 conf.py 可能一直找不到 sphinx_rtd_theme 这个 module,即使你更新了 pip,重新下载了 sphinx_rtd_theme 好多遍,也没有办法

这个原因很简单,就是因为他没有找到你的 python 下载包的路径

我的 cmake 配置如下,主要是设置了一个虚拟环境,放在输出目录中,这样我们就可以不污染主机的 python 环境,也可以清楚地知道自己的包下载到哪里了

projectRoot/CMakeLists.txt

...

# Docs only available if this is the main app
find_package(Doxygen)
if(Doxygen_FOUND)
    message(STATUS "Found Doxygen, building docs")
    add_subdirectory(docs)
else()
    message(STATUS "Doxygen not found, not building docs")
endif()

projectRoot/docs/CMakeLists.txt

option(BUILD_DOCS_USE_VENV "Generate Python virtual environment" ON)

find_package(Python COMPONENTS Interpreter REQUIRED)
if (BUILD_DOCS_USE_VENV)
    set(DOCS_VENV "${CMAKE_CURRENT_BINARY_DIR}/venv")
    message(STATUS "Creating Python venv at ${DOCS_VENV}")
    execute_process(COMMAND ${Python_EXECUTABLE} -m venv ${DOCS_VENV})
    set(ENV{VIRTUAL_ENV} ${DOCS_VENV})
    set(Python_FIND_VIRTUALENV FIRST)
    unset(Python_EXECUTABLE)
    find_package(Python COMPONENTS Interpreter REQUIRED)

    execute_process(
        COMMAND ${Python_EXECUTABLE} -m pip install --no-cache wheel
        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
        COMMAND_ERROR_IS_FATAL ANY
    )
    execute_process(
        COMMAND ${Python_EXECUTABLE} -m pip install --no-cache -r requirements.txt
        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
        COMMAND_ERROR_IS_FATAL ANY
    )
endif()

execute_process(
    COMMAND ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/../helper/req_check.py requirements.txt
    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
    COMMAND_ERROR_IS_FATAL ANY
)

find_program(SPHINX_EXECUTABLE sphinx-build HINTS ${DOCS_VENV}/Scripts ${DOCS_VENV}/bin REQUIRED)
message(STATUS "Found Sphinx: ${SPHINX_EXECUTABLE}")

# Find all the public headers from runtime
get_target_property(RUNTIME_PUBLIC_HEADER_DIR ${RUNTIME_NAME} INTERFACE_INCLUDE_DIRECTORIES)
file(GLOB_RECURSE RUNTIME_PUBLIC_HEADERS CONFIGURE_DEPENDS ${RUNTIME_PUBLIC_HEADER_DIR}/*.h)

# Find all the public headers from editor
get_target_property(EDITOR_PUBLIC_HEADER_DIR ${EDITOR_NAME} INTERFACE_INCLUDE_DIRECTORIES)
file(GLOB_RECURSE EDITOR_PUBLIC_HEADERS CONFIGURE_DEPENDS ${EDITOR_PUBLIC_HEADER_DIR}/*.h)

message(--------------)
message(STATUS "${RUNTIME_PUBLIC_HEADERS}")
message(STATUS "${EDITOR_PUBLIC_HEADERS}")
message(--------------)

set(DOXYGEN_INPUT_DIR ${PROJECT_SOURCE_DIR}/src)
set(DOXYGEN_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/doxygen)
set(DOXYGEN_INDEX_FILE ${DOXYGEN_OUTPUT_DIR}/xml/index.xml)
set(DOXYFILE_IN ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in)
set(DOXYFILE_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)

# Replace variables inside @@ with the current values
configure_file(${DOXYFILE_IN} ${DOXYFILE_OUT} @ONLY)

# Doxygen won't create this for us
file(MAKE_DIRECTORY ${DOXYGEN_OUTPUT_DIR})

# Only regenerate Doxygen when the Doxyfile or public headers change
add_custom_command(OUTPUT ${DOXYGEN_INDEX_FILE}
                   DEPENDS ${RUNTIME_PUBLIC_HEADERS} ${EDITOR_PUBLIC_HEADERS}
                   COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE_OUT}
                   MAIN_DEPENDENCY ${DOXYFILE_OUT} ${DOXYFILE_IN}
                   COMMENT "Generating docs"
                   VERBATIM)

# Nice named target so we can run the job easily
add_custom_target(Doxygen ALL DEPENDS ${DOXYGEN_INDEX_FILE})

set(SPHINX_SOURCE ${CMAKE_CURRENT_SOURCE_DIR})
set(SPHINX_BUILD ${CMAKE_CURRENT_BINARY_DIR}/sphinx)
set(SPHINX_INDEX_FILE ${SPHINX_BUILD}/index.html)

# Only regenerate Sphinx when:
# - Doxygen has rerun
# - Our doc files have been updated
# - The Sphinx config has been updated
add_custom_command(OUTPUT ${SPHINX_INDEX_FILE}
                   COMMAND 
                     ${SPHINX_EXECUTABLE} -b html
                     # Tell Breathe where to find the Doxygen output
                     -Dbreathe_projects.MeowEngine=${DOXYGEN_OUTPUT_DIR}/xml
                   ${SPHINX_SOURCE} ${SPHINX_BUILD}
                   WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
                   DEPENDS
                   # Other docs files you want to track should go here (or in some variable)
                   ${CMAKE_CURRENT_SOURCE_DIR}/index.rst
                   ${DOXYGEN_INDEX_FILE}
                   MAIN_DEPENDENCY ${SPHINX_SOURCE}/conf.py
                   COMMENT "Generating documentation with Sphinx")

# Nice named target so we can run the job easily
add_custom_target(Sphinx ALL DEPENDS ${SPHINX_INDEX_FILE})

# Add an install target to install the docs
include(GNUInstallDirs)
install(DIRECTORY ${SPHINX_BUILD}
DESTINATION ${CMAKE_INSTALL_DOCDIR})

其中,获取 Doxygen 所需要的头文件那里,那里是我自己的项目的情况,一个 runtime 一个 engine,这个具体实现因项目而异

然后我们现在已经知道自己下载的包在哪里了,我们就在 conf.py 中直接把这个路径写进去

projectRoot/docs/conf.py

import sys
from pathlib import Path

sys.path.insert(0, str(Path('../build/docs/venv/Lib/site-packages/').resolve()))

然后还有一点坑的就是,在 conf.py 中我们要写明 breathe 的项目的名称和对应的 doxygen 输出的 xml 的位置:

projectRoot/docs/conf.py

breathe_projects = {
    "MeowEngine": "../build/docs/doxygen/xml"
}

完整的 conf.py

projectRoot/docs/conf.py

# Configuration file for the Sphinx documentation builder.
#
# For the full list of built-in configuration values, see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html

# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information

import sys
from pathlib import Path

sys.path.insert(0, str(Path('../build/docs/venv/Lib/site-packages/').resolve()))

import sphinx_rtd_theme

project = 'MeowEngine'
copyright = '2023, CheapMeow'
author = 'CheapMeow'

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration

extensions = ['sphinx_rtd_theme', 'breathe']

breathe_projects = {
    "MeowEngine": "../build/docs/doxygen/xml"
}

templates_path = ['_templates']
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']

# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output

html_theme = 'sphinx_rtd_theme'
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
html_static_path = ['_static']

如果现在 sphinx 还是没有办法找到你的类的话,可能是你没有写明命名空间

projectRoot/docs/index.rst

.. doxygenclass:: Meow::MeowEngine
   :project: MeowEngine
   :members:

因为你可以看到 xml 里面的输出是带着命名空间的

projectRoot/build/docs/doxygen/xml/class_meow_1_1_meow_engine.xml

  <compounddef id="class_meow_1_1_meow_engine" kind="class" language="C++" prot="public">
    <compoundname>Meow::MeowEnginecompoundname>

你可能感兴趣的:(GameEngineDev,sphinx,xml)