1.. _contrib-docs-build: 2 3========================================= 4Working with the pigweed.dev build system 5========================================= 6``pigweed.dev`` is built with Bazel. When you want to add or remove files 7used by ``pigweed.dev``, you'll need to interact with this Bazel-based 8documentation generation (docgen) system. 9 10Check out :ref:`contrib-docs-build-appendix-architecture` for a top-down explanation 11of the main components of the docgen system. 12 13.. _contrib-docs-build-quickstart: 14 15---------- 16Quickstart 17---------- 18#. Build the docs: 19 20 .. code-block:: console 21 22 $ bazelisk build //docs:docs 23 24#. Locally preview the docs: 25 26 .. code-block:: console 27 28 $ bazelisk run //docs:docs.serve 29 30.. _contrib-docs-build-setup: 31 32----- 33Setup 34----- 35Before you can do anything with the Bazel-based docgen system, you must 36complete this setup: 37 38#. Complete :ref:`docs-first-time-setup`. 39 40#. :ref:`docs-install-bazel`. 41 42.. _contrib-docs-build-files: 43 44--------------------------- 45Add files to the docs build 46--------------------------- 47 48.. _contrib-docs-build-files-doxygen: 49 50Add files to the C/C++ API reference auto-generation system (Doxygen) 51===================================================================== 52#. Package your headers into a ``filegroup``: 53 54 .. code-block:: py 55 56 filegroup( 57 name = "doxygen", 58 srcs = [ 59 "public/pw_string/format.h", 60 "public/pw_string/string.h", 61 "public/pw_string/string_builder.h", 62 "public/pw_string/utf_codecs.h", 63 "public/pw_string/util.h", 64 ], 65 ) 66 67#. Update ``doxygen_srcs`` in ``//docs/BUILD.bazel`` to take a 68 dependency on your new ``filegroup``: 69 70 .. code-block:: py 71 72 filegroup( 73 name = "doxygen_srcs", 74 srcs = [ 75 # … 76 "//pw_string:doxygen", 77 # … 78 ] 79 ) 80 81.. _Breathe directive: https://breathe.readthedocs.io/en/latest/directives.html 82 83#. Use a `Breathe directive`_ such as ``.. doxygenclass::`` to pull the API 84 reference content into a reStructuredText file. 85 86.. _contrib-docs-build-files-autodoc: 87 88Add files to the Python API reference auto-generation system (autodoc) 89====================================================================== 90If you see an error like this: 91 92.. code-block:: text 93 94 sphinx.errors.SphinxWarning: autodoc: failed to import module 'benchmark' 95 from module 'pw_rpc'; the following exception was raised: 96 No module named 'pw_rpc.benchmark' 97 98.. inclusive-language: disable 99.. _autodoc: https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html 100.. inclusive-language: enable 101 102It means that `autodoc`_ (the program we use to auto-generate Python API 103references) could not find the source code for the module that it was 104supposed to document. To fix this: 105 106#. Add your Python target as a dependency to the ``sphinx_build_binary`` 107 rule in ``//docs/BUILD.bazel``: 108 109 .. code-block:: py 110 111 sphinx_build_binary( 112 name = "sphinx_build", 113 target_compatible_with = incompatible_with_mcu(), 114 deps = [ 115 # … 116 "//pw_rpc/py:pw_rpc_benchmark", 117 # … 118 ], 119 ) 120 121.. _contrib-docs-build-files-sphinx: 122 123Add reStructuredText files to Sphinx 124==================================== 125#. Package your inputs into a ``sphinx_docs_library``: 126 127 .. code-block:: py 128 129 load("@rules_python//sphinxdocs:sphinx_docs_library.bzl", "sphinx_docs_library") 130 load("//pw_build:compatibility.bzl", "incompatible_with_mcu") 131 132 sphinx_docs_library( 133 name = "docs", 134 srcs = [ 135 "docs.rst", 136 ], 137 prefix = "pw_elf/", 138 target_compatible_with = incompatible_with_mcu(), 139 visibility = ["//visibility:public"], 140 ) 141 142#. Update ``docs`` in ``//docs/BUILD.bazel`` to take a dependency on 143 your new ``sphinx_docs_library``: 144 145 .. code-block:: py 146 147 sphinx_docs( 148 name = "docs", 149 # … 150 deps = [ 151 # … 152 "//pw_elf:docs", 153 # … 154 ] 155 ) 156 157.. _toctree: https://documatt.com/restructuredtext-reference/element/toctree.html 158 159#. Add your new reStructuredText files to an existing `toctree`_, or create a new one. 160 161.. _contrib-docs-build-files-source: 162 163Add source code to the docs build 164================================= 165Whenever possible, don't manually write code examples in your reStructuredText 166(reST) docs. These code examples will bitrot over time. Instead, put your code 167examples in real source code that can actually be built and tested, and then 168use Sphinx's ``literalinclude`` feature to insert the code example into your 169doc. 170 171#. Put your code example into a unit test: 172 173 .. code-block:: c++ 174 175 // examples.cc 176 177 TEST(StringExamples, BufferExample) { 178 // START: BufferExample 179 // … 180 // END: BufferExample 181 } 182 183#. Include the code example in your reST: 184 185 .. code-block:: rest 186 187 .. literalinclude:: ./examples.cc 188 :language: cpp 189 :dedent: 190 :start-after: // START: BufferExample 191 :end-before: // END: BufferExample 192 193#. Add the source code file to the ``srcs`` list in your 194 ``sphinx_docs_library`` target: 195 196 .. code-block:: py 197 198 sphinx_docs_library( 199 name = "docs", 200 srcs = [ 201 # … 202 "examples.cc", 203 # … 204 ], 205 ) 206 207.. _contrib-docs-build-files-images: 208 209Add images 210========== 211Images should not be checked into the Pigweed repo. 212See :ref:`contrib-docs-website-images`. 213 214.. _contrib-docs-build-files-remove: 215 216---------------------------------------- 217Remove or change files in the docs build 218---------------------------------------- 219Here's the general workflow: 220 221#. Remove or change files that are used in the docs build. 222 223#. :ref:`contrib-docs-build-build`. 224 225#. When the docs build fails, Bazel's logs will tell you what you need to do 226 next. If Bazel's logs aren't informative, try some of the tips described 227 in :ref:`contrib-docs-build-debug`. 228 229You may need to do some or all of these steps: 230 231* In your module's ``BUILD.bazel`` files, update these rules: 232 233 * ``sphinx_docs_library`` targets (usually named ``docs``) 234 235 * ``filegroup`` targets named ``doxygen`` 236 237* Update ``//docs/BUILD.bazel``. 238 239* :ref:`redirects <contrib-docs-website-redirects>`. 240 241.. _contrib-docs-build-build: 242 243-------------- 244Build the docs 245-------------- 246.. code-block:: console 247 248 $ bazelisk build //docs:docs 249 250.. _contrib-docs-build-build-watch: 251 252Watch the docs (automatically rebuild when files change) 253======================================================== 254.. code-block:: console 255 256 $ bazelisk run //:watch build //docs:docs 257 258.. tip:: 259 260 Try :ref:`locally previewing the docs <contrib-docs-build-preview>` in one console 261 tab and watching the docs in another tab. 262 263.. _contrib-docs-build-preview: 264 265------------------------ 266Locally preview the docs 267------------------------ 268.. code-block:: console 269 270 $ bazelisk run //docs:docs.serve 271 272A message like this should get printed to ``stdout``: 273 274.. code-block:: text 275 276 Serving... 277 Address: http://0.0.0.0:8000 278 Serving directory: /home/kayce/pigweed/pigweed/bazel-out/k8-fastbuild/bin/docs/docs/_build/html 279 url: file:///home/kayce/pigweed/pigweed/bazel-out/k8-fastbuild/bin/docs/docs/_build/html 280 Server CWD: /home/kayce/.cache/bazel/_bazel_kayce/9659373b1552c281136de1c8eeb3080d/execroot/_main/bazel-out/k8-fastbuild/bin/docs/docs.serve.runfiles/_main 281 282You can access the rendered docs at the URL that's printed next to 283**Address** (``http://0.0.0.0:8000`` in the example). 284 285.. _contrib-docs-build-list: 286 287--------------------- 288List all docs sources 289--------------------- 290.. _hermetic: https://bazel.build/basics/hermeticity 291 292Bazel builds the docs in a `hermetic`_ environment. All inputs to the docgen 293system must be copied into this hermetic environment. To check that you're 294copying your files to the correct directory, run this command: 295 296.. code-block:: console 297 298 $ bazelisk build //docs:_docs/_sources 299 300.. _contrib-docs-build-debug: 301 302-------------------- 303Debug the docs build 304-------------------- 305.. inclusive-language: disable 306.. _sphinx-build: https://www.sphinx-doc.org/en/master/man/sphinx-build.html 307.. _--verbose: https://www.sphinx-doc.org/en/master/man/sphinx-build.html#cmdoption-sphinx-build-v 308.. inclusive-language: enable 309 310When things go wrong, run this command to build the docs in a 311non-`hermetic`_ environment: 312 313.. code-block:: console 314 315 $ bazelisk run //docs:docs.run 316 317Also consider tweaking these ``extra_opts`` from the ``sphinx_docs`` rule in 318``//docs/BUILD.bazel``: 319 320* Comment out the ``--silent`` warning to get more verbose logging output. 321* Check `sphinx-build`_ to see what other options you might want to add or remove. 322 ``sphinx-build`` is the underlying command that the ``sphinx_docs`` Bazel rule runs. 323 324.. _contrib-docs-build-troubleshoot: 325 326--------------- 327Troubleshooting 328--------------- 329 330.. _contrib-docs-build-troubleshoot-autodoc: 331 332autodoc: failed to import module 333================================ 334See :ref:`contrib-docs-build-files-autodoc`. 335 336.. _contrib-docs-build-appendix-architecture: 337 338------------------------------- 339Appendix: Architecture overview 340------------------------------- 341The outputs of some components of the docgen system are used as inputs 342to other components. 343 344.. mermaid:: 345 346 flowchart LR 347 348 Doxygen --> Breathe 349 Breathe --> reST 350 reST --> Sphinx 351 Rust --> Sphinx 352 Python --> Sphinx 353 354.. _Doxygen: https://www.doxygen.nl/ 355.. _Breathe: https://breathe.readthedocs.io/en/latest/ 356.. _reStructuredText: https://docutils.sourceforge.io/rst.html 357.. _rustdoc: https://doc.rust-lang.org/rustdoc/what-is-rustdoc.html 358.. inclusive-language: disable 359.. _autodoc: https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html 360.. _Sphinx: https://www.sphinx-doc.org/en/master/ 361.. inclusive-language: enable 362.. _static site generator: https://en.wikipedia.org/wiki/Static_site_generator 363 364* **Doxygen**: We feed a bunch of C/C++ headers to `Doxygen`_. Doxygen parses each 365 header and generates XML metadata for all of the classes, functions, structs, 366 etc. that it finds. We also publish the Doxygen-generated HTML as a separate 367 subsite. This subsite is available at 368 `pigweed.dev/doxygen <https://pigweed.dev/doxygen>`_. 369 370* **Breathe**: We provide the Doxygen XML metadata to `Breathe`_ so that C/C++ API 371 reference content can be inserted into our reStructuredText files. 372 373* **reST**: We gather up all the `reStructuredText`_ (reST) source files 374 that are scattered across the Pigweed repository. Pigweed docs are authored in 375 reST. We don't use Markdown. 376 377* **Rust**: `rustdoc`_ generates Rust API reference content, similar to how 378 Doxygen generates C/C++ API reference content. The Rust API references are output 379 as HTML. It's essentially a separate documentation subsite that is not integrated 380 with the rest of ``pigweed.dev`` (yet). This subsite is available at URLs like 381 `pigweed.dev/rustdoc/pw_bytes/ <https://pigweed.dev/rustdoc/pw_bytes/>`_. 382 383* **Python**: We use Sphinx's `autodoc`_ feature to auto-generate Python API 384 reference content. In order for this to work, the Python modules must be 385 listed as dependencies of the ``//docs:docs`` target. 386 387* **Sphinx**: Once all the other inputs are ready, we can use `Sphinx`_ 388 (essentially a `static site generator`_) to build the ``pigweed.dev`` 389 website. 390