1# Zephyr documentation build configuration file.
2# Reference: https://www.sphinx-doc.org/en/master/usage/configuration.html
3
4import os
5import re
6import sys
7import textwrap
8from pathlib import Path
9
10ZEPHYR_BASE = Path(__file__).resolve().parents[1]
11ZEPHYR_BUILD = Path(os.environ.get("OUTPUT_DIR")).resolve()
12
13# Add the '_extensions' directory to sys.path, to enable finding Sphinx
14# extensions within.
15sys.path.insert(0, str(ZEPHYR_BASE / "doc" / "_extensions"))
16
17# Add the '_scripts' directory to sys.path, to enable finding utility
18# modules.
19sys.path.insert(0, str(ZEPHYR_BASE / "doc" / "_scripts"))
20
21# Add the directory which contains the runners package as well,
22# for autodoc directives on runners.xyz.
23sys.path.insert(0, str(ZEPHYR_BASE / "scripts" / "west_commands"))
24
25# Add the directory which contains the pytest-twister-pytest
26sys.path.insert(0, str(ZEPHYR_BASE / "scripts" / "pylib" / "pytest-twister-harness" / "src"))
27
28import redirects  # noqa: E402
29
30try:
31    import west as west_found
32except ImportError:
33    west_found = False
34
35# -- Project --------------------------------------------------------------
36
37project = "Zephyr Project"
38copyright = "2015-2025 Zephyr Project members and individual contributors"
39author = "The Zephyr Project Contributors"
40
41# parse version from 'VERSION' file
42with open(ZEPHYR_BASE / "VERSION") as f:
43    m = re.match(
44        (
45            r"^VERSION_MAJOR\s*=\s*(\d+)$\n"
46            + r"^VERSION_MINOR\s*=\s*(\d+)$\n"
47            + r"^PATCHLEVEL\s*=\s*(\d+)$\n"
48            + r"^VERSION_TWEAK\s*=\s*\d+$\n"
49            + r"^EXTRAVERSION\s*=\s*(.*)$"
50        ),
51        f.read(),
52        re.MULTILINE,
53    )
54
55    if not m:
56        sys.stderr.write("Warning: Could not extract kernel version\n")
57        version = "Unknown"
58    else:
59        major, minor, patch, extra = m.groups(1)
60        version = ".".join((major, minor, patch))
61        if extra:
62            version += "-" + extra
63
64release = version
65
66# parse SDK version from 'SDK_VERSION' file
67with open(ZEPHYR_BASE / "SDK_VERSION") as f:
68    sdk_version = f.read().strip()
69
70# -- General configuration ------------------------------------------------
71
72extensions = [
73    "sphinx_rtd_theme",
74    "sphinx.ext.todo",
75    "sphinx.ext.extlinks",
76    "sphinx.ext.autodoc",
77    "sphinx.ext.graphviz",
78    "sphinxcontrib.jquery",
79    "zephyr.application",
80    "zephyr.html_redirects",
81    "zephyr.kconfig",
82    "zephyr.dtcompatible-role",
83    "zephyr.link-roles",
84    "sphinx_tabs.tabs",
85    "sphinx_sitemap",
86    "zephyr.doxyrunner",
87    "zephyr.doxybridge",
88    "zephyr.doxytooltip",
89    "zephyr.gh_utils",
90    "zephyr.manifest_projects_table",
91    "notfound.extension",
92    "sphinx_copybutton",
93    "sphinx_togglebutton",
94    "zephyr.external_content",
95    "zephyr.domain",
96    "zephyr.api_overview",
97]
98
99# Only use image conversion when it is really needed, e.g. LaTeX build.
100# Ensure "sphinxcontrib.rsvgconverter" is added before "sphinx.ext.imgconverter"
101# as it's better at converting SVG with extended features (like the ones from
102# draw.io) to PDF format).
103if tags.has("convertimages"):  # pylint: disable=undefined-variable  # noqa: F821
104    extensions.append("sphinxcontrib.rsvgconverter")
105    extensions.append("sphinx.ext.imgconverter")
106
107templates_path = ["_templates"]
108
109exclude_patterns = ["_build"]
110
111if not west_found:
112    exclude_patterns.append("**/*west-apis*")
113else:
114    exclude_patterns.append("**/*west-not-found*")
115
116pygments_style = "sphinx"
117highlight_language = "none"
118
119todo_include_todos = False
120
121nitpick_ignore = [
122    # ignore C standard identifiers (they are not defined in Zephyr docs)
123    ("c:identifier", "FILE"),
124    ("c:identifier", "int8_t"),
125    ("c:identifier", "int16_t"),
126    ("c:identifier", "int32_t"),
127    ("c:identifier", "int64_t"),
128    ("c:identifier", "intptr_t"),
129    ("c:identifier", "off_t"),
130    ("c:identifier", "size_t"),
131    ("c:identifier", "ssize_t"),
132    ("c:identifier", "time_t"),
133    ("c:identifier", "uint8_t"),
134    ("c:identifier", "uint16_t"),
135    ("c:identifier", "uint32_t"),
136    ("c:identifier", "uint64_t"),
137    ("c:identifier", "uintptr_t"),
138    ("c:identifier", "va_list"),
139]
140
141SDK_URL_BASE="https://github.com/zephyrproject-rtos/sdk-ng/releases/download"
142
143rst_epilog = f"""
144.. include:: /substitutions.txt
145
146.. |sdk-version-literal| replace:: ``{sdk_version}``
147.. |sdk-version-trim| unicode:: {sdk_version}
148   :trim:
149.. |sdk-version-ltrim| unicode:: {sdk_version}
150   :ltrim:
151.. _Zephyr SDK bundle: https://github.com/zephyrproject-rtos/sdk-ng/releases/tag/v{sdk_version}
152.. |sdk-url-linux| replace::
153   `{SDK_URL_BASE}/v{sdk_version}/zephyr-sdk-{sdk_version}_linux-x86_64.tar.xz`
154.. |sdk-url-linux-sha| replace::
155   `{SDK_URL_BASE}/v{sdk_version}/sha256.sum`
156.. |sdk-url-macos| replace::
157   `{SDK_URL_BASE}/v{sdk_version}/zephyr-sdk-{sdk_version}_macos-x86_64.tar.xz`
158.. |sdk-url-macos-sha| replace::
159   `{SDK_URL_BASE}/v{sdk_version}/sha256.sum`
160.. |sdk-url-windows| replace::
161   `{SDK_URL_BASE}/v{sdk_version}/zephyr-sdk-{sdk_version}_windows-x86_64.7z`
162"""
163
164# -- Options for HTML output ----------------------------------------------
165
166html_theme = "sphinx_rtd_theme"
167html_theme_options = {
168    "logo_only": True,
169    "prev_next_buttons_location": None,
170    "navigation_depth": 5,
171}
172html_baseurl = "https://docs.zephyrproject.org/latest/"
173html_title = "Zephyr Project Documentation"
174html_logo = str(ZEPHYR_BASE / "doc" / "_static" / "images" / "logo.svg")
175html_favicon = str(ZEPHYR_BASE / "doc" / "_static" / "images" / "favicon.png")
176html_static_path = [str(ZEPHYR_BASE / "doc" / "_static")]
177html_last_updated_fmt = "%b %d, %Y"
178html_domain_indices = False
179html_split_index = True
180html_show_sourcelink = False
181html_show_sphinx = False
182html_search_scorer = str(ZEPHYR_BASE / "doc" / "_static" / "js" / "scorer.js")
183html_additional_pages = {
184    "gsearch": "gsearch.html"
185}
186
187is_release = tags.has("release")  # pylint: disable=undefined-variable  # noqa: F821
188reference_prefix = ""
189if tags.has("publish"):  # pylint: disable=undefined-variable  # noqa: F821
190    reference_prefix = f"/{version}" if is_release else "/latest"
191docs_title = "Docs / {}".format(version if is_release else "Latest")
192html_context = {
193    "show_license": True,
194    "docs_title": docs_title,
195    "is_release": is_release,
196    "current_version": version,
197    "versions": (
198        ("latest", "/"),
199        ("4.1.0", "/4.1.0/"),
200        ("4.0.0", "/4.0.0/"),
201        ("3.7.0 (LTS)", "/3.7.0/"),
202    ),
203    "display_gh_links": True,
204    "reference_links": {
205        "API": f"{reference_prefix}/doxygen/html/index.html",
206        "Kconfig Options": f"{reference_prefix}/kconfig.html",
207        "Devicetree Bindings": f"{reference_prefix}/build/dts/api/bindings.html",
208        "West Projects": f"{reference_prefix}/develop/manifest/index.html",
209    },
210    # Set google_searchengine_id to your Search Engine ID to replace built-in search
211    # engine with Google's Programmable Search Engine.
212    # See https://programmablesearchengine.google.com/ for details.
213    "google_searchengine_id": "746031aa0d56d4912",
214}
215
216# -- Options for LaTeX output ---------------------------------------------
217
218latex_elements = {
219    "papersize": "a4paper",
220    "maketitle": (ZEPHYR_BASE / "doc" / "_static" / "latex" / "title.tex").read_text(),
221    "preamble": (ZEPHYR_BASE / "doc" / "_static" / "latex" / "preamble.tex").read_text(),
222    "makeindex": r"\usepackage[columns=1]{idxlayout}\makeindex",
223    "fontpkg": textwrap.dedent(r"""
224                                    \usepackage{noto}
225                                    \usepackage{inconsolata-nerd-font}
226                                    \usepackage[T1]{fontenc}
227                                """),
228    "sphinxsetup": ",".join(
229        (
230            # NOTE: colors match those found in light.css stylesheet
231            "verbatimwithframe=false",
232            "VerbatimColor={HTML}{f0f2f4}",
233            "InnerLinkColor={HTML}{2980b9}",
234            "warningBgColor={HTML}{e9a499}",
235            "warningborder=0pt",
236            r"HeaderFamily=\rmfamily\bfseries",
237        )
238    ),
239}
240latex_logo = str(ZEPHYR_BASE / "doc" / "_static" / "images" / "logo-latex.pdf")
241latex_documents = [
242    ("index-tex", "zephyr.tex", "Zephyr Project Documentation", author, "manual"),
243]
244latex_engine = "xelatex"
245
246# -- Options for zephyr.doxyrunner plugin ---------------------------------
247
248doxyrunner_doxygen = os.environ.get("DOXYGEN_EXECUTABLE", "doxygen")
249doxyrunner_projects = {
250    "zephyr": {
251        "doxyfile": ZEPHYR_BASE / "doc" / "zephyr.doxyfile.in",
252        "outdir": ZEPHYR_BUILD / "doxygen",
253        "fmt": True,
254        "fmt_vars": {
255            "ZEPHYR_BASE": str(ZEPHYR_BASE),
256            "ZEPHYR_VERSION": version,
257        },
258        "outdir_var": "DOXY_OUT",
259    },
260}
261
262# -- Options for zephyr.doxybridge plugin ---------------------------------
263
264doxybridge_projects = {"zephyr": doxyrunner_projects["zephyr"]["outdir"]}
265
266# -- Options for html_redirect plugin -------------------------------------
267
268html_redirect_pages = redirects.REDIRECTS
269
270# -- Options for zephyr.link-roles ----------------------------------------
271
272link_roles_manifest_project = "zephyr"
273link_roles_manifest_project_broken_links_ignore_globs = [
274    "releases/release-notes-[123].*.rst",
275]
276link_roles_manifest_baseurl = "https://github.com/zephyrproject-rtos/zephyr"
277
278# -- Options for notfound.extension ---------------------------------------
279
280notfound_urls_prefix = f"/{version}/" if is_release else "/latest/"
281
282# -- Options for zephyr.gh_utils ------------------------------------------
283
284gh_link_version = f"v{version}" if is_release else "main"
285gh_link_base_url = "https://github.com/zephyrproject-rtos/zephyr"
286gh_link_prefixes = {
287    "samples/.*": "",
288    "boards/.*": "",
289    "snippets/.*": "",
290    ".*": "doc",
291}
292gh_link_exclude = [
293    "reference/kconfig.*",
294    "build/dts/api/bindings.*",
295    "build/dts/api/compatibles.*",
296]
297
298# -- Options for zephyr.kconfig -------------------------------------------
299
300kconfig_generate_db = True
301kconfig_ext_paths = [ZEPHYR_BASE]
302kconfig_gh_link_base_url = "https://github.com/zephyrproject-rtos/zephyr"
303kconfig_zephyr_version = f"v{version}" if is_release else "main"
304
305# -- Options for zephyr.external_content ----------------------------------
306
307external_content_contents = [
308    (ZEPHYR_BASE / "doc", "[!_]*"),
309    (ZEPHYR_BASE, "boards/**/*.rst"),
310    (ZEPHYR_BASE, "boards/**/doc"),
311    (ZEPHYR_BASE, "samples/**/*.html"),
312    (ZEPHYR_BASE, "samples/**/*.rst"),
313    (ZEPHYR_BASE, "samples/**/doc"),
314    (ZEPHYR_BASE, "snippets/**/*.rst"),
315    (ZEPHYR_BASE, "snippets/**/doc"),
316    (ZEPHYR_BASE, "tests/**/*.pts"),
317]
318external_content_keep = [
319    "reference/kconfig/*",
320    "develop/manifest/index.rst",
321    "build/dts/api/bindings.rst",
322    "build/dts/api/bindings/**/*",
323    "build/dts/api/compatibles/**/*",
324]
325
326# -- Options for zephyr.domain --------------------------------------------
327
328zephyr_breathe_insert_related_samples = True
329zephyr_generate_hw_features = not tags.has("hw_features_turbo")  # pylint: disable=undefined-variable  # noqa: F821
330
331# -- Options for sphinx.ext.graphviz --------------------------------------
332
333graphviz_dot = os.environ.get("DOT_EXECUTABLE", "dot")
334graphviz_output_format = "svg"
335graphviz_dot_args = [
336    "-Gbgcolor=transparent",
337    "-Nstyle=filled",
338    "-Nfillcolor=white",
339    "-Ncolor=gray60",
340    "-Nfontcolor=gray25",
341    "-Ecolor=gray60",
342    "-Gfontname=system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif",
343    "-Nfontname=system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif",
344    "-Efontname=SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace",
345]
346
347# -- Options for sphinx_copybutton ----------------------------------------
348
349copybutton_prompt_text = r"\$ |uart:~\$ "
350copybutton_prompt_is_regexp = True
351
352# -- Options for sphinx-sitemap ----------------------------------------
353
354sitemap_url_scheme = "{link}"
355
356# -- Linkcheck options ----------------------------------------------------
357
358linkcheck_ignore = [
359    r"https://github.com/zephyrproject-rtos/zephyr/issues/.*"
360]
361
362extlinks = {
363    "github": ("https://github.com/zephyrproject-rtos/zephyr/issues/%s", "GitHub #%s"),
364}
365
366linkcheck_timeout = 30
367linkcheck_workers = 10
368linkcheck_anchors = False
369
370# -- Options for zephyr.api_overview --------------------------------------
371
372api_overview_doxygen_out_dir = str(doxyrunner_projects["zephyr"]["outdir"])
373api_overview_base_url = "https://github.com/zephyrproject-rtos/zephyr"
374
375def setup(app):
376    # theme customizations
377    app.add_css_file("css/custom.css")
378    app.add_js_file("js/custom.js")
379