Hi,

On 2023-03-15 20:55:33 -0700, Andres Freund wrote:
> WIP patch for that attached. There's now
>   install-doc-man
>   install-doc-html
> run targets and a
>   install-docs
> alias target.
> 
> 
> I did end up getting stuck when hacking on this, and ended up adding css
> support for nochunk and support for the website style for htmlhelp and
> nochunk, as well as obsoleting the need for copying the css files... But
> perhaps that's a bit too much.

Updated set of patches attached. This one works in older meson versions too
and adds install-world and install-quiet targets.


I also ended up getting so frustrated at the docs build speed that I started
to hack a bit on that. I attached a patch shaving a few seconds off the
buildtime.


I think we can make the docs build in parallel and incrementally, by building
the different parts of the docs in parallel, using --stringparam rootid,
e.g. building each 'part' separately.

A very very rough draft attached:

parallel with parts:
real    0m10.831s
user    0m58.295s
sys     0m1.402s

normal:
real    0m32.215s
user    0m31.876s
sys     0m0.328s

1/3 of the build time at 2x the cost is nothing to sneeze at.

Greetings,

Andres Freund
>From 9313c2938265109b3a82f96697bae26ed3f74412 Mon Sep 17 00:00:00 2001
From: Andres Freund <and...@anarazel.de>
Date: Wed, 15 Mar 2023 15:53:14 -0700
Subject: [PATCH v2 1/8] meson: rename html_help target to htmlhelp

Reported-by: Peter Eisentraut <peter.eisentr...@enterprisedb.com>
Discussion: https://postgr.es/m/3fc3bb9b-f7f8-d442-35c1-ec82280c5...@enterprisedb.com
---
 doc/src/sgml/meson.build | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/doc/src/sgml/meson.build b/doc/src/sgml/meson.build
index 38f1b8e7b17..e6fe124c7bc 100644
--- a/doc/src/sgml/meson.build
+++ b/doc/src/sgml/meson.build
@@ -123,7 +123,7 @@ if xsltproc_bin.found()
   # build multi-page html docs as part of docs target
   docs += html
 
