diff --git a/doc/man/README.md b/doc/man/README.md new file mode 100644 index 0000000000..2814b3e6a4 --- /dev/null +++ b/doc/man/README.md @@ -0,0 +1,41 @@ + +# Building the Manpage + +## Building from the tarball + +When building BIND from the tarball, there will be pre-generated `.in` manpage templates. +For every page relevant to the build (`man_srcset`), meson will generate the manpage and install it using `install_man`. + +Sphinx can also be used like in git tree builds described below but the pages generated with sphinx will not be installed if templated ones are available. + +## Building from the git tree + +Sphinx is required when building the manpages from the git tree. +If `sphinx-build` didn't exist when creating the build directory, build targets for the manpage will not exist. +Use the command `meson configure --clearcache` to force the next build to probe for sphinx again. + +The source set `manrst_srcset` is used only to determine when a rebuild is necessary from meson's perspective and doesn't actually pass the source files. +Sphinx works by handling entire directories and so meson needs to use `depend_files` for the task. + +To find which optional manpages need to be built or not, we pass the build directory to sphinx using the environment variable `BIND_BUILD_ROOT`. +Sphinx will then inspect the meson-generated `intro-targets.json` file to see which optional build components are enabled. + +If an optional component like LMDB is disabled in the build directory, its corresponding manpage needs to be removed. +From meson's perspective, the entire folder is the output and doesn't concern itself with the insides specifically. +This is done by checking which optional targets are not built but have the page entry in the output folder. + +If the `BIND_BUILD_ROOT` is not specified, sphinx will build every page. +This is used when creating a release tarball. +Meson will use the script `util/meson-dist-package.sh` to create the templates when runnnig the `dist` command. +If sphinx is not available in the build directory, this step will be skipped and so the tarballs must be created on a system with `sphinx-build`. diff --git a/doc/man/conf.py b/doc/man/conf.py index 2ba58b805e..d0d8f65843 100644 --- a/doc/man/conf.py +++ b/doc/man/conf.py @@ -11,6 +11,8 @@ # information regarding copyright ownership. ############################################################################ +import json +import os import sys from pathlib import Path @@ -123,13 +125,6 @@ man_pages = [ ), ("dnssec-signzone", "dnssec-signzone", "DNSSEC zone signing tool", author, 1), ("dnssec-verify", "dnssec-verify", "DNSSEC zone verification tool", author, 1), - ( - "dnstap-read", - "dnstap-read", - "print dnstap data in human-readable form", - author, - 1, - ), ( "filter-aaaa", "filter-aaaa", @@ -181,13 +176,6 @@ man_pages = [ author, 1, ), - ( - "named-nzd2nzf", - "named-nzd2nzf", - "convert an NZD database to NZF text format", - author, - 1, - ), ( "named-rrchecker", "named-rrchecker", @@ -206,6 +194,53 @@ man_pages = [ ("tsig-keygen", "tsig-keygen", "TSIG key generation tool", author, 8), ] +bind_optional_pages = { + "dnstap-read": ( + "dnstap-read", + "dnstap-read", + "print dnstap data in human-readable form", + author, + 1, + ), + "named-nzd2nzf": ( + "named-nzd2nzf", + "named-nzd2nzf", + "convert an NZD database to NZF text format", + author, + 1, + ), +} + +bind_build_root = os.getenv("BIND_BUILD_ROOT") +if bind_build_root is None: + man_pages.extend(bind_optional_pages.values()) +else: + bind_build_path = Path(bind_build_root).resolve() + with open( + bind_build_path / "meson-info" / "intro-targets.json", encoding="utf-8" + ) as f: + for target in json.load(f): + if target["name"] in bind_optional_pages: + page = bind_optional_pages.pop(target["name"]) + man_pages.append(page) + + # Delete artifacts if an optional binary is no longer built. + # This happens when the build directory is reconfigured to exclude + # dnstap etc. + # + # Meson can't handle this because: + # - "man.p" is under our control + # - Meson just expects an entire folder as an output, this is just how sphinx works. + for unused in bind_optional_pages.values(): + doctree = bind_build_path / "man.p" / f"{unused[0]}.doctree" + if doctree.exists(): + doctree.unlink() + + page = bind_build_path / "man" / f"man{unused[4]}" / f"{unused[0]}.{unused[4]}" + if page.exists(): + page.unlink() + + # # The rst_epilog will be completely overwritten from meson # the definition here is provided for when manpages are generated diff --git a/meson.build b/meson.build index c00be2bdce..6a1e57fa9a 100644 --- a/meson.build +++ b/meson.build @@ -1670,6 +1670,7 @@ if doc_opt.allowed() custom_target( 'man', + build_always_stale: true, depend_files: manrst_srcconf.sources(), depends: doc_misc_targets, install: man_srcconf.sources().length() == 0, diff --git a/util/meson-dist-package.sh b/util/meson-dist-package.sh index 7a60e18c75..3fb6e56c54 100644 --- a/util/meson-dist-package.sh +++ b/util/meson-dist-package.sh @@ -18,9 +18,6 @@ if [ -z "$MESON_DIST_ROOT" ] || [ -z "$MESON_SOURCE_ROOT" ]; then exit 1 fi -export BIND_BUILD_ROOT=${MESON_BUILD_ROOT} -export BIND_SOURCE_ROOT=${MESON_SOURCE_ROOT} - generate_man_pages() { export MESON_PROJECT_VERSION=$1