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>