Re: [PATCH v2 1/5] docs: sphinx-pre-install: add macOS Homebrew support

From: Chen Miao

Date: Tue Aug 11 2026 - 09:08:08 EST


Mauro Carvalho Chehab <mchehab+huawei@xxxxxxxxxx> 于2026年8月11日周二 03:56写道:
>
> On Mon, 10 Aug 2026 22:33:05 +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
> > actually 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 virtual environment requirements because Homebrew
> > does not provide a PyYAML formula. Document the macOS setup, the
> > --no-pdf option, and how to create a case-sensitive APFS volume before
> > cloning the kernel tree.
> >
> > Signed-off-by: Chen Miao <chenmiao.ku@xxxxxxxxx>
> > ---
> > Documentation/doc-guide/sphinx.rst | 18 +++++
> > tools/docs/sphinx-pre-install | 113 ++++++++++++++++++++++++++++-
> > 2 files changed, 130 insertions(+), 1 deletion(-)
> >
> > 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..1b9d77ec3 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,7 +1565,11 @@ class SphinxDependencyChecker(MissingCheckers):
> > self.check_program("dot", DepManager.SYSTEM_OPTIONAL)
> > self.check_program("convert", DepManager.SYSTEM_OPTIONAL)
> >
> > - self.check_python_module("yaml")
> > + # PyYAML is installed from Documentation/sphinx/requirements.txt in
> > + # the virtualenv recommended on macOS. Homebrew does not provide a
> > + # PyYAML formula, so do not ask for a nonexistent brew package here.
> > + if not (sys.platform == "darwin" and self.virtualenv and self.need_pip):
> > + self.check_python_module("yaml")
>
> This is not right: yaml is needed even outside venv/pip, as
> it is required to build some docs - See Documentation/sphinx/parser_yaml.py
> extension.
>
> So, basically:
>
> if python on macOS is *always* shipped with python3-yaml package (or
> whatever name it has there), the code would be something like:
>
> # For whatever weird reason, macOS added a non-builtin module
> # on its python package, so no need to check as yaml is always
> # there.
> if sys.platform != "darwin":
> self.check_python_module("yaml")
>
> Otherwise, this hunk is wrong.
>
> >
> > if self.pdf:
> > self.check_program("xelatex", DepManager.PDF_MANDATORY)
>
>
>
> Thanks,
> Mauro
>
You're right. I'll keep checking for PyYAML on macOS and fix this in v3.

Thanks,
Chen Miao