Re: [PATCH v3 2/6] docs: sphinx-pre-install: add macOS Homebrew support

From: Mauro Carvalho Chehab

Date: Wed Aug 12 2026 - 16:19:15 EST


On Thu, 13 Aug 2026 02:23:19 +0800
Chen Miao <chenmiao.ku@xxxxxxxxx> wrote:

> The dependency checker currently reports an unknown distribution on macOS
> and cannot provide installation hints.
>
> Detect macOS and include its product version in the status output. Use
> Homebrew for formula dependencies and install the command-line-only MacTeX
> cask without sudo. Only require Homebrew when dependencies need to be
> installed, install the DejaVu and Noto CJK fonts needed for PDF output, and
> explain how to refresh PATH after installing MacTeX.
>
> Keep PyYAML in the virtualenv requirements because Homebrew does not
> provide a PyYAML formula. Check the module even on macOS: it is required by
> the parser_yaml extension regardless of how Sphinx is installed. When it is
> missing, direct users to the default virtualenv mode.
>
> Signed-off-by: Chen Miao <chenmiao.ku@xxxxxxxxx>

I can't comment on macOS specifics, but the logic looks sane on my
eyes.

Acked-by: Mauro Carvalho Chehab <mchehab+huawei@xxxxxxxxxx>

> ---
> Documentation/doc-guide/sphinx.rst | 18 +++++
> tools/docs/sphinx-pre-install | 110 +++++++++++++++++++++++++++++
> 2 files changed, 128 insertions(+)
>
> diff --git a/Documentation/doc-guide/sphinx.rst b/Documentation/doc-guide/sphinx.rst
> index 51c370260..1e105542a 100644
> --- a/Documentation/doc-guide/sphinx.rst
> +++ b/Documentation/doc-guide/sphinx.rst
> @@ -131,6 +131,24 @@ It supports two optional parameters:
> ``--no-virtualenv``
> Use OS packaging for Sphinx instead of Python virtual environment.
>
> +macOS uses a case-insensitive APFS volume by default, but the kernel tree
> +contains file names that differ only in case. Before cloning the tree, use
> +``diskutil apfs list`` to find the APFS container identifier, replace
> +``diskX`` below with that identifier, and create an additional case-sensitive
> +volume with::
> +
> + diskutil apfs addVolume diskX APFSX Linux
> +
> +On macOS, the script uses Homebrew for system dependencies. Homebrew
> +commands are printed without ``sudo``. The PDF toolchain is provided by the
> +``mactex-no-gui`` cask, while the required DejaVu and Noto CJK fonts are
> +installed from Homebrew font casks; use ``--no-pdf`` when only building HTML
> +documentation. After installing MacTeX, restart the terminal or run
> +``eval "$(/usr/libexec/path_helper)"`` so its command-line tools are visible.
> +The default virtualenv mode is recommended on macOS because PyYAML is
> +installed from ``Documentation/sphinx/requirements.txt`` rather than from a
> +Homebrew formula.
> +
> Installing Sphinx Minimal Version
> ---------------------------------
>
> diff --git a/tools/docs/sphinx-pre-install b/tools/docs/sphinx-pre-install
> index 965c9b093..1956f1369 100755
> --- a/tools/docs/sphinx-pre-install
> +++ b/tools/docs/sphinx-pre-install
> @@ -518,6 +518,24 @@ class MissingCheckers(AncillaryMethods):
> a decent coverage.
> """
>
> + if sys.platform == "darwin":
> + sw_vers = self.which("sw_vers")
> + if sw_vers:
> + try:
> + result = self.run(
> + [sw_vers, "-productVersion"],
> + capture_output=True,
> + text=True,
> + check=True,
> + )
> + version = result.stdout.strip()
> + if version:
> + return f"macOS {version}"
> + except (subprocess.CalledProcessError, FileNotFoundError):
> + pass
> +
> + return "macOS"
> +
> system_release = ""
>
> if self.which("lsb_release"):
> @@ -716,6 +734,93 @@ class SphinxDependencyChecker(MissingCheckers):
>
> return self.get_install_progs(progs, "apt-get install")
>
> + def give_macos_hints(self):
> + """Provide package installation hints for macOS using Homebrew."""
> + progs = {
> + "Pod::Usage": "perl",
> + "convert": "imagemagick",
> + "dot": "graphviz",
> + "ensurepip": "python",
> + "python-sphinx": "sphinx-doc",
> + "rsvg-convert": "librsvg",
> + "xelatex": "mactex-no-gui",
> + "latexmk": "mactex-no-gui",
> + }
> +
> + if self.pdf:
> + font_dirs = [
> + os.path.expanduser("~/Library/Fonts"),
> + "/Library/Fonts",
> + "/System/Library/Fonts",
> + ]
> + pdf_fonts = {
> + "font-dejavu": ["DejaVuSans.ttf"],
> + "font-noto-sans-cjk": ["NotoSansCJK.ttc"],
> + }
> +
> + for package, names in pdf_fonts.items():
> + files = [
> + os.path.join(font_dir, name)
> + for font_dir in font_dirs
> + for name in names
> + ]
> + self.check_missing_file(files, package, DepManager.PDF_MANDATORY)
> +
> + install = self.deps.check_missing(progs)
> +
> + if self.verbose_warn_install:
> + self.deps.warn_install()
> +
> + if not install:
> + return None
> +
> + formulae = set()
> + casks = set()
> + notes = []
> + for package in install.split():
> + if package == "yaml":
> + notes.append(
> + "PyYAML is not provided as a Homebrew formula. Use the "
> + "default virtualenv mode so it is installed from "
> + "Documentation/sphinx/requirements.txt."
> + )
> + continue
> +
> + if package == "mactex-no-gui" or package.startswith("font-"):
> + casks.add(package)
> + else:
> + formulae.add(package)
> +
> + commands = []
> + if formulae:
> + commands.append("\tbrew install " + " ".join(sorted(formulae)))
> + if casks:
> + commands.append("\tbrew install --cask " + " ".join(sorted(casks)))
> +
> + if not commands:
> + self.distro_msg = "\n".join(notes)
> + return None
> +
> + if not self.which("brew"):
> + notes.append(
> + "Homebrew is needed to install the missing dependencies. "
> + "Install it from https://brew.sh/ and re-run this script."
> + )
> + self.distro_msg = "\n".join(notes)
> + return None
> +
> + if "mactex-no-gui" in casks:
> + notes.append(
> + "After installing MacTeX, restart the terminal or run:\n"
> + "\teval \"$(/usr/libexec/path_helper)\"\n"
> + "before re-running this script."
> + )
> +
> + if notes:
> + self.distro_msg = "\n".join(notes)
> +
> + return "\nYou should run:\n" + "\n".join(commands)
> +
> def give_redhat_hints(self):
> """
> Provide package installation hints for RedHat-based distros
> @@ -1138,6 +1243,8 @@ class SphinxDependencyChecker(MissingCheckers):
> re.compile("Kali"): self.give_debian_hints,
> re.compile("Mint"): self.give_debian_hints,
>
> + re.compile("macOS"): self.give_macos_hints,
> +
> re.compile("openSUSE"): self.give_opensuse_hints,
>
> re.compile("Mageia"): self.give_mageia_hints,
> @@ -1458,6 +1565,9 @@ class SphinxDependencyChecker(MissingCheckers):
> self.check_program("dot", DepManager.SYSTEM_OPTIONAL)
> self.check_program("convert", DepManager.SYSTEM_OPTIONAL)
>
> + # PyYAML is required by Documentation/sphinx/parser_yaml.py. The
> + # macOS installation hints explain that it is installed from the
> + # virtualenv requirements, rather than from a Homebrew formula.
> self.check_python_module("yaml")
>
> if self.pdf:



Thanks,
Mauro