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