Skip to content

Commit dad453d

Browse files
authored
[docs] add Read the Docs C++ API reference (#354)
## Summary - Problem: issue #88 asks for the C++ API surface to be available on Read the Docs, but the docs currently only expose narrative guides. - Scope: add a Doxygen+Breathe docs pipeline for curated `envpool/core` headers, wire the new page into the existing Sphinx/RTD nav, and bump the package version for a docs-only patch release. - Outcome: RTD builds a browsable C++ API reference page alongside the existing `new_env` guide, without changing runtime behavior. This diff adds a generated C++ API reference to RTD and keeps the release semantics at a patch bump because the change is documentation-only. ## Technical Details - Approach: generate Doxygen XML during the Sphinx build, point Breathe at that XML, and render a curated set of core classes/types instead of dumping the entire header tree. - Code pointers: - `docs/conf.py`: configures the Doxygen XML generation hook and Breathe project mapping. - `docs/content/cpp_interface.rst`: defines the new curated C++ API reference page. - `.readthedocs.yaml`: installs `doxygen` in RTD so the docs build is self-contained. - `envpool/__init__.py`: bumps the package version to `0.9.1` for this docs-only release. - Notes: the docs link back into `content/new_env.rst`, and the version bump is intentionally `patch` because there is no API or behavior change. ## Test Plan ### Automated - `python3 -m compileall docs/conf.py`: passed locally. - `brix ssh dev -C -- 'bash /tmp/envpool_issue88_devbox.sh'`: passed on `dev`; installs docs deps, runs `make -C docs html`, and verifies `docs/_build/html/content/cpp_interface.html` contains the generated C++ API page. ### Suggested Manual - `make -C docs html`: verify the new `C++ API Reference` page appears in the Content nav. - Open `docs/_build/html/content/cpp_interface.html`: spot-check key entries like `AsyncEnvPool`, `EnvSpec`, and `PyEnvPool`. Closes #88.
1 parent bf3262d commit dad453d

13 files changed

Lines changed: 140 additions & 10 deletions

.readthedocs.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ version: 2
88
# Set the version of Python and other tools you might need
99
build:
1010
os: ubuntu-22.04
11+
apt_packages:
12+
- doxygen
1113
tools:
1214
python: "3.12"
1315

Makefile

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ clang-tidy-install:
4545
mkdir -p $(CLANG_TIDY_WRAPPER_DIR)
4646
ln -sf $$(command -v $(CLANG_TIDY_BIN)) $(CLANG_TIDY_WRAPPER_DIR)/clang-tidy
4747

48+
doxygen-install:
49+
command -v doxygen || (if command -v sudo >/dev/null 2>&1; then sudo apt-get update && sudo apt-get install -y doxygen; else apt-get update && apt-get install -y doxygen; fi)
50+
4851
go-install:
4952
# requires go >= 1.16
5053
command -v go || (sudo apt-get install -y golang-1.18 && sudo ln -sf /usr/lib/go-1.18/bin/go /usr/bin/go)
@@ -58,12 +61,13 @@ buildifier-install: go-install
5861
addlicense-install: go-install
5962
command -v addlicense || go install github.com/google/addlicense@latest
6063

61-
doc-install:
64+
doc-install: doxygen-install
6265
$(call check_install_extra, doc8, "doc8<1")
6366
$(call check_install, setuptools)
6467
$(call check_install, pbr)
6568
$(call check_install, sphinx)
6669
$(call check_install, sphinx_rtd_theme)
70+
$(call check_install, breathe)
6771

6872
spelling-install: doc-install spelling-system-install
6973
$(call check_install_extra, sphinxcontrib.spelling, sphinxcontrib.spelling pyenchant)

docs/conf.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,23 @@
1717
# sys.path.insert(0, os.path.abspath('.'))
1818

1919
import os
20+
import shutil
21+
import subprocess
22+
23+
CPP_API_HEADERS = [
24+
"envpool/core/array.h",
25+
"envpool/core/spec.h",
26+
"envpool/core/dict.h",
27+
"envpool/core/env_spec.h",
28+
"envpool/core/env.h",
29+
"envpool/core/envpool.h",
30+
"envpool/core/async_envpool.h",
31+
"envpool/core/py_envpool.h",
32+
]
33+
DOCS_DIR = os.path.abspath(os.path.dirname(__file__))
34+
PROJECT_ROOT = os.path.abspath(os.path.join(DOCS_DIR, ".."))
35+
DOXYGEN_BUILD_DIR = os.path.join(DOCS_DIR, "_build", "doxygen")
36+
DOXYGEN_XML_DIR = os.path.join(DOXYGEN_BUILD_DIR, "xml")
2037

2138

2239
def get_version() -> str:
@@ -42,6 +59,7 @@ def get_version() -> str:
4259
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
4360
# ones.
4461
extensions = [
62+
"breathe",
4563
"sphinx.ext.autodoc",
4664
]
4765

@@ -57,6 +75,9 @@ def get_version() -> str:
5775
# This pattern also affects html_static_path and html_extra_path.
5876
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
5977
spelling_exclude_patterns = ["pages/slides.rst"]
78+
breathe_projects = {"envpool_cpp_api": DOXYGEN_XML_DIR}
79+
breathe_domain_by_extension = {"h": "cpp"}
80+
breathe_default_members = ("members", "undoc-members")
6081

6182
# -- Options for HTML output -------------------------------------------------
6283

@@ -73,8 +94,41 @@ def get_version() -> str:
7394
html_logo = "_static/images/envpool-logo.png"
7495

7596

97+
def generate_doxygen_xml(_app):
98+
"""Generate the Doxygen XML consumed by Breathe."""
99+
doxygen = shutil.which("doxygen")
100+
if doxygen is None:
101+
raise RuntimeError("doxygen is required to build the C++ API docs")
102+
os.makedirs(DOXYGEN_BUILD_DIR, exist_ok=True)
103+
doxyfile = os.path.join(DOXYGEN_BUILD_DIR, "Doxyfile")
104+
inputs = " \\\n".join(
105+
os.path.join(PROJECT_ROOT, header) for header in CPP_API_HEADERS
106+
)
107+
with open(doxyfile, "w", encoding="utf-8") as f:
108+
f.write(
109+
f"""PROJECT_NAME = "EnvPool C++ API"
110+
OUTPUT_DIRECTORY = "{DOXYGEN_BUILD_DIR}"
111+
INPUT = {inputs}
112+
FILE_PATTERNS = *.h
113+
RECURSIVE = NO
114+
GENERATE_HTML = NO
115+
GENERATE_LATEX = NO
116+
GENERATE_XML = YES
117+
XML_OUTPUT = xml
118+
EXTRACT_ALL = YES
119+
EXTRACT_PRIVATE = NO
120+
EXTRACT_STATIC = YES
121+
QUIET = YES
122+
WARN_IF_UNDOCUMENTED = NO
123+
STRIP_FROM_PATH = "{PROJECT_ROOT}"
124+
"""
125+
)
126+
subprocess.run([doxygen, doxyfile], check=True, cwd=PROJECT_ROOT)
127+
128+
76129
def setup(app):
77130
"""Register the Sphinx configuration hooks."""
131+
app.connect("builder-inited", generate_doxygen_xml)
78132
app.add_js_file("js/copybutton.js")
79133
app.add_css_file("css/style.css")
80134

docs/content/cpp_interface.rst

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
C++ API Reference
2+
=================
3+
4+
This reference is generated from the curated ``envpool/core`` headers used by
5+
the :doc:`new_env` integration guide. It is meant to make the C++ extension
6+
surface available on Read the Docs alongside the narrative guide.
7+
8+
9+
Core Data Structures
10+
--------------------
11+
12+
.. doxygenclass:: Array
13+
:project: envpool_cpp_api
14+
15+
.. doxygenclass:: TArray
16+
:project: envpool_cpp_api
17+
18+
.. doxygenclass:: ShapeSpec
19+
:project: envpool_cpp_api
20+
21+
.. doxygenclass:: Spec
22+
:project: envpool_cpp_api
23+
24+
The compile-time dictionary helpers used by these types still live in
25+
``envpool/core/dict.h`` and are referenced throughout :doc:`new_env`.
26+
27+
28+
Environment Authoring
29+
---------------------
30+
31+
.. doxygenvariable:: common_config
32+
:project: envpool_cpp_api
33+
34+
.. doxygenvariable:: common_action_spec
35+
:project: envpool_cpp_api
36+
37+
.. doxygenvariable:: common_state_spec
38+
:project: envpool_cpp_api
39+
40+
.. doxygenclass:: EnvSpec
41+
:project: envpool_cpp_api
42+
43+
.. doxygenclass:: Env
44+
:project: envpool_cpp_api
45+
46+
47+
Pool Implementations
48+
--------------------
49+
50+
.. doxygenclass:: EnvPool
51+
:project: envpool_cpp_api
52+
53+
.. doxygenclass:: AsyncEnvPool
54+
:project: envpool_cpp_api
55+
56+
57+
Python Binding Helpers
58+
----------------------
59+
60+
.. doxygenclass:: PyEnvSpec
61+
:project: envpool_cpp_api
62+
63+
.. doxygenclass:: PyEnvPool
64+
:project: envpool_cpp_api

docs/content/new_env.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ Add New Environment into EnvPool
44
To add a new environment in C++ that EnvPool will parallelly run, we provide a
55
developer interface in `envpool/core/env.h
66
<https://github.com/sail-sg/envpool/blob/main/envpool/core/env.h>`_.
7+
The generated reference for the core headers used below is available in
8+
:doc:`cpp_interface`.
79

810
- For a quick and annotated example, please refer to
911
`envpool/dummy/ <https://github.com/sail-sg/envpool/tree/main/envpool/dummy>`_.

docs/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ stable version through `envpool.readthedocs.io/en/stable/
7676
content/slides
7777
content/build
7878
content/python_interface
79+
content/cpp_interface
7980
content/xla_interface
8081
content/benchmark
8182
content/new_env

docs/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
breathe
12
sphinx
23
sphinx_rtd_theme

docs/spelling_wordlist.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,5 @@ jit
7272
mins
7373
lidar
7474
procgen
75+
Subclassed
76+
deleter

envpool/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
if not hasattr(np, "bool8"):
3131
np.__dict__["bool8"] = np.bool_
3232

33-
__version__ = "0.9.0"
33+
__version__ = "0.9.1"
3434
__all__ = [
3535
"register",
3636
"make",

envpool/core/env_spec.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ auto common_state_spec =
4343
"step_type"_.Bind(Spec<int>({})), "trunc"_.Bind(Spec<bool>({})));
4444

4545
/**
46-
* EnvSpec funciton, it constructs the env spec when a Config is passed.
46+
* EnvSpec function, it constructs the env spec when a Config is passed.
4747
*/
4848
template <typename EnvFns>
4949
class EnvSpec {

0 commit comments

Comments
 (0)