-  html_help = custom_target('html_help',
+  htmlhelp = custom_target('htmlhelp',
     input: ['stylesheet-hh.xsl', postgres_full_xml],
     output: 'htmlhelp',
     depfile: 'htmlhelp.d',
@@ -131,7 +131,7 @@ if xsltproc_bin.found()
     command: [xsltproc, '--path', '@OUTDIR@', '-o', '@OUTDIR@/', xsltproc_flags, '@INPUT@'],
     build_by_default: false,
   )
-  alldocs += html_help
+  alldocs += htmlhelp
 
 
   # single-page HTML
-- 
2.38.0

>From 10fd8d20ae15889054e69e0b62a445e52b9afe2f Mon Sep 17 00:00:00 2001
From: Andres Freund <and...@anarazel.de>
Date: Wed, 15 Mar 2023 16:29:27 -0700
Subject: [PATCH v2 2/8] meson: make install_test_files more generic, rename to
 install_files

Now it supports installing directories and directory contents as well. This
will be used in a subsequent patch to install doc contents.
---
 meson.build                  |  5 ++-
 src/tools/install_files      | 72 ++++++++++++++++++++++++++++++++++++
 src/tools/install_test_files | 33 -----------------
 3 files changed, 75 insertions(+), 35 deletions(-)
 create mode 100644 src/tools/install_files
 delete mode 100644 src/tools/install_test_files

diff --git a/meson.build b/meson.build
index 7f76a101ecf..84fe2c3d4c3 100644
--- a/meson.build
+++ b/meson.build
@@ -369,6 +369,8 @@ flex_cmd = [python, flex_wrapper,
 wget = find_program('wget', required: false, native: true)
 wget_flags = ['-O', '@OUTPUT0@', '--no-use-server-timestamps']
 
+install_files = files('src/tools/install_files')
+
 
 
 ###############################################################
@@ -2845,9 +2847,8 @@ testprep_targets += test_install_libs
 
 
 # command to install files used for tests, which aren't installed by default
-install_test_files = files('src/tools/install_test_files')
 install_test_files_args = [
-  install_test_files,
+  install_files,
   '--prefix', dir_prefix,
   '--install', contrib_data_dir, test_install_data,
   '--install', dir_lib_pkg, test_install_libs,
diff --git a/src/tools/install_files b/src/tools/install_files
new file mode 100644
index 00000000000..0428316b67e
--- /dev/null
+++ b/src/tools/install_files
@@ -0,0 +1,72 @@
+#!/usr/bin/env python3
+
+# Helper to install additional files into the temporary installation
+# for tests, beyond those that are installed by meson/ninja install.
+
+import argparse
+import os
+import shutil
+import sys
+from pathlib import PurePath
+
+parser = argparse.ArgumentParser()
+
+parser.add_argument('--destdir', type=str,
+                    default=os.environ.get('DESTDIR', None))
+parser.add_argument('--prefix', type=str)
+parser.add_argument('--install', type=str, nargs='+',
+                    action='append', default=[])
+parser.add_argument('--install-dirs', type=str, nargs='+',
+                    action='append', default=[])
+parser.add_argument('--install-dir-contents', type=str, nargs='+',
+                    action='append', default=[])
+
+args = parser.parse_args()
+
+
+def error_exit(msg: str):
+    print(msg, file=sys.stderr)
+    exit(1)
+
+
+def create_target_dir(prefix: str, destdir: str, targetdir: str):
+    if not os.path.isabs(targetdir):
+        targetdir = os.path.join(prefix, targetdir)
+
+    if destdir is not None:
+        # copy of meson's logic for joining destdir and install paths
+        targetdir = str(PurePath(destdir, *PurePath(targetdir).parts[1:]))
+
+    os.makedirs(targetdir, exist_ok=True)
+
+    return targetdir
+
+
+def copy_files(targetdir: str, src_list: list):
+    for src in src_list:
+        shutil.copy2(src, targetdir)
+
+
+def copy_dirs(targetdir: str, src_list: list, contents: bool):
+    for src in src_list:
+        if not os.path.isdir(src):
+            error_exit('{0} is not a directory'.format(src))
+
+        if contents:
+            target = targetdir
+        else:
+            target = os.path.join(targetdir, os.path.split(src)[1])
+        shutil.copytree(src, target, dirs_exist_ok=True)
+
+
+for installs in args.install:
+    targetdir = create_target_dir(args.prefix, args.destdir, installs[0])
+    copy_files(targetdir, installs[1:])
+
+for installs in args.install_dirs:
+    targetdir = create_target_dir(args.prefix, args.destdir, installs[0])
+    copy_dirs(targetdir, installs[1:], contents=False)
+
+for installs in args.install_dir_contents:
+    targetdir = create_target_dir(args.prefix, args.destdir, installs[0])
+    copy_dirs(targetdir, installs[1:], contents=True)
diff --git a/src/tools/install_test_files b/src/tools/install_test_files
deleted file mode 100644
index 8e0b36a74d1..00000000000
--- a/src/tools/install_test_files
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/usr/bin/env python3
-
-# Helper to install additional files into the temporary installation
-# for tests, beyond those that are installed by meson/ninja install.
-
-import argparse
-import shutil
-import os
-from pathlib import PurePath
-
-parser = argparse.ArgumentParser()
-
-parser.add_argument('--destdir', type=str, default=os.environ.get('DESTDIR', None))
-parser.add_argument('--prefix', type=str)
-parser.add_argument('--install', type=str, nargs='+', action='append')
-
-args = parser.parse_args()
-
-def copy_files(prefix: str, destdir: str, targetdir: str, src_list: list):
-    if not os.path.isabs(targetdir):
-        targetdir = os.path.join(prefix, targetdir)
-
-    if destdir is not None:
-        # copy of meson's logic for joining destdir and install paths
-        targetdir = str(PurePath(destdir, *PurePath(targetdir).parts[1:]))
-
-    os.makedirs(targetdir, exist_ok=True)
-
-    for src in src_list:
-        shutil.copy2(src, targetdir)
-
-for installs in args.install:
-    copy_files(args.prefix, args.destdir, installs[0], installs[1:])
-- 
2.38.0

>From bb0756f88e3dba00bfc5f3efe90d9ab785f62831 Mon Sep 17 00:00:00 2001
From: Andres Freund <and...@anarazel.de>
Date: Wed, 15 Mar 2023 16:43:40 -0700
Subject: [PATCH v2 3/8] wip: meson: add install-{docs,doc-html,doc-man}
 targets

---
 meson.build              |  2 +-
 doc/src/sgml/meson.build | 67 +++++++++++++++++++++++++++++++++++++++-
 2 files changed, 67 insertions(+), 2 deletions(-)

diff --git a/meson.build b/meson.build
index 84fe2c3d4c3..33dd5b43ed5 100644
--- a/meson.build
+++ b/meson.build
@@ -504,7 +504,7 @@ dir_man = get_option('mandir')
 
 # FIXME: These used to be separately configurable - worth adding?
 dir_doc = get_option('datadir') / 'doc' / 'postgresql'
-dir_doc_html = dir_doc
+dir_doc_html = dir_doc / 'html'
 
 dir_locale = get_option('localedir')
 
diff --git a/doc/src/sgml/meson.build b/doc/src/sgml/meson.build
index e6fe124c7bc..f24acebb0fe 100644
--- a/doc/src/sgml/meson.build
+++ b/doc/src/sgml/meson.build
@@ -1,6 +1,7 @@
 # Copyright (c) 2022-2023, PostgreSQL Global Development Group
 
 docs = []
+installdocs = []
 alldocs = []
 doc_generated = []
 
@@ -120,8 +121,21 @@ if xsltproc_bin.found()
   )
   alldocs += html
 
-  # build multi-page html docs as part of docs target
+  install_doc_html = custom_target('install-html',
+    output: 'install-html', input: html,
+    command: [
+      python, install_files, '--prefix', dir_prefix,
+      '--install-dir-contents', dir_doc_html, '@INPUT@'],
+    depends: html,
+    build_always_stale: true,
+    build_by_default: false,
+  )
+  alias_target('install-doc-html', install_doc_html)
+
+  # build and install multi-page html docs as part of docs target
   docs += html
+  installdocs += install_doc_html
+
 
   htmlhelp = custom_target('htmlhelp',
     input: ['stylesheet-hh.xsl', postgres_full_xml],
@@ -208,6 +222,20 @@ if xsltproc_bin.found()
     build_by_default: false,
   )
   alldocs += man
+
+  install_doc_man = custom_target('install-man',
+    output: 'install-man', input: man,
+    command: [
+      python, install_files, '--prefix', dir_prefix,
+      '--install-dirs', dir_man, '@INPUT@'],
+    build_always_stale: true,
+    build_by_default: false,
+  )
+  alias_target('install-doc-man', install_doc_man)
+
+  # even though we don't want to build man pages as part of 'docs', we do want
+  # to install them as part of install-docs
+  installdocs += install_doc_man
 endif
 
 
@@ -262,10 +290,47 @@ if pandoc.found() and xsltproc_bin.found()
   alldocs += postgres_epub
 endif
 
+
+##
+## Experimental Texinfo targets
+##
+
+db2x_xsltproc = find_program('db2x_xsltproc', native: true, required: false)
+db2x_texixml = find_program('db2x_texixml', native: true, required: false)
+makeinfo = find_program('makeinfo', native: true, required: false)
+
+if db2x_texixml.found() and db2x_xsltproc.found() and makeinfo.found()
+    postgres_texixml = custom_target('postgres.texixml',
+      input: postgres_full_xml,
+      output: 'postgres.texixml',
+      command: [db2x_xsltproc, '-s', 'texi',
+                '-g', 'output-file=postgres',
+                '@INPUT@', '-o', '@OUTPUT@'],
+      build_by_default: false,
+    )
+    postgres_texi = custom_target('postgres.texi',
+      input: postgres_texixml,
+      output: 'postgres.texi',
+      command: [db2x_texixml, '--encoding=utf-8', '@INPUT@',
+                '--output-dir=@OUTDIR@'],
+      build_by_default: false,
+    )
+    postgres_info = custom_target('postgres.info',
+      input: postgres_texi,
+      output: 'postgres.info',
+      command: [makeinfo, '--enable-encoding', '--no-split', '--no-validate',
+                '@INPUT@', '-o', '@OUTPUT0@'],
+      build_by_default: false,
+    )
+    alldocs += postgres_info
+endif
+
+
 if docs.length() == 0
   run_target('docs', command: [missing, 'xsltproc'])
 else
   alias_target('docs', docs)
+  alias_target('install-docs', installdocs)
 endif
 
 if alldocs.length() == 0
-- 
2.38.0

>From efc9cc54de401cb7e20e02d4edbe85384ecf01a2 Mon Sep 17 00:00:00 2001
From: Andres Freund <and...@anarazel.de>
Date: Sun, 19 Mar 2023 11:17:54 -0700
Subject: [PATCH v2 4/8] meson: add install-{quiet, world} targets

---
 meson.build                                | 36 ++++++++++++++++++++++
 src/backend/po/meson.build                 |  2 +-
 src/bin/initdb/po/meson.build              |  2 +-
 src/bin/pg_amcheck/po/meson.build          |  2 +-
 src/bin/pg_archivecleanup/po/meson.build   |  2 +-
 src/bin/pg_basebackup/po/meson.build       |  2 +-
 src/bin/pg_checksums/po/meson.build        |  2 +-
 src/bin/pg_config/po/meson.build           |  2 +-
 src/bin/pg_controldata/po/meson.build      |  2 +-
 src/bin/pg_ctl/po/meson.build              |  2 +-
 src/bin/pg_dump/po/meson.build             |  2 +-
 src/bin/pg_resetwal/po/meson.build         |  2 +-
 src/bin/pg_rewind/po/meson.build           |  2 +-
 src/bin/pg_test_fsync/po/meson.build       |  2 +-
 src/bin/pg_test_timing/po/meson.build      |  2 +-
 src/bin/pg_upgrade/po/meson.build          |  2 +-
 src/bin/pg_verifybackup/po/meson.build     |  2 +-
 src/bin/pg_waldump/po/meson.build          |  2 +-
 src/bin/psql/po/meson.build                |  2 +-
 src/bin/scripts/po/meson.build             |  2 +-
 src/interfaces/libpq/po/meson.build        |  2 +-
 src/interfaces/libpq/test/meson.build      |  4 +--
 src/pl/plperl/po/meson.build               |  2 +-
 src/pl/plpgsql/src/po/meson.build          |  2 +-
 src/pl/plpython/po/meson.build             |  2 +-
 src/pl/tcl/po/meson.build                  |  2 +-
 src/interfaces/ecpg/ecpglib/po/meson.build |  2 +-
 src/interfaces/ecpg/preproc/po/meson.build |  2 +-
 28 files changed, 64 insertions(+), 28 deletions(-)

diff --git a/meson.build b/meson.build
index 33dd5b43ed5..bd1c1bf9f1d 100644
--- a/meson.build
+++ b/meson.build
@@ -2543,6 +2543,7 @@ bin_targets = []
 pl_targets = []
 contrib_targets = []
 testprep_targets = []
+nls_targets = []
 
 
 # Define the tests to distribute them to the correct test styles later
@@ -3185,6 +3186,7 @@ if meson.version().version_compare('>=0.57')
 endif
 
 
+
 ###############################################################
 # Pseudo targets
 ###############################################################
@@ -3195,6 +3197,40 @@ alias_target('pl', pl_targets)
 alias_target('contrib', contrib_targets)
 alias_target('testprep', testprep_targets)
 
+# i18n.gettext() doesn't return the dependencies before 0.60 - but the gettext
+# generation happens during install, so that's not a real issue.
+nls_mo_targets = []
+if libintl.found() and meson.version().version_compare('>=0.60')
+  # use range() to avoid the flattening of the list that forech() would do
+  foreach off : range(0, nls_targets.length())
+    # i18n.gettext() list containing 1) list of built .mo files 2) maintainer
+    # -pot target 3) maintainer -pot target
+    nls_mo_targets += nls_targets[off][0]
+  endforeach
+  alias_target('nls', nls_mo_targets)
+endif
+
+all_built = [
+  backend_targets,
+  bin_targets,
+  libpq_st,
+  pl_targets,
+  contrib_targets,
+  nls_mo_targets,
+  testprep_targets,
+  ecpg_targets,
+]
+
+install_quiet = custom_target('install-quiet',
+  output: 'install-quiet',
+  build_always_stale: true,
+  build_by_default: false,
+  command: meson_args + ['install', '--quiet', '--no-rebuild'],
+  depends: all_built,
+)
+
+alias_target('install-world', install_quiet, installdocs)
+
 
 
 ###############################################################
diff --git a/src/backend/po/meson.build b/src/backend/po/meson.build
index 772399b0bd8..b3cb083eb2c 100644
--- a/src/backend/po/meson.build
+++ b/src/backend/po/meson.build
@@ -1,3 +1,3 @@
 # Copyright (c) 2022-2023, PostgreSQL Global Development Group
 
-i18n.gettext('postgres-' + pg_version_major.to_string())
+nls_targets += [i18n.gettext('postgres-' + pg_version_major.to_string())]
diff --git a/src/bin/initdb/po/meson.build b/src/bin/initdb/po/meson.build
index 6506c5264ee..ad193984175 100644
--- a/src/bin/initdb/po/meson.build
+++ b/src/bin/initdb/po/meson.build
@@ -1,3 +1,3 @@
 # Copyright (c) 2022-2023, PostgreSQL Global Development Group
 
-i18n.gettext('initdb-' + pg_version_major.to_string())
+nls_targets += [i18n.gettext('initdb-' + pg_version_major.to_string())]
diff --git a/src/bin/pg_amcheck/po/meson.build b/src/bin/pg_amcheck/po/meson.build
index 9cb62eaaae2..618de4f4458 100644
--- a/src/bin/pg_amcheck/po/meson.build
+++ b/src/bin/pg_amcheck/po/meson.build
@@ -1,3 +1,3 @@
 # Copyright (c) 2022-2023, PostgreSQL Global Development Group
 
-i18n.gettext('pg_amcheck-' + pg_version_major.to_string())
+nls_targets += [i18n.gettext('pg_amcheck-' + pg_version_major.to_string())]
diff --git a/src/bin/pg_archivecleanup/po/meson.build b/src/bin/pg_archivecleanup/po/meson.build
index 79957fa2b98..c6f33edcad1 100644
--- a/src/bin/pg_archivecleanup/po/meson.build
+++ b/src/bin/pg_archivecleanup/po/meson.build
@@ -1,3 +1,3 @@
 # Copyright (c) 2022-2023, PostgreSQL Global Development Group
 
-i18n.gettext('pg_archivecleanup-' + pg_version_major.to_string())
+nls_targets += [i18n.gettext('pg_archivecleanup-' + pg_version_major.to_string())]
diff --git a/src/bin/pg_basebackup/po/meson.build b/src/bin/pg_basebackup/po/meson.build
index 437f7e0606f..2a39f5ffeba 100644
--- a/src/bin/pg_basebackup/po/meson.build
+++ b/src/bin/pg_basebackup/po/meson.build
@@ -1,3 +1,3 @@
 # Copyright (c) 2022-2023, PostgreSQL Global Development Group
 
-i18n.gettext('pg_basebackup-' + pg_version_major.to_string())
+nls_targets += [i18n.gettext('pg_basebackup-' + pg_version_major.to_string())]
diff --git a/src/bin/pg_checksums/po/meson.build b/src/bin/pg_checksums/po/meson.build
index 273f55d9012..97b20f263cf 100644
--- a/src/bin/pg_checksums/po/meson.build
+++ b/src/bin/pg_checksums/po/meson.build
@@ -1,3 +1,3 @@
 # Copyright (c) 2022-2023, PostgreSQL Global Development Group
 
-i18n.gettext('pg_checksums-' + pg_version_major.to_string())
+nls_targets += [i18n.gettext('pg_checksums-' + pg_version_major.to_string())]
diff --git a/src/bin/pg_config/po/meson.build b/src/bin/pg_config/po/meson.build
index 7e4629ffc4e..f515af816ea 100644
--- a/src/bin/pg_config/po/meson.build
+++ b/src/bin/pg_config/po/meson.build
@@ -1,3 +1,3 @@
 # Copyright (c) 2022-2023, PostgreSQL Global Development Group
 
-i18n.gettext('pg_config-' + pg_version_major.to_string())
+nls_targets += [i18n.gettext('pg_config-' + pg_version_major.to_string())]
diff --git a/src/bin/pg_controldata/po/meson.build b/src/bin/pg_controldata/po/meson.build
index 73a77568b6f..685f1c167a7 100644
--- a/src/bin/pg_controldata/po/meson.build
+++ b/src/bin/pg_controldata/po/meson.build
@@ -1,3 +1,3 @@
 # Copyright (c) 2022-2023, PostgreSQL Global Development Group
 
-i18n.gettext('pg_controldata-' + pg_version_major.to_string())
+nls_targets += [i18n.gettext('pg_controldata-' + pg_version_major.to_string())]
diff --git a/src/bin/pg_ctl/po/meson.build b/src/bin/pg_ctl/po/meson.build
index da7710090e0..3d35f7ad211 100644
--- a/src/bin/pg_ctl/po/meson.build
+++ b/src/bin/pg_ctl/po/meson.build
@@ -1,3 +1,3 @@
 # Copyright (c) 2022-2023, PostgreSQL Global Development Group
 
-i18n.gettext('pg_ctl-' + pg_version_major.to_string())
+nls_targets += [i18n.gettext('pg_ctl-' + pg_version_major.to_string())]
diff --git a/src/bin/pg_dump/po/meson.build b/src/bin/pg_dump/po/meson.build
index 3b627711d73..cc9d3680119 100644
--- a/src/bin/pg_dump/po/meson.build
+++ b/src/bin/pg_dump/po/meson.build
@@ -1,3 +1,3 @@
 # Copyright (c) 2022-2023, PostgreSQL Global Development Group
 
-i18n.gettext('pg_dump-' + pg_version_major.to_string())
+nls_targets += [i18n.gettext('pg_dump-' + pg_version_major.to_string())]
diff --git a/src/bin/pg_resetwal/po/meson.build b/src/bin/pg_resetwal/po/meson.build
index c82c6a4263f..fa75d287526 100644
--- a/src/bin/pg_resetwal/po/meson.build
+++ b/src/bin/pg_resetwal/po/meson.build
@@ -1,3 +1,3 @@
 # Copyright (c) 2022-2023, PostgreSQL Global Development Group
 
-i18n.gettext('pg_resetwal-' + pg_version_major.to_string())
+nls_targets += [i18n.gettext('pg_resetwal-' + pg_version_major.to_string())]
diff --git a/src/bin/pg_rewind/po/meson.build b/src/bin/pg_rewind/po/meson.build
index b0ccd16bbb9..bffe7debea9 100644
--- a/src/bin/pg_rewind/po/meson.build
+++ b/src/bin/pg_rewind/po/meson.build
@@ -1,3 +1,3 @@
 # Copyright (c) 2022-2023, PostgreSQL Global Development Group
 
-i18n.gettext('pg_rewind-' + pg_version_major.to_string())
+nls_targets += [i18n.gettext('pg_rewind-' + pg_version_major.to_string())]
diff --git a/src/bin/pg_test_fsync/po/meson.build b/src/bin/pg_test_fsync/po/meson.build
index b25a6d0f826..46d0ac587e2 100644
--- a/src/bin/pg_test_fsync/po/meson.build
+++ b/src/bin/pg_test_fsync/po/meson.build
@@ -1,3 +1,3 @@
 # Copyright (c) 2022-2023, PostgreSQL Global Development Group
 
-i18n.gettext('pg_test_fsync-' + pg_version_major.to_string())
+nls_targets += [i18n.gettext('pg_test_fsync-' + pg_version_major.to_string())]
diff --git a/src/bin/pg_test_timing/po/meson.build b/src/bin/pg_test_timing/po/meson.build
index 918225a1cf5..7bc84d5c7ff 100644
--- a/src/bin/pg_test_timing/po/meson.build
+++ b/src/bin/pg_test_timing/po/meson.build
@@ -1,3 +1,3 @@
 # Copyright (c) 2022-2023, PostgreSQL Global Development Group
 
-i18n.gettext('pg_test_timing-' + pg_version_major.to_string())
+nls_targets += [i18n.gettext('pg_test_timing-' + pg_version_major.to_string())]
diff --git a/src/bin/pg_upgrade/po/meson.build b/src/bin/pg_upgrade/po/meson.build
index b4ba67b1c5e..8531c3b31ef 100644
--- a/src/bin/pg_upgrade/po/meson.build
+++ b/src/bin/pg_upgrade/po/meson.build
@@ -1,3 +1,3 @@
 # Copyright (c) 2022-2023, PostgreSQL Global Development Group
 
-i18n.gettext('pg_upgrade-' + pg_version_major.to_string())
+nls_targets += [i18n.gettext('pg_upgrade-' + pg_version_major.to_string())]
diff --git a/src/bin/pg_verifybackup/po/meson.build b/src/bin/pg_verifybackup/po/meson.build
index 092b8a95f31..181cf640e71 100644
--- a/src/bin/pg_verifybackup/po/meson.build
+++ b/src/bin/pg_verifybackup/po/meson.build
@@ -1,3 +1,3 @@
 # Copyright (c) 2022-2023, PostgreSQL Global Development Group
 
-i18n.gettext('pg_verifybackup-' + pg_version_major.to_string())
+nls_targets += [i18n.gettext('pg_verifybackup-' + pg_version_major.to_string())]
diff --git a/src/bin/pg_waldump/po/meson.build b/src/bin/pg_waldump/po/meson.build
index 076dbcafb42..c4188032d71 100644
--- a/src/bin/pg_waldump/po/meson.build
+++ b/src/bin/pg_waldump/po/meson.build
@@ -1,3 +1,3 @@
 # Copyright (c) 2022-2023, PostgreSQL Global Development Group
 
-i18n.gettext('pg_waldump-' + pg_version_major.to_string())
+nls_targets += [i18n.gettext('pg_waldump-' + pg_version_major.to_string())]
diff --git a/src/bin/psql/po/meson.build b/src/bin/psql/po/meson.build
index da257154d4c..103ed93a789 100644
--- a/src/bin/psql/po/meson.build
+++ b/src/bin/psql/po/meson.build
@@ -1,3 +1,3 @@
 # Copyright (c) 2022-2023, PostgreSQL Global Development Group
 
-i18n.gettext('psql-' + pg_version_major.to_string())
+nls_targets += [i18n.gettext('psql-' + pg_version_major.to_string())]
diff --git a/src/bin/scripts/po/meson.build b/src/bin/scripts/po/meson.build
index a28ec9ed049..00a9f208acf 100644
--- a/src/bin/scripts/po/meson.build
+++ b/src/bin/scripts/po/meson.build
@@ -1,3 +1,3 @@
 # Copyright (c) 2022-2023, PostgreSQL Global Development Group
 
-i18n.gettext('pgscripts-' + pg_version_major.to_string())
+nls_targets += [i18n.gettext('pgscripts-' + pg_version_major.to_string())]
diff --git a/src/interfaces/libpq/po/meson.build b/src/interfaces/libpq/po/meson.build
index 5489b23b795..a7a1df87ae3 100644
--- a/src/interfaces/libpq/po/meson.build
+++ b/src/interfaces/libpq/po/meson.build
@@ -1,3 +1,3 @@
 # Copyright (c) 2022-2023, PostgreSQL Global Development Group
 
-i18n.gettext('libpq' + '5' + '-' + pg_version_major.to_string())
+nls_targets += [i18n.gettext('libpq' + '5' + '-' + pg_version_major.to_string())]
diff --git a/src/interfaces/libpq/test/meson.build b/src/interfaces/libpq/test/meson.build
index b2a4b06fd23..d56b63e1186 100644
--- a/src/interfaces/libpq/test/meson.build
+++ b/src/interfaces/libpq/test/meson.build
@@ -10,7 +10,7 @@ if host_system == 'windows'
     '--FILEDESC', 'libpq test program',])
 endif
 
