diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index bf982d18..3cc28654 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -21,7 +21,6 @@ on: - '**/*.rst' - 'cmake/HIPOBJDocumentation.cmake' - 'docs/**' - - 'requirements.txt' push: branches: [ "develop" ] paths-ignore: *paths-ignore diff --git a/.github/workflows/hipobject-build.yml b/.github/workflows/hipobject-build.yml index be0b267f..647471d7 100644 --- a/.github/workflows/hipobject-build.yml +++ b/.github/workflows/hipobject-build.yml @@ -24,7 +24,6 @@ on: - '!ci/**' - '!cmake/HIPOBJDocumentation.cmake' - '!docs/**' - - '!requirements.txt' - '!.github/**' - '.github/workflows/hipobject-build.yml' - '.github/actions/install-rocm/**' diff --git a/.github/workflows/hipobject-clang-tidy.yml b/.github/workflows/hipobject-clang-tidy.yml index 490094cf..33456c3f 100644 --- a/.github/workflows/hipobject-clang-tidy.yml +++ b/.github/workflows/hipobject-clang-tidy.yml @@ -31,7 +31,6 @@ on: - '!ci/**' - '!cmake/HIPOBJDocumentation.cmake' - '!docs/**' - - '!requirements.txt' - '!.github/**' - '.github/workflows/hipobject-clang-tidy.yml' - '.github/actions/install-rocm/**' diff --git a/.github/workflows/hipobject-documentation-check.yml b/.github/workflows/hipobject-documentation-check.yml index f691a98b..722616b6 100644 --- a/.github/workflows/hipobject-documentation-check.yml +++ b/.github/workflows/hipobject-documentation-check.yml @@ -3,11 +3,12 @@ name: hipObject - Documentation Check on: pull_request: branches: [develop] + # docs/conf.py reads the version from the top-level CMakeLists.txt. paths: &paths - 'docs/**' - 'include/**/*.h' - 'README.md' - - 'requirements.txt' + - 'CMakeLists.txt' - 'cmake/HIPOBJDocumentation.cmake' - '.github/workflows/hipobject-documentation-check.yml' push: diff --git a/.github/workflows/hipobject-documentation-deploy.yml b/.github/workflows/hipobject-documentation-deploy.yml index 77bf1f10..b88f0720 100644 --- a/.github/workflows/hipobject-documentation-deploy.yml +++ b/.github/workflows/hipobject-documentation-deploy.yml @@ -10,10 +10,11 @@ name: hipObject - Documentation Deploy on: push: branches: [develop] + # docs/conf.py reads the version from the top-level CMakeLists.txt. paths: - 'docs/**' - 'include/**/*.h' - - 'requirements.txt' + - 'CMakeLists.txt' - 'cmake/HIPOBJDocumentation.cmake' - '.github/workflows/hipobject-documentation-deploy.yml' workflow_dispatch: diff --git a/.github/workflows/hipobject-iwyu.yml b/.github/workflows/hipobject-iwyu.yml index d15a905e..cadb97ce 100644 --- a/.github/workflows/hipobject-iwyu.yml +++ b/.github/workflows/hipobject-iwyu.yml @@ -26,7 +26,6 @@ on: - '!ci/**' - '!cmake/HIPOBJDocumentation.cmake' - '!docs/**' - - '!requirements.txt' - '!.github/**' - 'ci/iwyu/**' - '.github/workflows/hipobject-iwyu.yml' diff --git a/.gitignore b/.gitignore index 64db02d9..6f4c2bfd 100644 --- a/.gitignore +++ b/.gitignore @@ -56,6 +56,7 @@ tmp/ # Documentation build artifacts docs/_build/ +docs/doxygen/xml/ # Test artifacts Testing/ diff --git a/AGENTS.md b/AGENTS.md index 2492ecf2..c8d404c9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -757,8 +757,16 @@ Python code must run on **Python 3.10**. Don't use anything newer, such as CI: [hipobject-documentation-check.yml](.github/workflows/hipobject-documentation-check.yml), - when the documentation, the public header, `README.md`, `requirements.txt`, - the documentation's build files, or the workflow file change. + when the documentation (including `docs/sphinx/requirements.txt`), the + public header, `README.md`, the top-level `CMakeLists.txt` (which + `docs/conf.py` reads the version from), the documentation's build files, + or the workflow file change. +- **The documentation has to build without CMake too.** After the move to + rocm-systems, Read the Docs will run doxygen in `docs/doxygen` and Sphinx + on `docs/conf.py` directly, so keep CMake's `@VARIABLE@` substitutions + out of both files. The CMake build only redirects their output to the + build directory (see + [`HIPOBJDocumentation.cmake`](cmake/HIPOBJDocumentation.cmake)). ### Ansible diff --git a/CHANGELOG.md b/CHANGELOG.md index d3480036..a52079dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -226,7 +226,14 @@ dependency on a shared library they don't call, such as `libm`. - Building the documentation (`HIPOBJ_BUILD_DOCS`) requires Breathe 4.36 or later, up from 4.35. The documentation build installs it from - `requirements.txt` into its own virtual environment. + `docs/sphinx/requirements.txt` into its own virtual environment. +- The documentation's Python requirements moved from the top-level + `requirements.txt` to `docs/sphinx/requirements.txt`, and the Doxygen + configuration from `docs/Doxyfile.in` to `docs/doxygen/Doxyfile`. Both + `docs/doxygen/Doxyfile` and `docs/conf.py` now work without CMake, so + the documentation can be built by running Doxygen in `docs/doxygen` and + then Sphinx on `docs` (see "Building Documentation" in + `docs/building.rst`). The CMake build works as before. - The documentation build's targets are now `hipobj-sphinx-html`, `hipobj-doxygen`, and `hipobj-docs-venv`, rather than `sphinx-html`, `doxygen`, and `docs-venv`, so they can't collide with another diff --git a/cmake/HIPOBJDocumentation.cmake b/cmake/HIPOBJDocumentation.cmake index b8e87f7a..73501096 100644 --- a/cmake/HIPOBJDocumentation.cmake +++ b/cmake/HIPOBJDocumentation.cmake @@ -6,7 +6,12 @@ # (following ROCm best practices) # # A Python venv is created automatically in the build -# tree and populated from requirements.txt. +# tree and populated from docs/sphinx/requirements.txt. +# +# docs/doxygen/Doxyfile and docs/conf.py work without +# CMake too, as Read the Docs uses them, so nothing here +# configures them. The build only sends the output to the +# build tree. option(HIPOBJ_BUILD_DOCS "Build documentation (Sphinx + Breathe + Doxygen)" @@ -38,7 +43,7 @@ if(HIPOBJ_BUILD_DOCS) set(HIPOBJ_DOCS_VENV_STAMP "${HIPOBJ_DOCS_VENV}/stamp") set(HIPOBJ_DOCS_REQUIREMENTS - "${PROJECT_SOURCE_DIR}/requirements.txt") + "${PROJECT_SOURCE_DIR}/docs/sphinx/requirements.txt") if(WIN32) set(HIPOBJ_VENV_BIN @@ -73,33 +78,27 @@ if(HIPOBJ_BUILD_DOCS) # ── Paths ──────────────────────────────────────────── set(HIPOBJ_DOC_PATH "${PROJECT_BINARY_DIR}/docs") - set(BREATHE_DOC_XML_DIR - "${HIPOBJ_DOC_PATH}/xml") - - set(HIPOBJ_DOXYFILE_INPUT - "${PROJECT_SOURCE_DIR}/include") - - # Configure Doxyfile (substitutes @VARIABLES@) - configure_file( - ${PROJECT_SOURCE_DIR}/docs/Doxyfile.in - ${PROJECT_BINARY_DIR}/Doxyfile - @ONLY - ESCAPE_QUOTES - ) + set(HIPOBJ_DOXYGEN_DIR + "${PROJECT_SOURCE_DIR}/docs/doxygen") - # Configure conf.py (substitutes the version and Breathe XML path) - configure_file( - ${PROJECT_SOURCE_DIR}/docs/conf.py - ${PROJECT_BINARY_DIR}/docs-sphinx/conf.py + # A Doxyfile that reads the committed one and changes + # only where the output goes. Doxygen still has to run + # in docs/doxygen, which the committed file's relative + # paths are from. + file(CONFIGURE + OUTPUT ${PROJECT_BINARY_DIR}/Doxyfile + CONTENT [[ +@INCLUDE = "@HIPOBJ_DOXYGEN_DIR@/Doxyfile" +OUTPUT_DIRECTORY = "@HIPOBJ_DOC_PATH@" +]] @ONLY - ESCAPE_QUOTES ) # ── Doxygen target: source headers -> XML ──────────── add_custom_target(hipobj-doxygen COMMAND ${DOXYGEN_EXECUTABLE} ${PROJECT_BINARY_DIR}/Doxyfile - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + WORKING_DIRECTORY ${HIPOBJ_DOXYGEN_DIR} COMMENT "Generating Doxygen XML" VERBATIM ) @@ -107,11 +106,12 @@ if(HIPOBJ_BUILD_DOCS) # ── Sphinx target: RST + Doxygen XML -> HTML ───────── # -d keeps Sphinx's doctree cache out of the HTML # directory, which is published to GitHub Pages as is. + # -D points Breathe at the XML in the build tree. add_custom_target(hipobj-sphinx-html COMMAND ${SPHINX_BUILD} -b html -d ${HIPOBJ_DOC_PATH}/doctrees - -c ${PROJECT_BINARY_DIR}/docs-sphinx + -D breathe_projects.hipobj=${HIPOBJ_DOC_PATH}/xml ${PROJECT_SOURCE_DIR}/docs ${HIPOBJ_DOC_PATH}/html DEPENDS hipobj-doxygen hipobj-docs-venv diff --git a/docs/building.rst b/docs/building.rst index e971a6cd..6b384fb0 100644 --- a/docs/building.rst +++ b/docs/building.rst @@ -517,6 +517,21 @@ toolchain: cmake --build build --target hipobj-sphinx-html +The build installs Sphinx and the other Python packages +that ``docs/sphinx/requirements.txt`` lists into a virtual +environment in the build directory, which needs network +access the first time. + +The documentation also builds without CMake, with Doxygen +and the packages in ``docs/sphinx/requirements.txt`` +installed. Run Doxygen in ``docs/doxygen``, which writes its +XML to ``docs/doxygen/xml/``, and then Sphinx: + +.. code-block:: bash + + (cd docs/doxygen && doxygen Doxyfile) + sphinx-build -b html docs build/docs/html + Environment Variables --------------------- diff --git a/docs/conf.py b/docs/conf.py index 0cd2168e..e9052915 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -5,7 +5,14 @@ # Sphinx reads its settings from lowercase module-level names # pylint: disable=invalid-name -"""Sphinx configuration for hipObject documentation.""" +"""Sphinx configuration for hipObject documentation. + +Sphinx reads this file as it is, with or without CMake, so it has +to find everything it needs from its own directory. +""" + +import re +from pathlib import Path project = "hipObject" author = "Advanced Micro Devices, Inc." @@ -13,9 +20,23 @@ copyright = "2025-2026 Advanced Micro Devices, Inc. All rights reserved." # pylint: enable=redefined-builtin -# The project's version, from CMakeLists.txt, which configure_file() fills -# in (see cmake/HIPOBJDocumentation.cmake) -version = "@PROJECT_VERSION@" + +def _cmake_version(): + """Return the version that the top-level CMakeLists.txt sets.""" + cmake = (Path(__file__).resolve().parent.parent / "CMakeLists.txt").read_text( + encoding="utf-8" + ) + parts = [] + for part in ("MAJOR", "MINOR", "PATCH"): + match = re.search(rf"^set\(HIPOBJ_VERSION_{part} (\d+)\)$", cmake, re.MULTILINE) + if not match: + raise ValueError(f"HIPOBJ_VERSION_{part} not found in CMakeLists.txt") + parts.append(match.group(1)) + return ".".join(parts) + + +# The project's version, from CMakeLists.txt +version = _cmake_version() release = version # -- Extensions ---------------------------------------------- @@ -31,8 +52,11 @@ # -- Breathe (Doxygen XML import) ---------------------------- +# Where running doxygen in doxygen/ puts the XML. The CMake build +# writes it to the build directory, and passes that path with +# -D breathe_projects.hipobj=... breathe_projects = { - "hipobj": "@BREATHE_DOC_XML_DIR@", + "hipobj": "doxygen/xml", } breathe_default_project = "hipobj" breathe_default_members = ("members",) diff --git a/docs/Doxyfile.in b/docs/doxygen/Doxyfile similarity index 71% rename from docs/Doxyfile.in rename to docs/doxygen/Doxyfile index 3d7798f9..51af98e6 100644 --- a/docs/Doxyfile.in +++ b/docs/doxygen/Doxyfile @@ -1,18 +1,26 @@ # Doxyfile for hipObject -# Generated from docs/Doxyfile.in by CMake # # Doxygen generates XML consumed by Breathe; Sphinx # produces the final HTML output. +# +# Run doxygen in this directory, which the relative +# paths below are from. That writes the XML into +# xml/, where docs/conf.py looks for it. The CMake +# build includes this file from one of its own that +# sends the output to the build directory instead +# (see cmake/HIPOBJDocumentation.cmake). -PROJECT_NAME = "@PROJECT_NAME@" -PROJECT_NUMBER = "@PROJECT_VERSION@" +PROJECT_NAME = "hipobj" PROJECT_BRIEF = \ "RDMA-accelerated S3 object storage for GPUs" -OUTPUT_DIRECTORY = "@HIPOBJ_DOC_PATH@" -INPUT = "@HIPOBJ_DOXYFILE_INPUT@" +OUTPUT_DIRECTORY = . +INPUT = ../../include RECURSIVE = YES FILE_PATTERNS = *.h +# Name the files from the repository's root +# (include/hipobj.h), not from here +STRIP_FROM_PATH = ../.. EXTRACT_ALL = YES EXTRACT_PRIVATE = NO diff --git a/requirements.txt b/docs/sphinx/requirements.txt similarity index 100% rename from requirements.txt rename to docs/sphinx/requirements.txt