-executable('libpq_uri_regress',
+testprep_targets += executable('libpq_uri_regress',
   libpq_uri_regress_sources,
   dependencies: [frontend_code, libpq],
   kwargs: default_bin_args + {
@@ -29,7 +29,7 @@ if host_system == 'windows'
     '--FILEDESC', 'libpq test program',])
 endif
 
-executable('libpq_testclient',
+testprep_targets += executable('libpq_testclient',
   libpq_testclient_sources,
   dependencies: [frontend_code, libpq],
   kwargs: default_bin_args + {
diff --git a/src/pl/plperl/po/meson.build b/src/pl/plperl/po/meson.build
index 2c3cd190cd9..f1c8e7d00a1 100644
--- a/src/pl/plperl/po/meson.build
+++ b/src/pl/plperl/po/meson.build
@@ -1,3 +1,3 @@
 # Copyright (c) 2022-2023, PostgreSQL Global Development Group
 
-i18n.gettext('plperl-' + pg_version_major.to_string())
+nls_targets += [i18n.gettext('plperl-' + pg_version_major.to_string())]
diff --git a/src/pl/plpgsql/src/po/meson.build b/src/pl/plpgsql/src/po/meson.build
index 1fa97d6ab50..aad875948b6 100644
--- a/src/pl/plpgsql/src/po/meson.build
+++ b/src/pl/plpgsql/src/po/meson.build
@@ -1,3 +1,3 @@
 # Copyright (c) 2022-2023, PostgreSQL Global Development Group
 
-i18n.gettext('plpgsql-' + pg_version_major.to_string())
+nls_targets += [i18n.gettext('plpgsql-' + pg_version_major.to_string())]
diff --git a/src/pl/plpython/po/meson.build b/src/pl/plpython/po/meson.build
index e5457069b47..ddaa1913b84 100644
--- a/src/pl/plpython/po/meson.build
+++ b/src/pl/plpython/po/meson.build
@@ -1,3 +1,3 @@
 # Copyright (c) 2022-2023, PostgreSQL Global Development Group
 
-i18n.gettext('plpython-' + pg_version_major.to_string())
+nls_targets += [i18n.gettext('plpython-' + pg_version_major.to_string())]
diff --git a/src/pl/tcl/po/meson.build b/src/pl/tcl/po/meson.build
index 3e7d3287f84..9e5c8e95f15 100644
--- a/src/pl/tcl/po/meson.build
+++ b/src/pl/tcl/po/meson.build
@@ -1,3 +1,3 @@
 # Copyright (c) 2022-2023, PostgreSQL Global Development Group
 
-i18n.gettext('pltcl-' + pg_version_major.to_string())
+nls_targets += [i18n.gettext('pltcl-' + pg_version_major.to_string())]
diff --git a/src/interfaces/ecpg/ecpglib/po/meson.build b/src/interfaces/ecpg/ecpglib/po/meson.build
index 95e748d9fa5..39fcc93bfcc 100644
--- a/src/interfaces/ecpg/ecpglib/po/meson.build
+++ b/src/interfaces/ecpg/ecpglib/po/meson.build
@@ -1,3 +1,3 @@
 # Copyright (c) 2022-2023, PostgreSQL Global Development Group
 
-i18n.gettext('ecpglib' + '6' + '-' + pg_version_major.to_string())
+nls_targets += [i18n.gettext('ecpglib' + '6' + '-' + pg_version_major.to_string())]
diff --git a/src/interfaces/ecpg/preproc/po/meson.build b/src/interfaces/ecpg/preproc/po/meson.build
index 1b2ff116547..43f825b88bb 100644
--- a/src/interfaces/ecpg/preproc/po/meson.build
+++ b/src/interfaces/ecpg/preproc/po/meson.build
@@ -1,3 +1,3 @@
 # Copyright (c) 2022-2023, PostgreSQL Global Development Group
 
-i18n.gettext('ecpg-' + pg_version_major.to_string())
+nls_targets += [i18n.gettext('ecpg-' + pg_version_major.to_string())]
-- 
2.38.0

>From f7f88de6726a5663d90da5a454c9b3a1ba037fd1 Mon Sep 17 00:00:00 2001
From: Andres Freund <and...@anarazel.de>
Date: Wed, 15 Mar 2023 16:45:14 -0700
Subject: [PATCH v2 5/8] docs: html: copy images to output as part of xslt
 build

---
 doc/src/sgml/Makefile              |  2 --
 doc/src/sgml/stylesheet-common.xsl | 22 ++++++++++++++++++++++
 doc/src/sgml/stylesheet-hh.xsl     |  6 ++++++
 doc/src/sgml/stylesheet.xsl        |  7 ++++++-
 4 files changed, 34 insertions(+), 3 deletions(-)

diff --git a/doc/src/sgml/Makefile b/doc/src/sgml/Makefile
index b96c7cbf223..1b098f983ec 100644
--- a/doc/src/sgml/Makefile
+++ b/doc/src/sgml/Makefile
@@ -144,7 +144,6 @@ html: html-stamp
 
 html-stamp: stylesheet.xsl postgres-full.xml $(ALL_IMAGES)
 	$(XSLTPROC) $(XMLINCLUDE) $(XSLTPROCFLAGS) $(XSLTPROC_HTML_FLAGS) $(wordlist 1,2,$^)
-	cp $(ALL_IMAGES) html/
 	cp $(srcdir)/stylesheet.css html/
 	touch $@
 
@@ -152,7 +151,6 @@ htmlhelp: htmlhelp-stamp
 
 htmlhelp-stamp: stylesheet-hh.xsl postgres-full.xml $(ALL_IMAGES)
 	$(XSLTPROC) $(XMLINCLUDE) $(XSLTPROCFLAGS) $(wordlist 1,2,$^)
-	cp $(ALL_IMAGES) htmlhelp/
 	cp $(srcdir)/stylesheet.css htmlhelp/
 	touch $@
 
diff --git a/doc/src/sgml/stylesheet-common.xsl b/doc/src/sgml/stylesheet-common.xsl
index 761484c7fef..d2928f86eb7 100644
--- a/doc/src/sgml/stylesheet-common.xsl
+++ b/doc/src/sgml/stylesheet-common.xsl
@@ -101,4 +101,26 @@
   <xsl:apply-templates select="." mode="xref"/>
 </xsl:template>
 
+
+<!--
+  Support for copying images to the output directory, so the output is self
+  contained.
+-->
+<xsl:template name="write-image">
+ <xsl:variable name="input_filename">
+   <xsl:value-of select="imagedata/@fileref"/>
+ </xsl:variable>
+
+ <!-- references images directly, without images/ -->
+ <xsl:variable name="output_filename">
+   <xsl:value-of select="concat($chunk.base.dir, substring-after($input_filename, '/'))"/>
+ </xsl:variable>
+
+ <xsl:call-template name="write.chunk">
+  <xsl:with-param name="filename" select="$output_filename"/>
+  <xsl:with-param name="content" select="document($input_filename)"/>
+ </xsl:call-template>
+</xsl:template>
+
+
 </xsl:stylesheet>
diff --git a/doc/src/sgml/stylesheet-hh.xsl b/doc/src/sgml/stylesheet-hh.xsl
index 6f4b706dac6..568ccf36d2a 100644
--- a/doc/src/sgml/stylesheet-hh.xsl
+++ b/doc/src/sgml/stylesheet-hh.xsl
@@ -39,6 +39,12 @@
 </xsl:template>
 
 
+<xsl:template match="imageobject">
+  <xsl:call-template name="write-image"/>
+  <!-- copy images to the output directory, so the output is self contained -->
+  <xsl:apply-templates select="imagedata"/>
+</xsl:template>
+
 <!-- strip directory name from image filerefs -->
 <xsl:template match="imagedata/@fileref">
  <xsl:value-of select="substring-after(., '/')"/>
diff --git a/doc/src/sgml/stylesheet.xsl b/doc/src/sgml/stylesheet.xsl
index b6141303abd..f9163e7d946 100644
--- a/doc/src/sgml/stylesheet.xsl
+++ b/doc/src/sgml/stylesheet.xsl
@@ -29,7 +29,12 @@
 </xsl:param>
 
 
-<!-- strip directory name from image filerefs -->
+<xsl:template match="imageobject">
+  <xsl:call-template name="write-image"/>
+  <!-- copy images to the output directory, so the output is self contained -->
+  <xsl:apply-templates select="imagedata"/>
+</xsl:template>
+
 <xsl:template match="imagedata/@fileref">
  <xsl:value-of select="substring-after(., '/')"/>
 </xsl:template>
-- 
2.38.0

>From 481cf9704196db7f6c05054943d184bfea303466 Mon Sep 17 00:00:00 2001
From: Andres Freund <and...@anarazel.de>
Date: Wed, 15 Mar 2023 20:49:47 -0700
Subject: [PATCH v2 6/8] wip: docs: copy or inline css

---
 doc/src/sgml/Makefile                    |  4 +---
 doc/src/sgml/meson.build                 |  2 +-
 doc/src/sgml/stylesheet-common.xsl       | 20 ++++++++++++++++++++
 doc/src/sgml/stylesheet-hh.xsl           | 10 +++++++++-
 doc/src/sgml/stylesheet-html-nochunk.xsl | 20 ++++++++++++++++++++
 doc/src/sgml/stylesheet.xsl              | 15 ++++++---------
 6 files changed, 57 insertions(+), 14 deletions(-)

diff --git a/doc/src/sgml/Makefile b/doc/src/sgml/Makefile
index 1b098f983ec..3f971f6eb33 100644
--- a/doc/src/sgml/Makefile
+++ b/doc/src/sgml/Makefile
@@ -53,7 +53,7 @@ else
 XSLTPROC = $(missing) xsltproc
 endif
 
-override XSLTPROCFLAGS += --stringparam pg.version '$(VERSION)'
+override XSLTPROCFLAGS += --xincludestyle --stringparam pg.version '$(VERSION)'
 
 
 GENERATED_SGML = version.sgml \
@@ -144,14 +144,12 @@ html: html-stamp
 
 html-stamp: stylesheet.xsl postgres-full.xml $(ALL_IMAGES)
 	$(XSLTPROC) $(XMLINCLUDE) $(XSLTPROCFLAGS) $(XSLTPROC_HTML_FLAGS) $(wordlist 1,2,$^)
-	cp $(srcdir)/stylesheet.css html/
 	touch $@
 
 htmlhelp: htmlhelp-stamp
 
 htmlhelp-stamp: stylesheet-hh.xsl postgres-full.xml $(ALL_IMAGES)
 	$(XSLTPROC) $(XMLINCLUDE) $(XSLTPROCFLAGS) $(wordlist 1,2,$^)
-	cp $(srcdir)/stylesheet.css htmlhelp/
 	touch $@
 
 # single-page HTML
diff --git a/doc/src/sgml/meson.build b/doc/src/sgml/meson.build
index f24acebb0fe..bbe285b29bb 100644
--- a/doc/src/sgml/meson.build
+++ b/doc/src/sgml/meson.build
@@ -104,7 +104,7 @@ if xsltproc_bin.found()
   xsltproc_flags = [
     '--nonet',
     '--stringparam', 'pg.version', pg_version,
-    '--param', 'website.stylesheet', '1'
+    '--xincludestyle',
   ]
 
   xsltproc = xmltools_wrapper + [
diff --git a/doc/src/sgml/stylesheet-common.xsl b/doc/src/sgml/stylesheet-common.xsl
index d2928f86eb7..25d05b9e5f4 100644
--- a/doc/src/sgml/stylesheet-common.xsl
+++ b/doc/src/sgml/stylesheet-common.xsl
@@ -41,6 +41,8 @@
 <xsl:param name="variablelist.term.break.after">1</xsl:param>
 <xsl:param name="variablelist.term.separator"></xsl:param>
 <xsl:param name="xref.with.number.and.title" select="0"></xsl:param>
+<!-- currently htmlhelp and other html have no common stylesheet -->
+<xsl:param name="website.stylesheet" select="0"/>
 
 
 <!-- Change display of some elements -->
@@ -122,5 +124,23 @@
  </xsl:call-template>
 </xsl:template>
 
+<xsl:template name="stylesheet-reference">
+  <xsl:choose>
+    <xsl:when test="$website.stylesheet = 0">stylesheet.css
+    <xsl:variable name="styleout" select="concat($base.dir, 'stylesheet.css')"/>
+    <xsl:call-template name="write.chunk">
+      <xsl:with-param name="filename" select="$styleout"/>
+      <xsl:with-param name="omit-xml-declaration" select="'yes'"/>
+      <xsl:with-param name="content">
+        <!-- xinclude is only processed in toplevel stylesheet -->
+        <xsl:call-template name="stylesheet-contents"/>
+      </xsl:with-param>
+    </xsl:call-template>
+    </xsl:when>
+    <xsl:otherwise>
+      https://www.postgresql.org/media/css/docs-complete.css
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
 
 </xsl:stylesheet>
diff --git a/doc/src/sgml/stylesheet-hh.xsl b/doc/src/sgml/stylesheet-hh.xsl
index 568ccf36d2a..6f6c6c64626 100644
--- a/doc/src/sgml/stylesheet-hh.xsl
+++ b/doc/src/sgml/stylesheet-hh.xsl
@@ -1,5 +1,6 @@
 <?xml version='1.0'?>
 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
+                xmlns:xi="http://www.w3.org/2001/XInclude";
                 version='1.0'>
 
 <xsl:import href="http://docbook.sourceforge.net/release/xsl/current/htmlhelp/htmlhelp.xsl"/>
@@ -9,7 +10,6 @@
 <xsl:param name="htmlhelp.use.hhk" select="'1'"/>
 
 <xsl:param name="base.dir" select="'htmlhelp/'"></xsl:param>
-<xsl:param name="html.stylesheet" select="'stylesheet.css'"></xsl:param>
 <xsl:param name="use.id.as.filename" select="'1'"></xsl:param>
 <xsl:param name="manifest.in.base.dir" select="1"/>
 <xsl:param name="make.valid.html" select="1"></xsl:param>
@@ -19,6 +19,14 @@
 <xsl:param name="chunker.output.indent" select="'yes'"/>
 <xsl:param name="chunk.quietly" select="1"></xsl:param>
 
+<xsl:param name="html.stylesheet">
+  <xsl:call-template name="stylesheet-reference"/>
+</xsl:param>
+
+<xsl:template name="stylesheet-contents">
+  <xi:include href="stylesheet.css" parse="text"/>
+</xsl:template>
+
 
 <!-- Change display of some elements -->
 
diff --git a/doc/src/sgml/stylesheet-html-nochunk.xsl b/doc/src/sgml/stylesheet-html-nochunk.xsl
index 8167127b93a..560f6a0b0a7 100644
--- a/doc/src/sgml/stylesheet-html-nochunk.xsl
+++ b/doc/src/sgml/stylesheet-html-nochunk.xsl
@@ -1,5 +1,7 @@
 <?xml version='1.0'?>
 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
+                xmlns:xi="http://www.w3.org/2001/XInclude";
+                xmlns="http://www.w3.org/1999/xhtml";
                 version='1.0'>
 
 <xsl:import href="http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl"/>
@@ -7,6 +9,24 @@
 <xsl:include href="stylesheet-html-common.xsl" />
 <xsl:include href="stylesheet-speedup-xhtml.xsl" />
 
+
+<xsl:param name="generate.css.header" select="1"/>
+<xsl:template name="generate.css.headers">
+  <xsl:choose>
+    <!-- inline css style sheet -->
+    <xsl:when test="$website.stylesheet = 0">
+      <style type="text/css">
+        <xi:include href="stylesheet.css" parse="text"/>
+      </style>
+    </xsl:when>
+    <!-- link to website -->
+    <xsl:otherwise>
+      <link rel="stylesheet" type="text/css" href="https://www.postgresql.org/media/css/docs-complete.css"/>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+
 <!-- embed SVG images into output file -->
 <xsl:template match="imagedata[@format='SVG']">
   <xsl:variable name="filename">
diff --git a/doc/src/sgml/stylesheet.xsl b/doc/src/sgml/stylesheet.xsl
index f9163e7d946..c551b9cd809 100644
--- a/doc/src/sgml/stylesheet.xsl
+++ b/doc/src/sgml/stylesheet.xsl
@@ -1,7 +1,8 @@
 <?xml version='1.0'?>
 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
                 version='1.0'
-                xmlns="http://www.w3.org/1999/xhtml";>
+                xmlns="http://www.w3.org/1999/xhtml";
+                xmlns:xi="http://www.w3.org/2001/XInclude";>
 
 <xsl:import href="http://docbook.sourceforge.net/release/xsl/current/xhtml/chunk.xsl"/>
 <xsl:include href="stylesheet-common.xsl" />
@@ -17,17 +18,13 @@
 <xsl:param name="chunk.quietly" select="1"></xsl:param>
 <xsl:param name="admon.style"></xsl:param>  <!-- handled by CSS stylesheet -->
 
-<xsl:param name="website.stylesheet" select="0"/>
-
 <xsl:param name="html.stylesheet">
-  <xsl:choose>
-    <xsl:when test="$website.stylesheet = 0">stylesheet.css</xsl:when>
-    <xsl:otherwise>
-      https://www.postgresql.org/media/css/docs-complete.css
-    </xsl:otherwise>
-  </xsl:choose>
+  <xsl:call-template name="stylesheet-reference"/>
 </xsl:param>
 
+<xsl:template name="stylesheet-contents">
+  <xi:include href="stylesheet.css" parse="text"/>
+</xsl:template>
 
 <xsl:template match="imageobject">
   <xsl:call-template name="write-image"/>
-- 
2.38.0

>From 8d4cc69ea39304decc78d687fd3b97a9b1907bf9 Mon Sep 17 00:00:00 2001
From: Andres Freund <and...@anarazel.de>
Date: Sun, 19 Mar 2023 11:11:37 -0700
Subject: [PATCH v2 7/8] docs: speed up docs build by special-casing the
 gentext.template

---
 doc/src/sgml/stylesheet-speedup-common.xsl | 79 ++++++++++++++++++++++
 1 file changed, 79 insertions(+)

diff --git a/doc/src/sgml/stylesheet-speedup-common.xsl b/doc/src/sgml/stylesheet-speedup-common.xsl
index e3fb582a1cc..5266ff587b9 100644
--- a/doc/src/sgml/stylesheet-speedup-common.xsl
+++ b/doc/src/sgml/stylesheet-speedup-common.xsl
@@ -96,5 +96,84 @@
 <!-- Just hardcode the language for the whole document, to make it faster. -->
 
 <xsl:template name="l10n.language">en</xsl:template>
+<xsl:param name='pg.l10n.xml' select="document('file:///usr/share/xml/docbook/stylesheet/docbook-xsl/common/en.xml')[1]"/>
+
+<xsl:template name="gentext.template.recurse">
+  <xsl:param name="context"/>
+  <xsl:param name="name"/>
+  <xsl:param name="origname"/>
+  <xsl:param name="verbose"/>
+
+
+  <xsl:choose>
+    <xsl:when test="contains($name, '/')">
+      <xsl:call-template name="gentext.template.recurse">
+        <xsl:with-param name="context" select="$context"/>
+        <xsl:with-param name="name" select="substring-after($name, '/')"/>
+        <xsl:with-param name="origname" select="$origname"/>
+        <xsl:with-param name="verbose" select="$verbose"/>
+      </xsl:call-template>
+    </xsl:when>
+    <xsl:otherwise>
+
+      <!-- FIXME: should find a way to avoid the concat and [1] here -->
+      <xsl:variable name="template.node"
+                    select="key('l10n-template', concat($context, '#', $name))[1]"/>
+
+      <xsl:choose>
+        <xsl:when test="$template.node/@text">
+          <xsl:value-of select="$template.node/@text"/>
+        </xsl:when>
+        <xsl:when test="$verbose = 0">
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:message>
+            <xsl:text>No template for "</xsl:text>
+            <xsl:value-of select="$origname"/>
+            <xsl:text>" (or any of its leaves) exists in the context named "</xsl:text>
+            <xsl:value-of select="$context"/>
+            <xsl:text>" in the "</xsl:text>
+            <xsl:text>" en localization.</xsl:text>
+          </xsl:message>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
+
+
+<xsl:template name="gentext.template">
+  <xsl:param name="context" select="'default'"/>
+  <xsl:param name="name" select="'default'"/>
+  <xsl:param name="origname" select="$name"/>
+  <xsl:param name="lang" select="'en'"/>
+  <xsl:param name="verbose" select="1"/>
+
+  <!-- FIXME: unnecessary recursion for leading -->
+  <xsl:for-each select="$pg.l10n.xml">
+    <xsl:variable name="context.node"
+                  select="key('l10n-context', $context)[1]"/>
+
+    <xsl:if test="count($context.node) = 0
+                  and $verbose != 0">
+      <xsl:message>
+        <xsl:text>No context named "</xsl:text>
+        <xsl:value-of select="$context"/>
+        <xsl:text>" exists in the "</xsl:text>
+        <xsl:value-of select="$lang"/>
+        <xsl:text>" localization.</xsl:text>
+      </xsl:message>
+    </xsl:if>
+
+    <xsl:for-each select="$context.node">
+      <xsl:call-template name="gentext.template.recurse">
+        <xsl:with-param name="context" select="$context"/>
+        <xsl:with-param name="name" select="$name"/>
+        <xsl:with-param name="origname" select="$origname"/>
+        <xsl:with-param name="verbose" select="$verbose"/>
+      </xsl:call-template>
+    </xsl:for-each>
+  </xsl:for-each>
+</xsl:template>
 
 </xsl:stylesheet>
-- 
2.38.0

>From df0548082b821e90b783131f37053326e28cfd06 Mon Sep 17 00:00:00 2001
From: Andres Freund <and...@anarazel.de>
Date: Sun, 19 Mar 2023 19:29:41 -0700
Subject: [PATCH v2 8/8] VERY WIP: parallel doc generation

---
 doc/src/sgml/meson.build          | 17 +++++++++++
 doc/src/sgml/postgres.sgml        |  2 +-
 doc/src/sgml/stylesheet.xsl       | 51 ++++++++++++++++++++++++++++++-
 doc/src/sgml/xmltools_dep_wrapper |  5 +++
 4 files changed, 73 insertions(+), 2 deletions(-)

diff --git a/doc/src/sgml/meson.build b/doc/src/sgml/meson.build
index bbe285b29bb..1adae3f7ee5 100644
--- a/doc/src/sgml/meson.build
+++ b/doc/src/sgml/meson.build
@@ -121,6 +121,23 @@ if xsltproc_bin.found()
   )
   alldocs += html
 
+  parts = ['bookinfo', 'preface', 'tutorial', 'sql', 'admin', 'client-interfaces', 'server-programming', 'reference', 'internals', 'appendixes', 'biblio', 'bookindex']
+  html_parts = []
+  foreach part : parts
+      html_parts += custom_target('html-@0@'.format(part),
+      input: ['stylesheet.xsl', postgres_full_xml],
+      output: 'html-stamp-@0@'.format(part),
+      depfile: 'html.d',
+      depends: doc_generated,
+      command: [
+        xmltools_wrapper, '--tool', xsltproc_bin, '--stamp', '@OUTPUT0@', '--',
+        '-o', '@OUTDIR@/', xsltproc_flags, '--stringparam', 'rootid', part, '@INPUT@',
+      ],
+      build_by_default: false,
+    )
+  endforeach
+  alias_target('html-parts', html_parts)
+
   install_doc_html = custom_target('install-html',
     output: 'install-html', input: html,
     command: [
diff --git a/doc/src/sgml/postgres.sgml b/doc/src/sgml/postgres.sgml
index 2e271862fc1..a169fd6f30a 100644
--- a/doc/src/sgml/postgres.sgml
+++ b/doc/src/sgml/postgres.sgml
@@ -23,7 +23,7 @@ break is not needed in a wider output rendering.
 <book id="postgres">
  <title>PostgreSQL &version; Documentation</title>
 
- <bookinfo>
+ <bookinfo id="bookinfo">
   <corpauthor>The PostgreSQL Global Development Group</corpauthor>
   <productname>PostgreSQL</productname>
   <productnumber>&version;</productnumber>
diff --git a/doc/src/sgml/stylesheet.xsl b/doc/src/sgml/stylesheet.xsl
index c551b9cd809..32bceba2d54 100644
--- a/doc/src/sgml/stylesheet.xsl
+++ b/doc/src/sgml/stylesheet.xsl
@@ -15,7 +15,7 @@
 <xsl:param name="use.id.as.filename" select="'1'"></xsl:param>
 <xsl:param name="generate.legalnotice.link" select="1"></xsl:param>
 <xsl:param name="chunk.first.sections" select="1"/>
-<xsl:param name="chunk.quietly" select="1"></xsl:param>
+<xsl:param name="chunk.quietly" select="0"></xsl:param>
 <xsl:param name="admon.style"></xsl:param>  <!-- handled by CSS stylesheet -->
 
 <xsl:param name="html.stylesheet">
@@ -36,6 +36,55 @@
  <xsl:value-of select="substring-after(., '/')"/>
 </xsl:template>
 
+<!-- Emit index.html and legalnotice.html -->
+<xsl:template name="pg.write.bookinfo">
+   <xsl:for-each select="/book">
+     <xsl:call-template name="process-chunk">
+       <xsl:with-param name="prev" select="/dontexist"/>
+       <xsl:with-param name="next" select="preface"/>
+       <xsl:with-param name="content">
+
+         <div>
+           <xsl:apply-templates select="." mode="common.html.attributes"/>
+           <xsl:call-template name="id.attribute">
+             <xsl:with-param name="conditional" select="0"/>
+           </xsl:call-template>
+
+           <xsl:call-template name="book.titlepage"/>
+
+           <xsl:apply-templates select="dedication" mode="dedication"/>
+           <xsl:apply-templates select="acknowledgements" mode="acknowledgements"/>
+
+           <xsl:variable name="toc.params">
+             <xsl:call-template name="find.path.params">
+               <xsl:with-param name="table" select="normalize-space($generate.toc)"/>
+             </xsl:call-template>
+           </xsl:variable>
+
+           <xsl:call-template name="make.lots">
+             <xsl:with-param name="toc.params" select="$toc.params"/>
+             <xsl:with-param name="toc">
+               <xsl:call-template name="division.toc">
+                 <xsl:with-param name="toc.title.p" select="contains($toc.params, 'title')"/>
+               </xsl:call-template>
+             </xsl:with-param>
+           </xsl:call-template>
+         </div>
+       </xsl:with-param>
+     </xsl:call-template>
+   </xsl:for-each>
+</xsl:template>
+
+<xsl:template match="/book/bookinfo" mode="process.root" priority="2">
+  <xsl:choose>
+    <xsl:when test="$rootid = 'bookinfo'">
+      <xsl:call-template name="pg.write.bookinfo"/>
+    </xsl:when>
+    <xsl:otherwise>
+      <xsl:apply-imports/>
+    </xsl:otherwise>
+  </xsl:choose>
+</xsl:template>
 
 <!--
 Customization of header
diff --git a/doc/src/sgml/xmltools_dep_wrapper b/doc/src/sgml/xmltools_dep_wrapper
index dd96f784268..a5f5981dcee 100644
--- a/doc/src/sgml/xmltools_dep_wrapper
+++ b/doc/src/sgml/xmltools_dep_wrapper
@@ -14,6 +14,7 @@ parser = argparse.ArgumentParser(
 parser.add_argument('--targetname', type=str, required=False, nargs='+')
 parser.add_argument('--depfile', type=str, required=False)
 parser.add_argument('--tool', type=str, required=True)
+parser.add_argument('--stamp', type=str, required=False, default=None)
 parser.add_argument('flags', nargs='*')
 
 args = parser.parse_args()
@@ -51,4 +52,8 @@ else:
     command = [args.tool] + args.flags
     res = subprocess.run(command)
 
+if args.stamp is not None:
+    with open(args.stamp, "w") as f:
+        pass
+
 exit(res.returncode)
-- 
2.38.0

Reply via email to