From 1939bdcfbfeaaf053b6a8e8a7e9f5c257b38fdfb Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Mon, 12 Sep 2022 17:05:05 -0700
Subject: [PATCH v13 08/20] meson: Add meson based buildsystem

Author: Andres Freund <andres@anarazel.de>
Author: Nazir Bilal Yavuz <byavuz81@gmail.com>
Author: Peter Eisentraut <peter@eisentraut.org>
Author: Thomas Munro <thomas.munro@gmail.com>
Author: John Naylor <john.naylor@enterprisedb.com>
Author: Stone Tickle <lattis@mochiro.moe>
---
 src/include/catalog/meson.build               |  142 +
 src/include/meson.build                       |  173 +
 src/include/nodes/meson.build                 |   58 +
 src/include/pg_config_ext.h.meson             |    7 +
 src/include/storage/meson.build               |   19 +
 src/include/utils/meson.build                 |   57 +
 src/common/meson.build                        |  174 +
 src/common/unicode/meson.build                |  106 +
 src/port/meson.build                          |  184 +
 config/meson.build                            |    4 +
 src/backend/access/brin/meson.build           |   12 +
 src/backend/access/common/meson.build         |   18 +
 src/backend/access/gin/meson.build            |   17 +
 src/backend/access/gist/meson.build           |   13 +
 src/backend/access/hash/meson.build           |   12 +
 src/backend/access/heap/meson.build           |   11 +
 src/backend/access/index/meson.build          |    6 +
 src/backend/access/meson.build                |   13 +
 src/backend/access/nbtree/meson.build         |   13 +
 src/backend/access/rmgrdesc/meson.build       |   26 +
 src/backend/access/spgist/meson.build         |   13 +
 src/backend/access/table/meson.build          |    6 +
 src/backend/access/tablesample/meson.build    |    5 +
 src/backend/access/transam/meson.build        |   31 +
 src/backend/backup/meson.build                |   13 +
 src/backend/bootstrap/meson.build             |   28 +
 src/backend/catalog/meson.build               |   44 +
 src/backend/commands/meson.build              |   51 +
 src/backend/executor/meson.build              |   67 +
 src/backend/foreign/meson.build               |    3 +
 src/backend/jit/llvm/meson.build              |   73 +
 src/backend/jit/meson.build                   |    3 +
 src/backend/lib/meson.build                   |   12 +
 src/backend/libpq/meson.build                 |   32 +
 src/backend/main/meson.build                  |    2 +
 src/backend/meson.build                       |  190 ++
 src/backend/nodes/meson.build                 |   29 +
 src/backend/optimizer/geqo/meson.build        |   17 +
 src/backend/optimizer/meson.build             |    5 +
 src/backend/optimizer/path/meson.build        |   11 +
 src/backend/optimizer/plan/meson.build        |   10 +
 src/backend/optimizer/prep/meson.build        |    7 +
 src/backend/optimizer/util/meson.build        |   16 +
 src/backend/parser/meson.build                |   48 +
 src/backend/partitioning/meson.build          |    5 +
 src/backend/po/meson.build                    |    1 +
 src/backend/port/meson.build                  |   31 +
 src/backend/port/win32/meson.build            |    6 +
 src/backend/postmaster/meson.build            |   15 +
 src/backend/regex/meson.build                 |    8 +
 .../replication/libpqwalreceiver/meson.build  |   13 +
 src/backend/replication/logical/meson.build   |   14 +
 src/backend/replication/meson.build           |   51 +
 src/backend/replication/pgoutput/meson.build  |   11 +
 src/backend/rewrite/meson.build               |    9 +
 src/backend/snowball/meson.build              |   88 +
 src/backend/statistics/meson.build            |    6 +
 src/backend/storage/buffer/meson.build        |    7 +
 src/backend/storage/file/meson.build          |    8 +
 src/backend/storage/freespace/meson.build     |    5 +
 src/backend/storage/ipc/meson.build           |   20 +
 src/backend/storage/large_object/meson.build  |    3 +
 src/backend/storage/lmgr/meson.build          |   13 +
 src/backend/storage/meson.build               |    9 +
 src/backend/storage/page/meson.build          |    5 +
 src/backend/storage/smgr/meson.build          |    4 +
 src/backend/storage/sync/meson.build          |    4 +
 src/backend/tcop/meson.build                  |    8 +
 src/backend/tsearch/meson.build               |   21 +
 src/backend/utils/activity/meson.build        |   18 +
 src/backend/utils/adt/meson.build             |  131 +
 src/backend/utils/cache/meson.build           |   16 +
 src/backend/utils/error/meson.build           |    6 +
 src/backend/utils/fmgr/meson.build            |    8 +
 src/backend/utils/hash/meson.build            |    4 +
 src/backend/utils/init/meson.build            |    4 +
 .../utils/mb/conversion_procs/meson.build     |   36 +
 src/backend/utils/mb/meson.build              |    9 +
 src/backend/utils/meson.build                 |   17 +
 src/backend/utils/misc/meson.build            |   35 +
 src/backend/utils/mmgr/meson.build            |   10 +
 src/backend/utils/resowner/meson.build        |    3 +
 src/backend/utils/sort/meson.build            |    9 +
 src/backend/utils/time/meson.build            |    4 +
 src/fe_utils/meson.build                      |   29 +
 src/bin/initdb/meson.build                    |   30 +
 src/bin/initdb/po/meson.build                 |    1 +
 src/bin/meson.build                           |   20 +
 src/bin/pg_amcheck/meson.build                |   27 +
 src/bin/pg_amcheck/po/meson.build             |    1 +
 src/bin/pg_archivecleanup/meson.build         |   19 +
 src/bin/pg_archivecleanup/po/meson.build      |    1 +
 src/bin/pg_basebackup/meson.build             |   61 +
 src/bin/pg_basebackup/po/meson.build          |    1 +
 src/bin/pg_checksums/meson.build              |   21 +
 src/bin/pg_checksums/po/meson.build           |    1 +
 src/bin/pg_config/meson.build                 |   19 +
 src/bin/pg_config/po/meson.build              |    1 +
 src/bin/pg_controldata/meson.build            |   19 +
 src/bin/pg_controldata/po/meson.build         |    1 +
 src/bin/pg_ctl/meson.build                    |   22 +
 src/bin/pg_ctl/po/meson.build                 |    1 +
 src/bin/pg_dump/meson.build                   |   75 +
 src/bin/pg_dump/po/meson.build                |    1 +
 src/bin/pg_resetwal/meson.build               |   20 +
 src/bin/pg_resetwal/po/meson.build            |    1 +
 src/bin/pg_rewind/meson.build                 |   42 +
 src/bin/pg_rewind/po/meson.build              |    1 +
 src/bin/pg_test_fsync/meson.build             |   21 +
 src/bin/pg_test_fsync/po/meson.build          |    1 +
 src/bin/pg_test_timing/meson.build            |   19 +
 src/bin/pg_test_timing/po/meson.build         |    1 +
 src/bin/pg_upgrade/meson.build                |   40 +
 src/bin/pg_upgrade/po/meson.build             |    1 +
 src/bin/pg_verifybackup/meson.build           |   33 +
 src/bin/pg_verifybackup/po/meson.build        |    1 +
 src/bin/pg_waldump/meson.build                |   30 +
 src/bin/pg_waldump/po/meson.build             |    1 +
 src/bin/pgbench/meson.build                   |   38 +
 src/bin/pgevent/meson.build                   |   26 +
 src/bin/psql/meson.build                      |   67 +
 src/bin/psql/po/meson.build                   |    1 +
 src/bin/scripts/meson.build                   |   51 +
 src/bin/scripts/po/meson.build                |    1 +
 src/interfaces/libpq/meson.build              |  108 +
 src/interfaces/libpq/po/meson.build           |    1 +
 src/interfaces/libpq/test/meson.build         |   15 +
 src/pl/meson.build                            |    5 +
 src/pl/plperl/meson.build                     |   90 +
 src/pl/plperl/po/meson.build                  |    1 +
 src/pl/plpgsql/meson.build                    |    1 +
 src/pl/plpgsql/src/meson.build                |   84 +
 src/pl/plpgsql/src/po/meson.build             |    1 +
 src/pl/plpython/meson.build                   |   99 +
 src/pl/plpython/po/meson.build                |    1 +
 src/pl/tcl/meson.build                        |   55 +
 src/pl/tcl/po/meson.build                     |    1 +
 contrib/adminpack/meson.build                 |   23 +
 contrib/amcheck/meson.build                   |   37 +
 contrib/auth_delay/meson.build                |    5 +
 contrib/auto_explain/meson.build              |   16 +
 contrib/basebackup_to_shell/meson.build       |   22 +
 contrib/basic_archive/meson.build             |   23 +
 contrib/bloom/meson.build                     |   36 +
 contrib/bool_plperl/meson.build               |   42 +
 contrib/btree_gin/meson.build                 |   54 +
 contrib/btree_gist/meson.build                |   84 +
 contrib/citext/meson.build                    |   34 +
 contrib/cube/meson.build                      |   53 +
 contrib/dblink/meson.build                    |   31 +
 contrib/dict_int/meson.build                  |   22 +
 contrib/dict_xsyn/meson.build                 |   29 +
 contrib/earthdistance/meson.build             |   23 +
 contrib/file_fdw/meson.build                  |   22 +
 contrib/fuzzystrmatch/meson.build             |   26 +
 contrib/hstore/meson.build                    |   44 +
 contrib/hstore_plperl/meson.build             |   43 +
 contrib/hstore_plpython/meson.build           |   37 +
 contrib/intagg/meson.build                    |    6 +
 contrib/intarray/meson.build                  |   37 +
 contrib/isn/meson.build                       |   33 +
 contrib/jsonb_plperl/meson.build              |   43 +
 contrib/jsonb_plpython/meson.build            |   36 +
 contrib/lo/meson.build                        |   27 +
 contrib/ltree/meson.build                     |   44 +
 contrib/ltree_plpython/meson.build            |   37 +
 contrib/meson.build                           |   66 +
 contrib/oid2name/meson.build                  |   17 +
 contrib/old_snapshot/meson.build              |   15 +
 contrib/pageinspect/meson.build               |   50 +
 contrib/passwordcheck/meson.build             |   30 +
 contrib/pg_buffercache/meson.build            |   27 +
 contrib/pg_freespacemap/meson.build           |   29 +
 contrib/pg_prewarm/meson.build                |   27 +
 contrib/pg_stat_statements/meson.build        |   35 +
 contrib/pg_surgery/meson.build                |   25 +
 contrib/pg_trgm/meson.build                   |   35 +
 contrib/pg_visibility/meson.build             |   26 +
 contrib/pg_walinspect/meson.build             |   27 +
 contrib/pgcrypto/meson.build                  |  100 +
 contrib/pgrowlocks/meson.build                |   27 +
 contrib/pgstattuple/meson.build               |   31 +
 contrib/postgres_fdw/meson.build              |   34 +
 contrib/seg/meson.build                       |   51 +
 contrib/sepgsql/meson.build                   |   34 +
 contrib/spi/meson.build                       |   50 +
 contrib/sslinfo/meson.build                   |   21 +
 contrib/tablefunc/meson.build                 |   24 +
 contrib/tcn/meson.build                       |   25 +
 contrib/test_decoding/meson.build             |   63 +
 contrib/tsm_system_rows/meson.build           |   24 +
 contrib/tsm_system_time/meson.build           |   24 +
 contrib/unaccent/meson.build                  |   32 +
 contrib/uuid-ossp/meson.build                 |   31 +
 contrib/vacuumlo/meson.build                  |   17 +
 contrib/xml2/meson.build                      |   32 +
 src/interfaces/ecpg/compatlib/meson.build     |   22 +
 src/interfaces/ecpg/ecpglib/meson.build       |   37 +
 src/interfaces/ecpg/ecpglib/po/meson.build    |    1 +
 src/interfaces/ecpg/include/meson.build       |   51 +
 src/interfaces/ecpg/meson.build               |    9 +
 src/interfaces/ecpg/pgtypeslib/meson.build    |   30 +
 src/interfaces/ecpg/preproc/meson.build       |  103 +
 src/interfaces/ecpg/preproc/po/meson.build    |    1 +
 .../ecpg/test/compat_informix/meson.build     |   31 +
 .../ecpg/test/compat_oracle/meson.build       |   20 +
 src/interfaces/ecpg/test/connect/meson.build  |   20 +
 src/interfaces/ecpg/test/meson.build          |   79 +
 .../ecpg/test/pgtypeslib/meson.build          |   21 +
 src/interfaces/ecpg/test/preproc/meson.build  |   37 +
 src/interfaces/ecpg/test/sql/meson.build      |   46 +
 src/interfaces/ecpg/test/thread/meson.build   |   21 +
 src/interfaces/meson.build                    |    2 +
 doc/src/sgml/meson.build                      |  252 ++
 doc/src/sgml/version.sgml.in                  |    2 +
 src/test/authentication/meson.build           |   11 +
 src/test/icu/meson.build                      |   11 +
 src/test/isolation/meson.build                |   58 +
 src/test/kerberos/meson.build                 |   15 +
 src/test/ldap/meson.build                     |   11 +
 src/test/meson.build                          |   25 +
 src/test/modules/brin/meson.build             |   16 +
 src/test/modules/commit_ts/meson.build        |   18 +
 src/test/modules/delay_execution/meson.build  |   18 +
 src/test/modules/dummy_index_am/meson.build   |   23 +
 src/test/modules/dummy_seclabel/meson.build   |   23 +
 src/test/modules/libpq_pipeline/meson.build   |   21 +
 src/test/modules/meson.build                  |   27 +
 src/test/modules/plsample/meson.build         |   23 +
 src/test/modules/snapshot_too_old/meson.build |   14 +
 src/test/modules/spgist_name_ops/meson.build  |   23 +
 .../ssl_passphrase_callback/meson.build       |   48 +
 src/test/modules/test_bloomfilter/meson.build |   23 +
 src/test/modules/test_ddl_deparse/meson.build |   43 +
 src/test/modules/test_extensions/meson.build  |   45 +
 .../modules/test_ginpostinglist/meson.build   |   23 +
 src/test/modules/test_integerset/meson.build  |   23 +
 src/test/modules/test_lfind/meson.build       |   23 +
 src/test/modules/test_misc/meson.build        |   12 +
 src/test/modules/test_oat_hooks/meson.build   |   18 +
 src/test/modules/test_parser/meson.build      |   23 +
 src/test/modules/test_pg_dump/meson.build     |   22 +
 src/test/modules/test_predtest/meson.build    |   23 +
 src/test/modules/test_rbtree/meson.build      |   23 +
 src/test/modules/test_regex/meson.build       |   24 +
 src/test/modules/test_rls_hooks/meson.build   |   17 +
 src/test/modules/test_shm_mq/meson.build      |   27 +
 src/test/modules/unsafe_tests/meson.build     |   11 +
 src/test/modules/worker_spi/meson.build       |   26 +
 src/test/perl/meson.build                     |   12 +
 src/test/recovery/meson.build                 |   43 +
 src/test/regress/meson.build                  |   62 +
 src/test/ssl/meson.build                      |   13 +
 src/test/subscription/meson.build             |   42 +
 configure                                     |    6 +
 configure.ac                                  |    6 +
 meson.build                                   | 3027 +++++++++++++++++
 meson_options.txt                             |  185 +
 src/meson.build                               |   12 +
 src/timezone/meson.build                      |   56 +
 src/timezone/tznames/meson.build              |   21 +
 src/tools/find_meson                          |   30 +
 src/tools/pgflex                              |   85 +
 src/tools/testwrap                            |   47 +
 264 files changed, 10886 insertions(+)
 create mode 100644 src/include/catalog/meson.build
 create mode 100644 src/include/meson.build
 create mode 100644 src/include/nodes/meson.build
 create mode 100644 src/include/pg_config_ext.h.meson
 create mode 100644 src/include/storage/meson.build
 create mode 100644 src/include/utils/meson.build
 create mode 100644 src/common/meson.build
 create mode 100644 src/common/unicode/meson.build
 create mode 100644 src/port/meson.build
 create mode 100644 config/meson.build
 create mode 100644 src/backend/access/brin/meson.build
 create mode 100644 src/backend/access/common/meson.build
 create mode 100644 src/backend/access/gin/meson.build
 create mode 100644 src/backend/access/gist/meson.build
 create mode 100644 src/backend/access/hash/meson.build
 create mode 100644 src/backend/access/heap/meson.build
 create mode 100644 src/backend/access/index/meson.build
 create mode 100644 src/backend/access/meson.build
 create mode 100644 src/backend/access/nbtree/meson.build
 create mode 100644 src/backend/access/rmgrdesc/meson.build
 create mode 100644 src/backend/access/spgist/meson.build
 create mode 100644 src/backend/access/table/meson.build
 create mode 100644 src/backend/access/tablesample/meson.build
 create mode 100644 src/backend/access/transam/meson.build
 create mode 100644 src/backend/backup/meson.build
 create mode 100644 src/backend/bootstrap/meson.build
 create mode 100644 src/backend/catalog/meson.build
 create mode 100644 src/backend/commands/meson.build
 create mode 100644 src/backend/executor/meson.build
 create mode 100644 src/backend/foreign/meson.build
 create mode 100644 src/backend/jit/llvm/meson.build
 create mode 100644 src/backend/jit/meson.build
 create mode 100644 src/backend/lib/meson.build
 create mode 100644 src/backend/libpq/meson.build
 create mode 100644 src/backend/main/meson.build
 create mode 100644 src/backend/meson.build
 create mode 100644 src/backend/nodes/meson.build
 create mode 100644 src/backend/optimizer/geqo/meson.build
 create mode 100644 src/backend/optimizer/meson.build
 create mode 100644 src/backend/optimizer/path/meson.build
 create mode 100644 src/backend/optimizer/plan/meson.build
 create mode 100644 src/backend/optimizer/prep/meson.build
 create mode 100644 src/backend/optimizer/util/meson.build
 create mode 100644 src/backend/parser/meson.build
 create mode 100644 src/backend/partitioning/meson.build
 create mode 100644 src/backend/po/meson.build
 create mode 100644 src/backend/port/meson.build
 create mode 100644 src/backend/port/win32/meson.build
 create mode 100644 src/backend/postmaster/meson.build
 create mode 100644 src/backend/regex/meson.build
 create mode 100644 src/backend/replication/libpqwalreceiver/meson.build
 create mode 100644 src/backend/replication/logical/meson.build
 create mode 100644 src/backend/replication/meson.build
 create mode 100644 src/backend/replication/pgoutput/meson.build
 create mode 100644 src/backend/rewrite/meson.build
 create mode 100644 src/backend/snowball/meson.build
 create mode 100644 src/backend/statistics/meson.build
 create mode 100644 src/backend/storage/buffer/meson.build
 create mode 100644 src/backend/storage/file/meson.build
 create mode 100644 src/backend/storage/freespace/meson.build
 create mode 100644 src/backend/storage/ipc/meson.build
 create mode 100644 src/backend/storage/large_object/meson.build
 create mode 100644 src/backend/storage/lmgr/meson.build
 create mode 100644 src/backend/storage/meson.build
 create mode 100644 src/backend/storage/page/meson.build
 create mode 100644 src/backend/storage/smgr/meson.build
 create mode 100644 src/backend/storage/sync/meson.build
 create mode 100644 src/backend/tcop/meson.build
 create mode 100644 src/backend/tsearch/meson.build
 create mode 100644 src/backend/utils/activity/meson.build
 create mode 100644 src/backend/utils/adt/meson.build
 create mode 100644 src/backend/utils/cache/meson.build
 create mode 100644 src/backend/utils/error/meson.build
 create mode 100644 src/backend/utils/fmgr/meson.build
 create mode 100644 src/backend/utils/hash/meson.build
 create mode 100644 src/backend/utils/init/meson.build
 create mode 100644 src/backend/utils/mb/conversion_procs/meson.build
 create mode 100644 src/backend/utils/mb/meson.build
 create mode 100644 src/backend/utils/meson.build
 create mode 100644 src/backend/utils/misc/meson.build
 create mode 100644 src/backend/utils/mmgr/meson.build
 create mode 100644 src/backend/utils/resowner/meson.build
 create mode 100644 src/backend/utils/sort/meson.build
 create mode 100644 src/backend/utils/time/meson.build
 create mode 100644 src/fe_utils/meson.build
 create mode 100644 src/bin/initdb/meson.build
 create mode 100644 src/bin/initdb/po/meson.build
 create mode 100644 src/bin/meson.build
 create mode 100644 src/bin/pg_amcheck/meson.build
 create mode 100644 src/bin/pg_amcheck/po/meson.build
 create mode 100644 src/bin/pg_archivecleanup/meson.build
 create mode 100644 src/bin/pg_archivecleanup/po/meson.build
 create mode 100644 src/bin/pg_basebackup/meson.build
 create mode 100644 src/bin/pg_basebackup/po/meson.build
 create mode 100644 src/bin/pg_checksums/meson.build
 create mode 100644 src/bin/pg_checksums/po/meson.build
 create mode 100644 src/bin/pg_config/meson.build
 create mode 100644 src/bin/pg_config/po/meson.build
 create mode 100644 src/bin/pg_controldata/meson.build
 create mode 100644 src/bin/pg_controldata/po/meson.build
 create mode 100644 src/bin/pg_ctl/meson.build
 create mode 100644 src/bin/pg_ctl/po/meson.build
 create mode 100644 src/bin/pg_dump/meson.build
 create mode 100644 src/bin/pg_dump/po/meson.build
 create mode 100644 src/bin/pg_resetwal/meson.build
 create mode 100644 src/bin/pg_resetwal/po/meson.build
 create mode 100644 src/bin/pg_rewind/meson.build
 create mode 100644 src/bin/pg_rewind/po/meson.build
 create mode 100644 src/bin/pg_test_fsync/meson.build
 create mode 100644 src/bin/pg_test_fsync/po/meson.build
 create mode 100644 src/bin/pg_test_timing/meson.build
 create mode 100644 src/bin/pg_test_timing/po/meson.build
 create mode 100644 src/bin/pg_upgrade/meson.build
 create mode 100644 src/bin/pg_upgrade/po/meson.build
 create mode 100644 src/bin/pg_verifybackup/meson.build
 create mode 100644 src/bin/pg_verifybackup/po/meson.build
 create mode 100644 src/bin/pg_waldump/meson.build
 create mode 100644 src/bin/pg_waldump/po/meson.build
 create mode 100644 src/bin/pgbench/meson.build
 create mode 100644 src/bin/pgevent/meson.build
 create mode 100644 src/bin/psql/meson.build
 create mode 100644 src/bin/psql/po/meson.build
 create mode 100644 src/bin/scripts/meson.build
 create mode 100644 src/bin/scripts/po/meson.build
 create mode 100644 src/interfaces/libpq/meson.build
 create mode 100644 src/interfaces/libpq/po/meson.build
 create mode 100644 src/interfaces/libpq/test/meson.build
 create mode 100644 src/pl/meson.build
 create mode 100644 src/pl/plperl/meson.build
 create mode 100644 src/pl/plperl/po/meson.build
 create mode 100644 src/pl/plpgsql/meson.build
 create mode 100644 src/pl/plpgsql/src/meson.build
 create mode 100644 src/pl/plpgsql/src/po/meson.build
 create mode 100644 src/pl/plpython/meson.build
 create mode 100644 src/pl/plpython/po/meson.build
 create mode 100644 src/pl/tcl/meson.build
 create mode 100644 src/pl/tcl/po/meson.build
 create mode 100644 contrib/adminpack/meson.build
 create mode 100644 contrib/amcheck/meson.build
 create mode 100644 contrib/auth_delay/meson.build
 create mode 100644 contrib/auto_explain/meson.build
 create mode 100644 contrib/basebackup_to_shell/meson.build
 create mode 100644 contrib/basic_archive/meson.build
 create mode 100644 contrib/bloom/meson.build
 create mode 100644 contrib/bool_plperl/meson.build
 create mode 100644 contrib/btree_gin/meson.build
 create mode 100644 contrib/btree_gist/meson.build
 create mode 100644 contrib/citext/meson.build
 create mode 100644 contrib/cube/meson.build
 create mode 100644 contrib/dblink/meson.build
 create mode 100644 contrib/dict_int/meson.build
 create mode 100644 contrib/dict_xsyn/meson.build
 create mode 100644 contrib/earthdistance/meson.build
 create mode 100644 contrib/file_fdw/meson.build
 create mode 100644 contrib/fuzzystrmatch/meson.build
 create mode 100644 contrib/hstore/meson.build
 create mode 100644 contrib/hstore_plperl/meson.build
 create mode 100644 contrib/hstore_plpython/meson.build
 create mode 100644 contrib/intagg/meson.build
 create mode 100644 contrib/intarray/meson.build
 create mode 100644 contrib/isn/meson.build
 create mode 100644 contrib/jsonb_plperl/meson.build
 create mode 100644 contrib/jsonb_plpython/meson.build
 create mode 100644 contrib/lo/meson.build
 create mode 100644 contrib/ltree/meson.build
 create mode 100644 contrib/ltree_plpython/meson.build
 create mode 100644 contrib/meson.build
 create mode 100644 contrib/oid2name/meson.build
 create mode 100644 contrib/old_snapshot/meson.build
 create mode 100644 contrib/pageinspect/meson.build
 create mode 100644 contrib/passwordcheck/meson.build
 create mode 100644 contrib/pg_buffercache/meson.build
 create mode 100644 contrib/pg_freespacemap/meson.build
 create mode 100644 contrib/pg_prewarm/meson.build
 create mode 100644 contrib/pg_stat_statements/meson.build
 create mode 100644 contrib/pg_surgery/meson.build
 create mode 100644 contrib/pg_trgm/meson.build
 create mode 100644 contrib/pg_visibility/meson.build
 create mode 100644 contrib/pg_walinspect/meson.build
 create mode 100644 contrib/pgcrypto/meson.build
 create mode 100644 contrib/pgrowlocks/meson.build
 create mode 100644 contrib/pgstattuple/meson.build
 create mode 100644 contrib/postgres_fdw/meson.build
 create mode 100644 contrib/seg/meson.build
 create mode 100644 contrib/sepgsql/meson.build
 create mode 100644 contrib/spi/meson.build
 create mode 100644 contrib/sslinfo/meson.build
 create mode 100644 contrib/tablefunc/meson.build
 create mode 100644 contrib/tcn/meson.build
 create mode 100644 contrib/test_decoding/meson.build
 create mode 100644 contrib/tsm_system_rows/meson.build
 create mode 100644 contrib/tsm_system_time/meson.build
 create mode 100644 contrib/unaccent/meson.build
 create mode 100644 contrib/uuid-ossp/meson.build
 create mode 100644 contrib/vacuumlo/meson.build
 create mode 100644 contrib/xml2/meson.build
 create mode 100644 src/interfaces/ecpg/compatlib/meson.build
 create mode 100644 src/interfaces/ecpg/ecpglib/meson.build
 create mode 100644 src/interfaces/ecpg/ecpglib/po/meson.build
 create mode 100644 src/interfaces/ecpg/include/meson.build
 create mode 100644 src/interfaces/ecpg/meson.build
 create mode 100644 src/interfaces/ecpg/pgtypeslib/meson.build
 create mode 100644 src/interfaces/ecpg/preproc/meson.build
 create mode 100644 src/interfaces/ecpg/preproc/po/meson.build
 create mode 100644 src/interfaces/ecpg/test/compat_informix/meson.build
 create mode 100644 src/interfaces/ecpg/test/compat_oracle/meson.build
 create mode 100644 src/interfaces/ecpg/test/connect/meson.build
 create mode 100644 src/interfaces/ecpg/test/meson.build
 create mode 100644 src/interfaces/ecpg/test/pgtypeslib/meson.build
 create mode 100644 src/interfaces/ecpg/test/preproc/meson.build
 create mode 100644 src/interfaces/ecpg/test/sql/meson.build
 create mode 100644 src/interfaces/ecpg/test/thread/meson.build
 create mode 100644 src/interfaces/meson.build
 create mode 100644 doc/src/sgml/meson.build
 create mode 100644 doc/src/sgml/version.sgml.in
 create mode 100644 src/test/authentication/meson.build
 create mode 100644 src/test/icu/meson.build
 create mode 100644 src/test/isolation/meson.build
 create mode 100644 src/test/kerberos/meson.build
 create mode 100644 src/test/ldap/meson.build
 create mode 100644 src/test/meson.build
 create mode 100644 src/test/modules/brin/meson.build
 create mode 100644 src/test/modules/commit_ts/meson.build
 create mode 100644 src/test/modules/delay_execution/meson.build
 create mode 100644 src/test/modules/dummy_index_am/meson.build
 create mode 100644 src/test/modules/dummy_seclabel/meson.build
 create mode 100644 src/test/modules/libpq_pipeline/meson.build
 create mode 100644 src/test/modules/meson.build
 create mode 100644 src/test/modules/plsample/meson.build
 create mode 100644 src/test/modules/snapshot_too_old/meson.build
 create mode 100644 src/test/modules/spgist_name_ops/meson.build
 create mode 100644 src/test/modules/ssl_passphrase_callback/meson.build
 create mode 100644 src/test/modules/test_bloomfilter/meson.build
 create mode 100644 src/test/modules/test_ddl_deparse/meson.build
 create mode 100644 src/test/modules/test_extensions/meson.build
 create mode 100644 src/test/modules/test_ginpostinglist/meson.build
 create mode 100644 src/test/modules/test_integerset/meson.build
 create mode 100644 src/test/modules/test_lfind/meson.build
 create mode 100644 src/test/modules/test_misc/meson.build
 create mode 100644 src/test/modules/test_oat_hooks/meson.build
 create mode 100644 src/test/modules/test_parser/meson.build
 create mode 100644 src/test/modules/test_pg_dump/meson.build
 create mode 100644 src/test/modules/test_predtest/meson.build
 create mode 100644 src/test/modules/test_rbtree/meson.build
 create mode 100644 src/test/modules/test_regex/meson.build
 create mode 100644 src/test/modules/test_rls_hooks/meson.build
 create mode 100644 src/test/modules/test_shm_mq/meson.build
 create mode 100644 src/test/modules/unsafe_tests/meson.build
 create mode 100644 src/test/modules/worker_spi/meson.build
 create mode 100644 src/test/perl/meson.build
 create mode 100644 src/test/recovery/meson.build
 create mode 100644 src/test/regress/meson.build
 create mode 100644 src/test/ssl/meson.build
 create mode 100644 src/test/subscription/meson.build
 create mode 100644 meson.build
 create mode 100644 meson_options.txt
 create mode 100644 src/meson.build
 create mode 100644 src/timezone/meson.build
 create mode 100644 src/timezone/tznames/meson.build
 create mode 100755 src/tools/find_meson
 create mode 100755 src/tools/pgflex
 create mode 100755 src/tools/testwrap

diff --git a/src/include/catalog/meson.build b/src/include/catalog/meson.build
new file mode 100644
index 00000000000..45ffa99692e
--- /dev/null
+++ b/src/include/catalog/meson.build
@@ -0,0 +1,142 @@
+catalog_headers = [
+  'pg_proc.h',
+  'pg_type.h',
+  'pg_attribute.h',
+  'pg_class.h',
+  'pg_attrdef.h',
+  'pg_constraint.h',
+  'pg_inherits.h',
+  'pg_index.h',
+  'pg_operator.h',
+  'pg_opfamily.h',
+  'pg_opclass.h',
+  'pg_am.h',
+  'pg_amop.h',
+  'pg_amproc.h',
+  'pg_language.h',
+  'pg_largeobject_metadata.h',
+  'pg_largeobject.h',
+  'pg_aggregate.h',
+  'pg_statistic.h',
+  'pg_statistic_ext.h',
+  'pg_statistic_ext_data.h',
+  'pg_rewrite.h',
+  'pg_trigger.h',
+  'pg_event_trigger.h',
+  'pg_description.h',
+  'pg_cast.h',
+  'pg_enum.h',
+  'pg_namespace.h',
+  'pg_conversion.h',
+  'pg_depend.h',
+  'pg_database.h',
+  'pg_db_role_setting.h',
+  'pg_tablespace.h',
+  'pg_authid.h',
+  'pg_auth_members.h',
+  'pg_shdepend.h',
+  'pg_shdescription.h',
+  'pg_ts_config.h',
+  'pg_ts_config_map.h',
+  'pg_ts_dict.h',
+  'pg_ts_parser.h',
+  'pg_ts_template.h',
+  'pg_extension.h',
+  'pg_foreign_data_wrapper.h',
+  'pg_foreign_server.h',
+  'pg_user_mapping.h',
+  'pg_foreign_table.h',
+  'pg_policy.h',
+  'pg_replication_origin.h',
+  'pg_default_acl.h',
+  'pg_init_privs.h',
+  'pg_seclabel.h',
+  'pg_shseclabel.h',
+  'pg_collation.h',
+  'pg_parameter_acl.h',
+  'pg_partitioned_table.h',
+  'pg_range.h',
+  'pg_transform.h',
+  'pg_sequence.h',
+  'pg_publication.h',
+  'pg_publication_namespace.h',
+  'pg_publication_rel.h',
+  'pg_subscription.h',
+  'pg_subscription_rel.h',
+]
+
+bki_data = [
+  'pg_aggregate.dat',
+  'pg_am.dat',
+  'pg_amop.dat',
+  'pg_amproc.dat',
+  'pg_authid.dat',
+  'pg_cast.dat',
+  'pg_class.dat',
+  'pg_collation.dat',
+  'pg_conversion.dat',
+  'pg_database.dat',
+  'pg_language.dat',
+  'pg_namespace.dat',
+  'pg_opclass.dat',
+  'pg_operator.dat',
+  'pg_opfamily.dat',
+  'pg_proc.dat',
+  'pg_range.dat',
+  'pg_tablespace.dat',
+  'pg_ts_config.dat',
+  'pg_ts_config_map.dat',
+  'pg_ts_dict.dat',
+  'pg_ts_parser.dat',
+  'pg_ts_template.dat',
+  'pg_type.dat',
+]
+bki_data_f = files(bki_data)
+
+
+input = []
+output_files = ['postgres.bki', 'system_constraints.sql', 'schemapg.h', 'system_fk_info.h']
+output_install = [dir_data, dir_data, dir_include_server / 'catalog', dir_include_server / 'catalog']
+
+foreach h : catalog_headers
+  fname = h.split('.h')[0] + '_d.h'
+  input += files(h)
+  output_files += fname
+  output_install += dir_include_server / 'catalog'
+endforeach
+
+generated_catalog_headers = custom_target('generated_catalog_headers',
+  output: output_files,
+  install_dir: output_install,
+  input: input,
+  depend_files: bki_data_f,
+  build_by_default: true,
+  install: true,
+  command: [
+    perl,
+    files('../../backend/catalog/genbki.pl'),
+    '--include-path=@SOURCE_ROOT@/src/include',
+    '--set-version=' + pg_version_major.to_string(),
+    '--output=@OUTDIR@', '@INPUT@'
+  ],
+)
+
+generated_headers += generated_catalog_headers.to_list()
+
+# autoconf generates the file there, ensure we get a conflict
+generated_sources_ac += {'src/backend/catalog': output_files + ['bki-stamp']}
+generated_sources_ac += {'src/include/catalog': ['header-stamp']}
+
+# 'reformat-dat-files' is a convenience target for rewriting the
+# catalog data files in our standard format.  This includes collapsing
+# out any entries that are redundant with a BKI_DEFAULT annotation.
+run_target('reformat-dat-files',
+  command: [perl, files('reformat_dat_file.pl'), '--output', '@CURRENT_SOURCE_DIR@', bki_data_f],
+)
+
+# 'expand-dat-files' is a convenience target for expanding out all
+# default values in the catalog data files.  This should be run before
+# altering or removing any BKI_DEFAULT annotation.
+run_target('expand-dat-files',
+  command: [perl, files('reformat_dat_file.pl'), '--output', '@CURRENT_SOURCE_DIR@', bki_data_f, '--full-tuples'],
+)
diff --git a/src/include/meson.build b/src/include/meson.build
new file mode 100644
index 00000000000..e5390df0584
--- /dev/null
+++ b/src/include/meson.build
@@ -0,0 +1,173 @@
+pg_config_ext = configure_file(
+  input: 'pg_config_ext.h.meson',
+  output: 'pg_config_ext.h',
+  configuration: cdata,
+  install: true,
+  install_dir: dir_include,
+)
+configure_files += pg_config_ext
+
+pg_config_os = configure_file(
+  output: 'pg_config_os.h',
+  input: files('port/@0@.h'.format(portname)),
+  install: true,
+  install_dir: dir_include,
+  copy: true,
+)
+configure_files += pg_config_os
+
+pg_config = configure_file(
+  output: 'pg_config.h',
+  install: true,
+  install_dir: dir_include,
+  configuration: cdata,
+)
+configure_files += pg_config
+
+
+config_paths_data = configuration_data()
+config_paths_data.set_quoted('PGBINDIR', dir_prefix / dir_bin)
+config_paths_data.set_quoted('PGSHAREDIR', dir_prefix / dir_data)
+config_paths_data.set_quoted('SYSCONFDIR', dir_prefix / dir_sysconf)
+config_paths_data.set_quoted('INCLUDEDIR', dir_prefix / dir_include)
+config_paths_data.set_quoted('PKGINCLUDEDIR', dir_prefix / dir_include_pkg)
+config_paths_data.set_quoted('INCLUDEDIRSERVER', dir_prefix / dir_include_server)
+config_paths_data.set_quoted('LIBDIR', dir_prefix / dir_lib)
+config_paths_data.set_quoted('PKGLIBDIR', dir_prefix / dir_lib_pkg)
+config_paths_data.set_quoted('LOCALEDIR', dir_prefix / dir_locale)
+config_paths_data.set_quoted('DOCDIR', dir_prefix / dir_doc)
+config_paths_data.set_quoted('HTMLDIR', dir_prefix / dir_doc_html)
+config_paths_data.set_quoted('MANDIR', dir_prefix / dir_man)
+
+
+var_cc = ' '.join(cc.cmd_array())
+var_cpp = ' '.join(cc.cmd_array() + ['-E'])
+var_cflags = ' '.join(cflags + cflags_warn)
+var_cxxflags = ' '.join(cxxflags + cxxflags_warn)
+var_cppflags = ' '.join(cppflags)
+var_cflags_sl = '-fPIC' #FIXME
+var_ldflags = ' '.join(ldflags)
+var_ldflags_sl = ''.join(ldflags_sl)
+var_ldflags_ex = '' # FIXME
+# FIXME - some extensions might directly use symbols from one of libs. If
+# that symbol isn't used by postgres, and statically linked, it'll cause an
+# undefined symbol at runtime. And obviously it'll cause problems for
+# executables, although those are probably less common.
+var_libs = ''
+
+
+pg_config_paths = configure_file(
+  output: 'pg_config_paths.h',
+  configuration: config_paths_data,
+  install: false,
+)
+configure_files += pg_config_paths
+
+install_headers(
+  'pg_config_manual.h',
+  'postgres_ext.h',
+)
+
+install_headers(
+  'libpq/libpq-fs.h',
+  install_dir: dir_include / 'libpq',
+)
+
+install_headers(
+  'c.h',
+  'port.h',
+  'postgres_fe.h',
+  install_dir: dir_include_internal
+)
+
+install_headers(
+  'libpq/pqcomm.h',
+  install_dir: dir_include_internal / 'libpq',
+)
+
+install_headers(
+  'c.h',
+  'fmgr.h',
+  'funcapi.h',
+  'getopt_long.h',
+  'miscadmin.h',
+  'pg_config_manual.h',
+  'pg_getopt.h',
+  'pg_trace.h',
+  'pgstat.h',
+  'pgtar.h',
+  'pgtime.h',
+  'port.h',
+  'postgres.h',
+  'postgres_ext.h',
+  'postgres_fe.h',
+  'windowapi.h',
+  pg_config_ext,
+  pg_config_os,
+  pg_config,
+  install_dir: dir_include_server,
+)
+
+subdir('catalog')
+subdir('nodes')
+subdir('storage')
+subdir('utils')
+
+header_subdirs = [
+  'access',
+  'catalog',
+  'bootstrap',
+  'commands',
+  'common',
+  'datatype',
+  'executor',
+  'fe_utils',
+  'foreign',
+  'jit',
+  'lib',
+  'libpq',
+  'mb',
+  'nodes',
+  'optimizer',
+  'parser',
+  'partitioning',
+  'postmaster',
+  'regex',
+  'replication',
+  'rewrite',
+  'statistics',
+  'storage',
+  'tcop',
+  'snowball',
+  'tsearch',
+  'utils',
+  'port',
+  'portability',
+]
+
+# XXX: installing headers this way has the danger of installing editor files
+# etc, unfortunately install_subdir() doesn't allow including / excluding by
+# pattern currently.
+foreach d : header_subdirs
+  if d == 'catalog'
+    continue
+  endif
+  install_subdir(d, install_dir: dir_include_server,
+                 exclude_files: ['.gitignore', 'meson.build'])
+endforeach
+
+install_subdir('catalog',
+  install_dir: dir_include_server,
+  exclude_files: [
+    '.gitignore',
+    'Makefile',
+    'duplicate_oids',
+    'meson.build',
+    'reformat_dat_file.pl',
+    'renumber_oids.pl',
+    'unused_oids',
+  ] + bki_data,
+)
+
+# autoconf generates the file there, ensure we get a conflict
+generated_sources_ac += {'src/include': ['stamp-h', 'stamp-ext-h']}
diff --git a/src/include/nodes/meson.build b/src/include/nodes/meson.build
new file mode 100644
index 00000000000..b7df232081f
--- /dev/null
+++ b/src/include/nodes/meson.build
@@ -0,0 +1,58 @@
+node_support_input_i = [
+  'nodes/nodes.h',
+  'nodes/primnodes.h',
+  'nodes/parsenodes.h',
+  'nodes/pathnodes.h',
+  'nodes/plannodes.h',
+  'nodes/execnodes.h',
+  'access/amapi.h',
+  'access/sdir.h',
+  'access/tableam.h',
+  'access/tsmapi.h',
+  'commands/event_trigger.h',
+  'commands/trigger.h',
+  'executor/tuptable.h',
+  'foreign/fdwapi.h',
+  'nodes/extensible.h',
+  'nodes/lockoptions.h',
+  'nodes/replnodes.h',
+  'nodes/supportnodes.h',
+  'nodes/value.h',
+  'utils/rel.h',
+]
+
+node_support_input = []
+foreach i : node_support_input_i
+  node_support_input += meson.source_root() / 'src' / 'include' / i
+endforeach
+
+node_support_output = [
+  'nodetags.h',
+  'outfuncs.funcs.c', 'outfuncs.switch.c',
+  'readfuncs.funcs.c', 'readfuncs.switch.c',
+  'copyfuncs.funcs.c', 'copyfuncs.switch.c',
+  'equalfuncs.funcs.c', 'equalfuncs.switch.c',
+]
+node_support_install = [
+  dir_include_server / 'nodes',
+  false, false,
+  false, false,
+  false, false,
+  false, false,
+]
+
+generated_nodes = custom_target('nodetags.h',
+  input: node_support_input,
+  output: node_support_output,
+  command: [
+    perl, files('../../backend/nodes/gen_node_support.pl'),
+    '-o', '@OUTDIR@',
+    '@INPUT@'],
+  install: true,
+  install_dir: node_support_install,
+)
+generated_headers += generated_nodes[0]
+
+# autoconf generates the file there, ensure we get a conflict
+generated_sources_ac += {'src/backend/nodes': node_support_output + ['node-support-stamp']}
+generated_sources_ac += {'src/include/nodes': ['header-stamp']}
diff --git a/src/include/pg_config_ext.h.meson b/src/include/pg_config_ext.h.meson
new file mode 100644
index 00000000000..57cdfca0cfd
--- /dev/null
+++ b/src/include/pg_config_ext.h.meson
@@ -0,0 +1,7 @@
+/*
+ * src/include/pg_config_ext.h.in.  This is generated manually, not by
+ * autoheader, since we want to limit which symbols get defined here.
+ */
+
+/* Define to the name of a signed 64-bit integer type. */
+#mesondefine PG_INT64_TYPE
diff --git a/src/include/storage/meson.build b/src/include/storage/meson.build
new file mode 100644
index 00000000000..eae9f98920e
--- /dev/null
+++ b/src/include/storage/meson.build
@@ -0,0 +1,19 @@
+lwlocknames = custom_target('lwlocknames',
+  input: files('../../backend/storage/lmgr/lwlocknames.txt'),
+  output: ['lwlocknames.h', 'lwlocknames.c'],
+  command: [
+    perl, files('../../backend/storage/lmgr/generate-lwlocknames.pl'),
+    '-o', '@OUTDIR@',
+    '@INPUT@'
+  ],
+  build_by_default: true,
+  install: true,
+  install_dir: [dir_include_server / 'storage', false],
+)
+
+lwlocknames_h = lwlocknames[0]
+
+generated_backend_headers += lwlocknames_h
+
+# autoconf generates the file there, ensure we get a conflict
+generated_sources_ac += {'src/backend/storage/lmgr': ['lwlocknames.c', 'lwlocknames.h']}
diff --git a/src/include/utils/meson.build b/src/include/utils/meson.build
new file mode 100644
index 00000000000..bded105f7ea
--- /dev/null
+++ b/src/include/utils/meson.build
@@ -0,0 +1,57 @@
+errcodes = custom_target('errcodes',
+  input: files('../../backend/utils/errcodes.txt'),
+  output: ['errcodes.h'],
+  command: [
+    perl, files('../../backend/utils/generate-errcodes.pl'),
+    '--outfile', '@OUTPUT@',
+    '@INPUT@',
+  ],
+  install: true,
+  install_dir: dir_include_server / 'utils',
+)
+generated_headers += errcodes
+
+if dtrace.found()
+  probes_tmp = custom_target('probes.h.tmp',
+    input: files('../../backend/utils/probes.d'),
+    output: 'probes.h.tmp',
+    command: [dtrace, '-C', '-h', '-s', '@INPUT@', '-o', '@OUTPUT@'],
+  )
+  probes = custom_target('probes.h',
+    input: probes_tmp,
+    output: 'probes.h',
+    capture: true,
+    command: [sed, '-f', files('../../backend/utils/postprocess_dtrace.sed'), '@INPUT@'],
+    install: true,
+    install_dir: dir_include_server / 'utils',
+  )
+else
+  probes = custom_target('probes.h',
+    input: files('../../backend/utils/probes.d'),
+    output: 'probes.h',
+    capture: true,
+    command: [sed, '-f', files('../../backend/utils/Gen_dummy_probes.sed'), '@INPUT@'],
+    install: true,
+    install_dir: dir_include_server / 'utils',
+  )
+endif
+
+generated_backend_headers += probes
+
+fmgrtab_output = ['fmgroids.h', 'fmgrprotos.h', 'fmgrtab.c']
+fmgrtab_target = custom_target('fmgrtab',
+  input: '../catalog/pg_proc.dat',
+  output : fmgrtab_output,
+  command: [perl, '-I', '@SOURCE_ROOT@/src/backend/catalog/', files('../../backend/utils/Gen_fmgrtab.pl'), '--include-path=@SOURCE_ROOT@/src/include', '--output=@OUTDIR@', '@INPUT@'],
+  install: true,
+  install_dir: [dir_include_server / 'utils', dir_include_server / 'utils', false],
+)
+
+generated_backend_headers += fmgrtab_target[0]
+generated_backend_headers += fmgrtab_target[1]
+
+# autoconf generates the file there, ensure we get a conflict
+generated_sources_ac += {
+  'src/backend/utils': fmgrtab_output + ['errcodes.h', 'probes.h', 'fmgr-stamp'],
+  'src/include/utils': ['header-stamp'],
+}
diff --git a/src/common/meson.build b/src/common/meson.build
new file mode 100644
index 00000000000..23842e1ffef
--- /dev/null
+++ b/src/common/meson.build
@@ -0,0 +1,174 @@
+common_sources = files(
+  'archive.c',
+  'base64.c',
+  'checksum_helper.c',
+  'compression.c',
+  'controldata_utils.c',
+  'encnames.c',
+  'exec.c',
+  'file_perm.c',
+  'file_utils.c',
+  'hashfn.c',
+  'ip.c',
+  'jsonapi.c',
+  'keywords.c',
+  'kwlookup.c',
+  'link-canary.c',
+  'md5_common.c',
+  'pg_get_line.c',
+  'pg_lzcompress.c',
+  'pg_prng.c',
+  'pgfnames.c',
+  'psprintf.c',
+  'relpath.c',
+  'rmtree.c',
+  'saslprep.c',
+  'scram-common.c',
+  'string.c',
+  'stringinfo.c',
+  'unicode_norm.c',
+  'username.c',
+  'wait_error.c',
+  'wchar.c',
+)
+
+if ssl.found()
+  common_sources += files(
+    'cryptohash_openssl.c',
+    'hmac_openssl.c',
+    'protocol_openssl.c',
+  )
+else
+  common_sources += files(
+    'cryptohash.c',
+    'hmac.c',
+    'md5.c',
+    'sha1.c',
+    'sha2.c',
+  )
+endif
+
+common_kwlist = custom_target('kwlist',
+  input: files('../include/parser/kwlist.h'),
+  output: 'kwlist_d.h',
+  command: [perl, '-I', '@SOURCE_ROOT@/src/tools', files('../tools/gen_keywordlist.pl'),
+      '--extern', '--output', '@OUTDIR@', '@INPUT@'])
+generated_sources += common_kwlist
+common_sources += common_kwlist
+
+# The code imported from Ryu gets a pass on declaration-after-statement,
+# in order to keep it more closely aligned with its upstream.
+ryu_sources = files(
+  'd2s.c',
+  'f2s.c',
+)
+ryu_cflags = []
+
+if using_declaration_after_statement_warning
+  ryu_cflags += ['-Wno-declaration-after-statement']
+endif
+
+config_info_sources = files('config_info.c',)
+config_info_cflags = [
+  '-DVAL_CC="@0@"'.format(var_cc),
+  '-DVAL_CPPFLAGS="@0@"'.format(var_cppflags),
+  '-DVAL_CFLAGS="@0@"'.format(var_cflags),
+  '-DVAL_CFLAGS_SL="@0@"'.format(var_cflags_sl),
+  '-DVAL_LDFLAGS="@0@"'.format(var_ldflags),
+  '-DVAL_LDFLAGS_EX="@0@"'.format(var_ldflags_ex),
+  '-DVAL_LDFLAGS_SL="@0@"'.format(var_ldflags_sl),
+  '-DVAL_LIBS="@0@"'.format(var_libs),
+]
+
+# Some files need to be built with different cflags. The different sets are
+# defined here.
+common_cflags = {
+  'ryu': ryu_cflags,
+  'config_info': config_info_cflags,
+}
+common_sources_cflags = {
+  'ryu': ryu_sources,
+  'config_info': config_info_sources
+}
+
+
+# A few files are currently only built for frontend, not server
+# (Mkvcbuild.pm has a copy of this list, too).  logging.c is excluded
+# from OBJS_FRONTEND_SHLIB (shared library) as a matter of policy,
+# because it is not appropriate for general purpose libraries such
+# as libpq to report errors directly.
+
+common_sources_frontend_shlib = common_sources
+common_sources_frontend_shlib += files(
+  'fe_memutils.c',
+  'restricted_token.c',
+  'sprompt.c',
+)
+
+common_sources_frontend_static = common_sources_frontend_shlib
+common_sources_frontend_static += files(
+  'logging.c',
+)
+
+# Build pgport once for backend, once for use in frontend binaries, and once
+# for use in shared libraries
+#
+# XXX: in most environments we could probably link_whole pgcommon_shlib
+# against pgcommon_static, instead of compiling twice.
+#
+# For the server build of pgcommon, depend on lwlocknames_h, because at least
+# cryptohash_openssl.c, hmac_openssl.c depend on it. That's arguably a
+# layering violation, but ...
+pgcommon = {}
+pgcommon_variants = {
+  '_srv': internal_lib_args + {
+    'sources': common_sources + [lwlocknames_h],
+    'dependencies': [backend_common_code],
+  },
+  '': default_lib_args + {
+    'sources': common_sources_frontend_static,
+    'dependencies': [frontend_common_code],
+  },
+  '_shlib': default_lib_args + {
+    'pic': true,
+    'sources': common_sources_frontend_shlib,
+    'dependencies': [frontend_common_code],
+  },
+}
+
+foreach name, opts : pgcommon_variants
+
+  # Build internal static libraries for sets of files that need to be built
+  # with different cflags
+  cflag_libs = []
+  foreach cflagname, sources : common_sources_cflags
+    if sources.length() == 0
+      continue
+    endif
+    c_args = opts.get('c_args', []) + common_cflags[cflagname]
+    cflag_libs += static_library('libpgcommon@0@_@1@'.format(name, cflagname),
+      include_directories: include_directories('.'),
+      kwargs: opts + {
+        'sources': sources,
+        'c_args': c_args,
+        'build_by_default': false,
+        'install': false,
+      },
+    )
+  endforeach
+
+  lib = static_library('libpgcommon@0@'.format(name),
+      link_with: cflag_libs,
+      include_directories: include_directories('.'),
+      kwargs: opts + {
+        'dependencies': opts['dependencies'] + [ssl],
+      }
+    )
+  pgcommon += {name: lib}
+endforeach
+
+common_srv = pgcommon['_srv']
+common_shlib = pgcommon['_shlib']
+common_static = pgcommon['']
+
+subdir('unicode')
diff --git a/src/common/unicode/meson.build b/src/common/unicode/meson.build
new file mode 100644
index 00000000000..43f0edd83e0
--- /dev/null
+++ b/src/common/unicode/meson.build
@@ -0,0 +1,106 @@
+UNICODE_VERSION = '14.0.0'
+
+unicode_data = {}
+unicode_baseurl = 'https://www.unicode.org/Public/@0@/ucd/@1@'
+
+if not wget.found()
+  subdir_done()
+endif
+
+# These files are part of the Unicode Character Database. Download them on
+# demand.
+foreach f : ['UnicodeData.txt', 'EastAsianWidth.txt', 'DerivedNormalizationProps.txt', 'CompositionExclusions.txt', 'NormalizationTest.txt']
+  url = unicode_baseurl.format(UNICODE_VERSION, f)
+  target = custom_target(f,
+    output: f,
+    command: [wget, wget_flags, url],
+    build_by_default: false,
+  )
+  unicode_data += {f: target}
+endforeach
+
+
+update_unicode_targets = []
+
+update_unicode_targets += \
+  custom_target('unicode_norm_table.h',
+    input: [unicode_data['UnicodeData.txt'], unicode_data['CompositionExclusions.txt']],
+    output: ['unicode_norm_table.h', 'unicode_norm_hashfunc.h'],
+    command: [
+      perl, files('generate-unicode_norm_table.pl'),
+      '--outdir', '@OUTDIR@', '@INPUT@'],
+    build_by_default: false,
+  )
+
+update_unicode_targets += \
+  custom_target('unicode_nonspacing_table.h',
+    input: [unicode_data['UnicodeData.txt']],
+    output: ['unicode_nonspacing_table.h'],
+    command: [perl, files('generate-unicode_nonspacing_table.pl'), '@INPUT@'],
+    build_by_default: false,
+    capture: true,
+  )
+
+update_unicode_targets += \
+  custom_target('unicode_east_asian_fw_table.h',
+    input: [unicode_data['EastAsianWidth.txt']],
+    output: ['unicode_east_asian_fw_table.h'],
+    command: [perl, files('generate-unicode_east_asian_fw_table.pl'), '@INPUT@'],
+    build_by_default: false,
+    capture: true,
+  )
+
+update_unicode_targets += \
+  custom_target('unicode_normprops_table.h',
+    input: [unicode_data['DerivedNormalizationProps.txt']],
+    output: ['unicode_normprops_table.h'],
+    command: [perl, files('generate-unicode_normprops_table.pl'), '@INPUT@'],
+    build_by_default: false,
+    capture: true,
+  )
+
+norm_test_table = custom_target('norm_test_table.h',
+    input: [unicode_data['NormalizationTest.txt']],
+    output: ['norm_test_table.h'],
+    command: [perl, files('generate-norm_test_table.pl'), '@INPUT@', '@OUTPUT@'],
+    build_by_default: false,
+  )
+
+inc = include_directories('.')
+
+norm_test = executable('norm_test',
+  ['norm_test.c', norm_test_table],
+  dependencies: [frontend_port_code],
+  include_directories: inc,
+  link_with: [common_static, pgport_static],
+  build_by_default: false,
+  kwargs: default_bin_args + {
+    'install': false,
+  }
+)
+
+update_unicode_dep = []
+
+if not meson.is_cross_build()
+  update_unicode_dep += custom_target('norm_test.run',
+    output: 'norm_test.run',
+    input: update_unicode_targets,
+    command: [norm_test],
+    build_by_default: false,
+    build_always_stale: true,
+  )
+endif
+
+
+# Use a custom target, as run targets serialize the output, making this harder
+# to debug, and don't deal well with targets with multiple outputs.
+update_unicode = custom_target('update-unicode',
+  depends: update_unicode_dep,
+  output: ['dont-exist'],
+  input: update_unicode_targets,
+  command: ['cp', '@INPUT@', '@SOURCE_ROOT@/src/include/common/'],
+  build_by_default: false,
+  build_always_stale: true,
+)
+
+alias_target('update-unicode', update_unicode)
diff --git a/src/port/meson.build b/src/port/meson.build
new file mode 100644
index 00000000000..ced2e014db8
--- /dev/null
+++ b/src/port/meson.build
@@ -0,0 +1,184 @@
+pgport_sources = [
+  'bsearch_arg.c',
+  'chklocale.c',
+  'inet_net_ntop.c',
+  'noblock.c',
+  'path.c',
+  'pg_bitutils.c',
+  'pg_strong_random.c',
+  'pgcheckdir.c',
+  'pgmkdirp.c',
+  'pgsleep.c',
+  'pgstrcasecmp.c',
+  'pgstrsignal.c',
+  'pqsignal.c',
+  'qsort.c',
+  'qsort_arg.c',
+  'quotes.c',
+  'snprintf.c',
+  'strerror.c',
+  'tar.c',
+  'thread.c',
+]
+
+if host_system == 'windows'
+  pgport_sources += files(
+    'dirmod.c',
+    'kill.c',
+    'open.c',
+    'system.c',
+    'win32dlopen.c',
+    'win32env.c',
+    'win32error.c',
+    'win32fdatasync.c',
+    'win32getrusage.c',
+    'win32link.c',
+    'win32ntdll.c',
+    'win32pread.c',
+    'win32pwrite.c',
+    'win32security.c',
+    'win32setlocale.c',
+    'win32stat.c',
+  )
+endif
+
+if cc.get_id() == 'msvc'
+  pgport_sources += files(
+    'dirent.c',
+    'win32gettimeofday.c',
+  )
+endif
+
+# Replacement functionality to be built if corresponding configure symbol
+# is false
+replace_funcs_neg = [
+  ['explicit_bzero'],
+  ['getopt'],
+  ['getopt_long'],
+  ['getpeereid'],
+  ['inet_aton'],
+  ['mkdtemp'],
+  ['preadv', 'HAVE_DECL_PREADV'],
+  ['pwritev', 'HAVE_DECL_PWRITEV'],
+  ['strlcat'],
+  ['strlcpy'],
+  ['strnlen'],
+]
+
+if host_system != 'windows'
+  replace_funcs_neg += [['pthread_barrier_wait']]
+endif
+
+# Replacement functionality to be built if corresponding configure symbol
+# is true
+replace_funcs_pos = [
+  # x86/x64
+  ['pg_crc32c_sse42', 'USE_SSE42_CRC32C'],
+  ['pg_crc32c_sse42', 'USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 'crc'],
+  ['pg_crc32c_sse42_choose', 'USE_SSE42_CRC32C_WITH_RUNTIME_CHECK'],
+  ['pg_crc32c_sb8', 'USE_SSE42_CRC32C_WITH_RUNTIME_CHECK'],
+
+  # arm / aarch64
+  ['pg_crc32c_armv8', 'USE_ARMV8_CRC32C'],
+  ['pg_crc32c_armv8', 'USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 'crc'],
+  ['pg_crc32c_armv8_choose', 'USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK'],
+  ['pg_crc32c_sb8', 'USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK'],
+
+  # generic fallback
+  ['pg_crc32c_sb8', 'USE_SLICING_BY_8_CRC32C'],
+]
+
+pgport_cflags = {'crc': cflags_crc}
+pgport_sources_cflags = {'crc': []}
+
+foreach f : replace_funcs_neg
+  func = f.get(0)
+  varname = f.get(1, 'HAVE_@0@'.format(func.to_upper()))
+  filename = '@0@.c'.format(func)
+
+  val = '@0@'.format(cdata.get(varname, 'false'))
+  if val == 'false' or val == '0'
+    pgport_sources += files(filename)
+  endif
+endforeach
+
+foreach f : replace_funcs_pos
+  func = f.get(0)
+  varname = f.get(1, 'HAVE_@0@'.format(func.to_upper()))
+  filename = '@0@.c'.format(func)
+
+  val = '@0@'.format(cdata.get(varname, 'false'))
+  if val == 'true' or val == '1'
+    src = files(filename)
+    if f.length() > 2
+      pgport_sources_cflags += {f[2]: pgport_sources_cflags[f[2]] + src}
+    else
+      pgport_sources += src
+    endif
+  endif
+endforeach
+
+
+if (host_system == 'windows' or host_system == 'cygwin') and \
+  (cc.get_id() != 'msvc' or cc.version().version_compare('<14.0'))
+
+  # Cygwin and (apparently, based on test results) Mingw both
+  # have a broken strtof(), so substitute its implementation.
+  # That's not a perfect fix, since it doesn't avoid double-rounding,
+  # but we have no better options.
+  pgport_sources += files('strtof.c')
+  message('On @0@ with compiler @1@ @2@ we will use our strtof wrapper.'.format(
+    host_system, cc.get_id(), cc.version()))
+endif
+
+
+
+# Build pgport once for backend, once for use in frontend binaries, and once
+# for use in shared libraries
+pgport = {}
+pgport_variants = {
+  '_srv': internal_lib_args + {
+    'dependencies': [backend_port_code],
+  },
+  '': default_lib_args + {
+    'dependencies': [frontend_port_code],
+  },
+  '_shlib': default_lib_args + {
+    'pic': true,
+    'dependencies': [frontend_port_code],
+  },
+}
+
+foreach name, opts : pgport_variants
+
+  # Build internal static libraries for sets of files that need to be built
+  # with different cflags
+  cflag_libs = []
+  foreach cflagname, sources : pgport_sources_cflags
+    if sources.length() == 0
+      continue
+    endif
+    c_args = opts.get('c_args', []) + pgport_cflags[cflagname]
+    cflag_libs += static_library('libpgport@0@_@1@'.format(name, cflagname),
+      sources,
+      kwargs: opts + {
+        'c_args': c_args,
+        'build_by_default': false,
+        'install': false,
+      },
+    )
+  endforeach
+
+  lib = static_library('libpgport@0@'.format(name),
+      pgport_sources,
+      link_with: cflag_libs,
+      kwargs: opts + {
+        'dependencies': opts['dependencies'] + [ssl],
+      }
+    )
+  pgport += {name: lib}
+endforeach
+
+pgport_srv = pgport['_srv']
+pgport_static = pgport['']
+pgport_shlib = pgport['_shlib']
diff --git a/config/meson.build b/config/meson.build
new file mode 100644
index 00000000000..ab19c380bd2
--- /dev/null
+++ b/config/meson.build
@@ -0,0 +1,4 @@
+install_data(
+  'install-sh', 'missing',
+  install_dir: dir_pgxs / 'config'
+)
diff --git a/src/backend/access/brin/meson.build b/src/backend/access/brin/meson.build
new file mode 100644
index 00000000000..a54c7532927
--- /dev/null
+++ b/src/backend/access/brin/meson.build
@@ -0,0 +1,12 @@
+backend_sources += files(
+  'brin.c',
+  'brin_bloom.c',
+  'brin_inclusion.c',
+  'brin_minmax.c',
+  'brin_minmax_multi.c',
+  'brin_pageops.c',
+  'brin_revmap.c',
+  'brin_tuple.c',
+  'brin_validate.c',
+  'brin_xlog.c',
+)
diff --git a/src/backend/access/common/meson.build b/src/backend/access/common/meson.build
new file mode 100644
index 00000000000..857beaa32d3
--- /dev/null
+++ b/src/backend/access/common/meson.build
@@ -0,0 +1,18 @@
+backend_sources += files(
+  'attmap.c',
+  'bufmask.c',
+  'detoast.c',
+  'heaptuple.c',
+  'indextuple.c',
+  'printsimple.c',
+  'printtup.c',
+  'relation.c',
+  'reloptions.c',
+  'scankey.c',
+  'session.c',
+  'syncscan.c',
+  'toast_compression.c',
+  'toast_internals.c',
+  'tupconvert.c',
+  'tupdesc.c',
+)
diff --git a/src/backend/access/gin/meson.build b/src/backend/access/gin/meson.build
new file mode 100644
index 00000000000..56d6f343d54
--- /dev/null
+++ b/src/backend/access/gin/meson.build
@@ -0,0 +1,17 @@
+backend_sources += files(
+  'ginarrayproc.c',
+  'ginbtree.c',
+  'ginbulk.c',
+  'gindatapage.c',
+  'ginentrypage.c',
+  'ginfast.c',
+  'ginget.c',
+  'gininsert.c',
+  'ginlogic.c',
+  'ginpostinglist.c',
+  'ginscan.c',
+  'ginutil.c',
+  'ginvacuum.c',
+  'ginvalidate.c',
+  'ginxlog.c',
+)
diff --git a/src/backend/access/gist/meson.build b/src/backend/access/gist/meson.build
new file mode 100644
index 00000000000..1a996b5e25d
--- /dev/null
+++ b/src/backend/access/gist/meson.build
@@ -0,0 +1,13 @@
+backend_sources += files(
+  'gist.c',
+  'gistbuild.c',
+  'gistbuildbuffers.c',
+  'gistget.c',
+  'gistproc.c',
+  'gistscan.c',
+  'gistsplit.c',
+  'gistutil.c',
+  'gistvacuum.c',
+  'gistvalidate.c',
+  'gistxlog.c',
+)
diff --git a/src/backend/access/hash/meson.build b/src/backend/access/hash/meson.build
new file mode 100644
index 00000000000..22f2c691c34
--- /dev/null
+++ b/src/backend/access/hash/meson.build
@@ -0,0 +1,12 @@
+backend_sources += files(
+  'hash.c',
+  'hash_xlog.c',
+  'hashfunc.c',
+  'hashinsert.c',
+  'hashovfl.c',
+  'hashpage.c',
+  'hashsearch.c',
+  'hashsort.c',
+  'hashutil.c',
+  'hashvalidate.c',
+)
diff --git a/src/backend/access/heap/meson.build b/src/backend/access/heap/meson.build
new file mode 100644
index 00000000000..f1dca73743c
--- /dev/null
+++ b/src/backend/access/heap/meson.build
@@ -0,0 +1,11 @@
+backend_sources += files(
+  'heapam.c',
+  'heapam_handler.c',
+  'heapam_visibility.c',
+  'heaptoast.c',
+  'hio.c',
+  'pruneheap.c',
+  'rewriteheap.c',
+  'vacuumlazy.c',
+  'visibilitymap.c',
+)
diff --git a/src/backend/access/index/meson.build b/src/backend/access/index/meson.build
new file mode 100644
index 00000000000..18af5533e65
--- /dev/null
+++ b/src/backend/access/index/meson.build
@@ -0,0 +1,6 @@
+backend_sources += files(
+  'amapi.c',
+  'amvalidate.c',
+  'genam.c',
+  'indexam.c',
+)
diff --git a/src/backend/access/meson.build b/src/backend/access/meson.build
new file mode 100644
index 00000000000..9874291fc0a
--- /dev/null
+++ b/src/backend/access/meson.build
@@ -0,0 +1,13 @@
+subdir('brin')
+subdir('common')
+subdir('gin')
+subdir('gist')
+subdir('hash')
+subdir('heap')
+subdir('index')
+subdir('nbtree')
+subdir('rmgrdesc')
+subdir('spgist')
+subdir('table')
+subdir('tablesample')
+subdir('transam')
diff --git a/src/backend/access/nbtree/meson.build b/src/backend/access/nbtree/meson.build
new file mode 100644
index 00000000000..07dc29e8190
--- /dev/null
+++ b/src/backend/access/nbtree/meson.build
@@ -0,0 +1,13 @@
+backend_sources += files(
+  'nbtcompare.c',
+  'nbtdedup.c',
+  'nbtinsert.c',
+  'nbtpage.c',
+  'nbtree.c',
+  'nbtsearch.c',
+  'nbtsort.c',
+  'nbtsplitloc.c',
+  'nbtutils.c',
+  'nbtvalidate.c',
+  'nbtxlog.c',
+)
diff --git a/src/backend/access/rmgrdesc/meson.build b/src/backend/access/rmgrdesc/meson.build
new file mode 100644
index 00000000000..f3a6e0a571b
--- /dev/null
+++ b/src/backend/access/rmgrdesc/meson.build
@@ -0,0 +1,26 @@
+# used by frontend programs like pg_waldump
+rmgr_desc_sources = files(
+  'brindesc.c',
+  'clogdesc.c',
+  'committsdesc.c',
+  'dbasedesc.c',
+  'genericdesc.c',
+  'gindesc.c',
+  'gistdesc.c',
+  'hashdesc.c',
+  'heapdesc.c',
+  'logicalmsgdesc.c',
+  'mxactdesc.c',
+  'nbtdesc.c',
+  'relmapdesc.c',
+  'replorigindesc.c',
+  'seqdesc.c',
+  'smgrdesc.c',
+  'spgdesc.c',
+  'standbydesc.c',
+  'tblspcdesc.c',
+  'xactdesc.c',
+  'xlogdesc.c',
+)
+
+backend_sources += rmgr_desc_sources
diff --git a/src/backend/access/spgist/meson.build b/src/backend/access/spgist/meson.build
new file mode 100644
index 00000000000..f18d0d2e53f
--- /dev/null
+++ b/src/backend/access/spgist/meson.build
@@ -0,0 +1,13 @@
+backend_sources += files(
+  'spgdoinsert.c',
+  'spginsert.c',
+  'spgkdtreeproc.c',
+  'spgproc.c',
+  'spgquadtreeproc.c',
+  'spgscan.c',
+  'spgtextproc.c',
+  'spgutils.c',
+  'spgvacuum.c',
+  'spgvalidate.c',
+  'spgxlog.c',
+)
diff --git a/src/backend/access/table/meson.build b/src/backend/access/table/meson.build
new file mode 100644
index 00000000000..66c706d640e
--- /dev/null
+++ b/src/backend/access/table/meson.build
@@ -0,0 +1,6 @@
+backend_sources += files(
+  'table.c',
+  'tableam.c',
+  'tableamapi.c',
+  'toast_helper.c',
+)
diff --git a/src/backend/access/tablesample/meson.build b/src/backend/access/tablesample/meson.build
new file mode 100644
index 00000000000..63ee8203226
--- /dev/null
+++ b/src/backend/access/tablesample/meson.build
@@ -0,0 +1,5 @@
+backend_sources += files(
+  'bernoulli.c',
+  'system.c',
+  'tablesample.c',
+)
diff --git a/src/backend/access/transam/meson.build b/src/backend/access/transam/meson.build
new file mode 100644
index 00000000000..c32169bd2c6
--- /dev/null
+++ b/src/backend/access/transam/meson.build
@@ -0,0 +1,31 @@
+backend_sources += files(
+  'clog.c',
+  'commit_ts.c',
+  'generic_xlog.c',
+  'multixact.c',
+  'parallel.c',
+  'rmgr.c',
+  'slru.c',
+  'subtrans.c',
+  'timeline.c',
+  'transam.c',
+  'twophase.c',
+  'twophase_rmgr.c',
+  'varsup.c',
+  'xact.c',
+  'xlog.c',
+  'xlogarchive.c',
+  'xlogfuncs.c',
+  'xloginsert.c',
+  'xlogprefetcher.c',
+  'xlogrecovery.c',
+  'xlogstats.c',
+  'xlogutils.c',
+)
+
+# used by frontend programs to build a frontend xlogreader
+xlogreader_sources = files(
+  'xlogreader.c',
+)
+
+backend_sources += xlogreader_sources
diff --git a/src/backend/backup/meson.build b/src/backend/backup/meson.build
new file mode 100644
index 00000000000..a09305cadfa
--- /dev/null
+++ b/src/backend/backup/meson.build
@@ -0,0 +1,13 @@
+backend_sources += files(
+  'backup_manifest.c',
+  'basebackup.c',
+  'basebackup_copy.c',
+  'basebackup_gzip.c',
+  'basebackup_lz4.c',
+  'basebackup_progress.c',
+  'basebackup_server.c',
+  'basebackup_sink.c',
+  'basebackup_target.c',
+  'basebackup_throttle.c',
+  'basebackup_zstd.c',
+)
diff --git a/src/backend/bootstrap/meson.build b/src/backend/bootstrap/meson.build
new file mode 100644
index 00000000000..55c33dd21c3
--- /dev/null
+++ b/src/backend/bootstrap/meson.build
@@ -0,0 +1,28 @@
+backend_sources += files(
+ 'bootstrap.c')
+
+# see ../parser/meson.build
+boot_parser_sources = []
+
+bootscanner = custom_target('bootscanner',
+  input: 'bootscanner.l',
+  output: 'bootscanner.c',
+  command: flex_cmd,
+)
+generated_sources += bootscanner
+boot_parser_sources += bootscanner
+
+bootparse = custom_target('bootparse',
+  input: 'bootparse.y',
+  kwargs: bison_kw,
+)
+generated_sources += bootparse.to_list()
+boot_parser_sources += bootparse
+
+boot_parser = static_library('boot_parser',
+  boot_parser_sources,
+  dependencies: [backend_code],
+  include_directories: include_directories('.'),
+  kwargs: internal_lib_args,
+)
+backend_link_with += boot_parser
diff --git a/src/backend/catalog/meson.build b/src/backend/catalog/meson.build
new file mode 100644
index 00000000000..08747914516
--- /dev/null
+++ b/src/backend/catalog/meson.build
@@ -0,0 +1,44 @@
+backend_sources += files(
+  'aclchk.c',
+  'catalog.c',
+  'dependency.c',
+  'heap.c',
+  'index.c',
+  'indexing.c',
+  'namespace.c',
+  'objectaccess.c',
+  'objectaddress.c',
+  'partition.c',
+  'pg_aggregate.c',
+  'pg_attrdef.c',
+  'pg_cast.c',
+  'pg_class.c',
+  'pg_collation.c',
+  'pg_constraint.c',
+  'pg_conversion.c',
+  'pg_db_role_setting.c',
+  'pg_depend.c',
+  'pg_enum.c',
+  'pg_inherits.c',
+  'pg_largeobject.c',
+  'pg_namespace.c',
+  'pg_operator.c',
+  'pg_parameter_acl.c',
+  'pg_proc.c',
+  'pg_publication.c',
+  'pg_range.c',
+  'pg_shdepend.c',
+  'pg_subscription.c',
+  'pg_type.c',
+  'storage.c',
+  'toasting.c',
+)
+
+
+install_data(
+  'information_schema.sql',
+  'sql_features.txt',
+  'system_functions.sql',
+  'system_views.sql',
+  install_dir: dir_data,
+)
diff --git a/src/backend/commands/meson.build b/src/backend/commands/meson.build
new file mode 100644
index 00000000000..9b350d025ff
--- /dev/null
+++ b/src/backend/commands/meson.build
@@ -0,0 +1,51 @@
+backend_sources += files(
+  'aggregatecmds.c',
+  'alter.c',
+  'amcmds.c',
+  'analyze.c',
+  'async.c',
+  'cluster.c',
+  'collationcmds.c',
+  'comment.c',
+  'constraint.c',
+  'conversioncmds.c',
+  'copy.c',
+  'copyfrom.c',
+  'copyfromparse.c',
+  'copyto.c',
+  'createas.c',
+  'dbcommands.c',
+  'define.c',
+  'discard.c',
+  'dropcmds.c',
+  'event_trigger.c',
+  'explain.c',
+  'extension.c',
+  'foreigncmds.c',
+  'functioncmds.c',
+  'indexcmds.c',
+  'lockcmds.c',
+  'matview.c',
+  'opclasscmds.c',
+  'operatorcmds.c',
+  'policy.c',
+  'portalcmds.c',
+  'prepare.c',
+  'proclang.c',
+  'publicationcmds.c',
+  'schemacmds.c',
+  'seclabel.c',
+  'sequence.c',
+  'statscmds.c',
+  'subscriptioncmds.c',
+  'tablecmds.c',
+  'tablespace.c',
+  'trigger.c',
+  'tsearchcmds.c',
+  'typecmds.c',
+  'user.c',
+  'vacuum.c',
+  'vacuumparallel.c',
+  'variable.c',
+  'view.c',
+)
diff --git a/src/backend/executor/meson.build b/src/backend/executor/meson.build
new file mode 100644
index 00000000000..518674cfa28
--- /dev/null
+++ b/src/backend/executor/meson.build
@@ -0,0 +1,67 @@
+backend_sources += files(
+  'execAmi.c',
+  'execAsync.c',
+  'execCurrent.c',
+  'execExpr.c',
+  'execExprInterp.c',
+  'execGrouping.c',
+  'execIndexing.c',
+  'execJunk.c',
+  'execMain.c',
+  'execParallel.c',
+  'execPartition.c',
+  'execProcnode.c',
+  'execReplication.c',
+  'execSRF.c',
+  'execScan.c',
+  'execTuples.c',
+  'execUtils.c',
+  'functions.c',
+  'instrument.c',
+  'nodeAgg.c',
+  'nodeAppend.c',
+  'nodeBitmapAnd.c',
+  'nodeBitmapHeapscan.c',
+  'nodeBitmapIndexscan.c',
+  'nodeBitmapOr.c',
+  'nodeCtescan.c',
+  'nodeCustom.c',
+  'nodeForeignscan.c',
+  'nodeFunctionscan.c',
+  'nodeGather.c',
+  'nodeGatherMerge.c',
+  'nodeGroup.c',
+  'nodeHash.c',
+  'nodeHashjoin.c',
+  'nodeIncrementalSort.c',
+  'nodeIndexonlyscan.c',
+  'nodeIndexscan.c',
+  'nodeLimit.c',
+  'nodeLockRows.c',
+  'nodeMaterial.c',
+  'nodeMemoize.c',
+  'nodeMergeAppend.c',
+  'nodeMergejoin.c',
+  'nodeModifyTable.c',
+  'nodeNamedtuplestorescan.c',
+  'nodeNestloop.c',
+  'nodeProjectSet.c',
+  'nodeRecursiveunion.c',
+  'nodeResult.c',
+  'nodeSamplescan.c',
+  'nodeSeqscan.c',
+  'nodeSetOp.c',
+  'nodeSort.c',
+  'nodeSubplan.c',
+  'nodeSubqueryscan.c',
+  'nodeTableFuncscan.c',
+  'nodeTidrangescan.c',
+  'nodeTidscan.c',
+  'nodeUnique.c',
+  'nodeValuesscan.c',
+  'nodeWindowAgg.c',
+  'nodeWorktablescan.c',
+  'spi.c',
+  'tqueue.c',
+  'tstoreReceiver.c',
+)
diff --git a/src/backend/foreign/meson.build b/src/backend/foreign/meson.build
new file mode 100644
index 00000000000..57463db92c1
--- /dev/null
+++ b/src/backend/foreign/meson.build
@@ -0,0 +1,3 @@
+backend_sources += files(
+  'foreign.c'
+)
diff --git a/src/backend/jit/llvm/meson.build b/src/backend/jit/llvm/meson.build
new file mode 100644
index 00000000000..de2e624ab58
--- /dev/null
+++ b/src/backend/jit/llvm/meson.build
@@ -0,0 +1,73 @@
+if not llvm.found()
+  subdir_done()
+endif
+
+# Build LLVM JIT backend module
+
+llvmjit_sources = []
+
+# Infrastructure
+llvmjit_sources += files(
+  'llvmjit.c',
+  'llvmjit_error.cpp',
+  'llvmjit_inline.cpp',
+  'llvmjit_wrap.cpp',
+)
+
+# Code generation
+llvmjit_sources += files(
+  'llvmjit_deform.c',
+  'llvmjit_expr.c',
+)
+
+llvmjit = shared_module('llvmjit',
+  llvmjit_sources,
+  kwargs: pg_mod_args + {
+    'dependencies': pg_mod_args['dependencies'] + [llvm],
+  }
+)
+
+backend_targets += llvmjit
+
+
+# Define a few bits and pieces used here and elsewhere to generate bitcode
+
+llvm_irgen_args = [
+  '-c', '-o', '@OUTPUT@', '@INPUT@',
+  '-flto=thin', '-emit-llvm',
+  '-MD', '-MQ', '@OUTPUT@', '-MF', '@DEPFILE@',
+  '-O2',
+  '-Wno-ignored-attributes',
+  '-Wno-empty-body',
+]
+
+if ccache.found()
+  llvm_irgen_command = ccache
+  llvm_irgen_args = [clang.path()] + llvm_irgen_args
+else
+  llvm_irgen_command = clang
+endif
+
+
+# XXX: Need to determine proper version of the function cflags for clang
+bitcode_cflags = ['-fno-strict-aliasing', '-fwrapv']
+bitcode_cflags += cppflags
+
+# XXX: Worth improving on the logic to find directories here
+bitcode_cflags += '-I@BUILD_ROOT@/src/include'
+bitcode_cflags += '-I@BUILD_ROOT@/src/backend/utils/misc'
+bitcode_cflags += '-I@SOURCE_ROOT@/src/include'
+
+
+# Note this is intentionally not installed to bitcodedir, as it's not for
+# inlining
+llvmjit_types = custom_target('llvmjit_types.bc',
+  command: [llvm_irgen_command] + llvm_irgen_args + bitcode_cflags,
+  input: 'llvmjit_types.c',
+  output: 'llvmjit_types.bc',
+  depends: [postgres],
+  install: true,
+  install_dir: dir_lib_pkg,
+  depfile: '@BASENAME@.c.bc.d',
+)
+backend_targets += llvmjit_types
diff --git a/src/backend/jit/meson.build b/src/backend/jit/meson.build
new file mode 100644
index 00000000000..63cd33a4bed
--- /dev/null
+++ b/src/backend/jit/meson.build
@@ -0,0 +1,3 @@
+backend_sources += files(
+  'jit.c'
+)
diff --git a/src/backend/lib/meson.build b/src/backend/lib/meson.build
new file mode 100644
index 00000000000..48da1bddce7
--- /dev/null
+++ b/src/backend/lib/meson.build
@@ -0,0 +1,12 @@
+backend_sources += files(
+  'binaryheap.c',
+  'bipartite_match.c',
+  'bloomfilter.c',
+  'dshash.c',
+  'hyperloglog.c',
+  'ilist.c',
+  'integerset.c',
+  'knapsack.c',
+  'pairingheap.c',
+  'rbtree.c',
+)
diff --git a/src/backend/libpq/meson.build b/src/backend/libpq/meson.build
new file mode 100644
index 00000000000..6061269ef13
--- /dev/null
+++ b/src/backend/libpq/meson.build
@@ -0,0 +1,32 @@
+backend_sources += files(
+  'auth-sasl.c',
+  'auth-scram.c',
+  'auth.c',
+  'be-fsstubs.c',
+  'be-secure-common.c',
+  'be-secure.c',
+  'crypt.c',
+  'hba.c',
+  'ifaddr.c',
+  'pqcomm.c',
+  'pqformat.c',
+  'pqmq.c',
+  'pqsignal.c',
+)
+
+if ssl.found()
+  backend_sources += files('be-secure-openssl.c')
+endif
+
+if gssapi.found()
+  backend_sources += files(
+    'be-secure-gssapi.c',
+    'be-gssapi-common.c'
+  )
+endif
+
+install_data(
+  'pg_hba.conf.sample',
+  'pg_ident.conf.sample',
+  install_dir: dir_data,
+)
diff --git a/src/backend/main/meson.build b/src/backend/main/meson.build
new file mode 100644
index 00000000000..241e125f089
--- /dev/null
+++ b/src/backend/main/meson.build
@@ -0,0 +1,2 @@
+main_file = files('main.c')
+backend_sources += main_file
diff --git a/src/backend/meson.build b/src/backend/meson.build
new file mode 100644
index 00000000000..fefa40ddb64
--- /dev/null
+++ b/src/backend/meson.build
@@ -0,0 +1,190 @@
+backend_build_deps = [backend_code]
+backend_sources = []
+backend_link_with = [pgport_srv, common_srv]
+
+generated_backend_sources = []
+
+subdir('access')
+subdir('backup')
+subdir('bootstrap')
+subdir('catalog')
+subdir('commands')
+subdir('executor')
+subdir('foreign')
+subdir('jit')
+subdir('lib')
+subdir('libpq')
+subdir('main')
+subdir('nodes')
+subdir('optimizer')
+subdir('parser')
+subdir('partitioning')
+subdir('port')
+subdir('postmaster')
+subdir('regex')
+subdir('replication')
+subdir('rewrite')
+subdir('statistics')
+subdir('storage')
+subdir('tcop')
+subdir('tsearch')
+subdir('utils')
+
+subdir('po', if_found: libintl)
+
+
+backend_link_args = []
+backend_link_depends = []
+
+
+# On windows when compiling with msvc we need to make postgres export all its
+# symbols so that extension libraries can use them. For that we need to scan
+# the constituting objects and generate a file specifying all the functions as
+# exported (variables need an "import" declaration in the header, hence
+# PGDLLEXPORT, but functions work without that, due to import libraries
+# basically being trampolines).
+#
+# For dtrace probes we need to invoke dtrace on all input files, before
+# linking the final executable (see more below).
+#
+#
+# On meson there's currently no easy way to do this that I found. So we build
+# a static library with all the input objects, run our script to generate
+# exports, and build the final executable using that static library
+#
+# We could do that only if either dtrace or msvc is in use, but it seems
+# easier to just always do so.
+#
+# Can't name the static library 'postgres', because msbuild ends up with a
+# conflict for the .pdb file otherwise.
+
+postgres_lib = static_library('postgres_lib',
+  backend_sources + timezone_sources + generated_backend_sources,
+  link_whole: backend_link_with,
+  dependencies: backend_build_deps,
+  kwargs: internal_lib_args,
+)
+
+if cc.get_id() == 'msvc'
+  postgres_def = custom_target('postgres.def',
+    command: [perl, files('../tools/msvc/gendef.pl'),
+              '--arch', host_cpu,
+              '--tempdir', '@PRIVATE_DIR@',
+              '--deffile', '@OUTPUT@',
+              '@INPUT@'],
+    input: [postgres_lib, common_srv, pgport_srv],
+    output: 'postgres.def',
+    depends: [postgres_lib, common_srv, pgport_srv],
+    install: false,
+    build_by_default: false,
+  )
+
+  backend_link_args += '/DEF:@0@'.format(postgres_def.full_path())
+  backend_link_depends += postgres_def
+
+elif host_system == 'aix'
+  # The '.' argument leads mkldexport.sh to emit "#! .", which refers to the
+  # main executable, allowing extension libraries to resolve their undefined
+  # symbols to symbols in the postgres binary.
+  postgres_imp = custom_target('postgres.imp',
+    command: [files('port/aix/mkldexport.sh'), '@INPUT@', '.'],
+    input: postgres_lib,
+    output: 'postgres.imp',
+    capture: true,
+    install: true,
+    install_dir: dir_lib,
+    build_by_default: false,
+  )
+  backend_link_args += '-Wl,-bE:@0@'.format(postgres_imp.full_path())
+  backend_link_depends += postgres_imp
+endif
+
+backend_input = []
+backend_objs = [postgres_lib.extract_all_objects(recursive: false)]
+
+# As of 1/2010:
+# The probes.o file is necessary for dtrace support on Solaris, and on recent
+# versions of systemtap.  (Older systemtap releases just produce an empty
+# file, but that's okay.)  However, macOS's dtrace doesn't use it and doesn't
+# even recognize the -G option.  So, build probes.o except on macOS.
+# This might need adjustment as other platforms add dtrace support.
+#
+# On at least linux we don't actually need to pass in all the objects, but
+# at least on FreeBSD and Solaris we have to.
+#
+# XXX: The reason we don't use the objects for generated sources is that
+# hits a meson bug. Luckily we don't don't have probes in generated
+# sources...
+if dtrace.found() and host_system != 'darwin'
+  backend_input += custom_target(
+    'probes.o',
+    input: ['utils/probes.d', postgres_lib.extract_objects(backend_sources, timezone_sources)],
+    output: 'probes.o',
+    command: [dtrace, '-C', '-G', '-o', '@OUTPUT@', '-s', '@INPUT@'],
+    install: false,
+  )
+endif
+
+postgres = executable('postgres',
+  backend_input,
+  objects: backend_objs,
+  link_args: backend_link_args,
+  link_with: backend_link_with,
+  link_depends: backend_link_depends,
+  export_dynamic: true,
+  implib: true,
+  dependencies: backend_build_deps,
+  kwargs: default_bin_args,
+)
+
+backend_targets += postgres
+
+pg_mod_c_args = cflags_mod
+pg_mod_cpp_args = cxxflags_mod
+pg_mod_link_args = ldflags_sl + ldflags_mod
+pg_mod_link_depend = []
+
+# A few platforms like MacOS and Windows link shared modules against postgres,
+# or a [import] library derived from it. Set up the link flags for that.
+if mod_link_args_fmt.length() > 0
+  # To avoid unnecessary build-time dependencies on other operating systems,
+  # only the dependency when it when necessary.
+  pg_mod_link_depend += postgres
+
+  name = mod_link_with_name.format('postgres')
+  link_with_uninst = meson.current_build_dir() / name
+  link_with_inst = '${@0@}/@1@'.format(mod_link_with_dir, name)
+
+  foreach el : mod_link_args_fmt
+    pg_mod_link_args += el.format(link_with_uninst)
+  endforeach
+endif
+
+
+# Note there's intentionally no dependency on pgport/common here - we want the
+# symbols from the main binary for extension modules, rather than the
+# extension linking separately to pgport/common.
+backend_mod_code = declare_dependency(
+  compile_args: pg_mod_c_args,
+  include_directories: postgres_inc,
+  link_args: pg_mod_link_args,
+  sources: generated_headers + generated_backend_headers,
+  dependencies: backend_mod_deps,
+)
+
+pg_mod_args = default_mod_args + {
+  'dependencies': [backend_mod_code],
+  'cpp_args': pg_mod_cpp_args,
+  'link_depends': pg_mod_link_depend,
+}
+
+
+
+# Shared modules that, on some system, link against the server binary. Only
+# enter these after we defined the server build.
+
+subdir('jit/llvm')
+subdir('replication/libpqwalreceiver')
+subdir('replication/pgoutput')
+subdir('snowball')
+subdir('utils/mb/conversion_procs')
diff --git a/src/backend/nodes/meson.build b/src/backend/nodes/meson.build
new file mode 100644
index 00000000000..8e0d4039f24
--- /dev/null
+++ b/src/backend/nodes/meson.build
@@ -0,0 +1,29 @@
+backend_sources += files(
+  'bitmapset.c',
+  'extensible.c',
+  'list.c',
+  'makefuncs.c',
+  'nodeFuncs.c',
+  'nodes.c',
+  'params.c',
+  'print.c',
+  'read.c',
+  'tidbitmap.c',
+  'value.c',
+)
+
+# these include .c files generated in ../../include/nodes, seems nicer to not
+# add that as an include path for the whole backend
+nodefunc_sources = files(
+  'copyfuncs.c',
+  'equalfuncs.c',
+  'outfuncs.c',
+  'readfuncs.c',
+)
+nodefuncs = static_library('nodefuncs',
+  nodefunc_sources,
+  dependencies: [backend_code],
+  include_directories: include_directories('../../include/nodes'),
+  kwargs: internal_lib_args,
+)
+backend_link_with += nodefuncs
diff --git a/src/backend/optimizer/geqo/meson.build b/src/backend/optimizer/geqo/meson.build
new file mode 100644
index 00000000000..c04f1dc2dfd
--- /dev/null
+++ b/src/backend/optimizer/geqo/meson.build
@@ -0,0 +1,17 @@
+backend_sources += files(
+  'geqo_copy.c',
+  'geqo_cx.c',
+  'geqo_erx.c',
+  'geqo_eval.c',
+  'geqo_main.c',
+  'geqo_misc.c',
+  'geqo_mutation.c',
+  'geqo_ox1.c',
+  'geqo_ox2.c',
+  'geqo_pmx.c',
+  'geqo_pool.c',
+  'geqo_px.c',
+  'geqo_random.c',
+  'geqo_recombination.c',
+  'geqo_selection.c',
+)
diff --git a/src/backend/optimizer/meson.build b/src/backend/optimizer/meson.build
new file mode 100644
index 00000000000..1ab1d9934ae
--- /dev/null
+++ b/src/backend/optimizer/meson.build
@@ -0,0 +1,5 @@
+subdir('geqo')
+subdir('path')
+subdir('plan')
+subdir('prep')
+subdir('util')
diff --git a/src/backend/optimizer/path/meson.build b/src/backend/optimizer/path/meson.build
new file mode 100644
index 00000000000..310042e7aee
--- /dev/null
+++ b/src/backend/optimizer/path/meson.build
@@ -0,0 +1,11 @@
+backend_sources += files(
+  'allpaths.c',
+  'clausesel.c',
+  'costsize.c',
+  'equivclass.c',
+  'indxpath.c',
+  'joinpath.c',
+  'joinrels.c',
+  'pathkeys.c',
+  'tidpath.c',
+)
diff --git a/src/backend/optimizer/plan/meson.build b/src/backend/optimizer/plan/meson.build
new file mode 100644
index 00000000000..22ec65a3845
--- /dev/null
+++ b/src/backend/optimizer/plan/meson.build
@@ -0,0 +1,10 @@
+backend_sources += files(
+  'analyzejoins.c',
+  'createplan.c',
+  'initsplan.c',
+  'planagg.c',
+  'planmain.c',
+  'planner.c',
+  'setrefs.c',
+  'subselect.c',
+)
diff --git a/src/backend/optimizer/prep/meson.build b/src/backend/optimizer/prep/meson.build
new file mode 100644
index 00000000000..4549a5b0e79
--- /dev/null
+++ b/src/backend/optimizer/prep/meson.build
@@ -0,0 +1,7 @@
+backend_sources += files(
+  'prepagg.c',
+  'prepjointree.c',
+  'prepqual.c',
+  'preptlist.c',
+  'prepunion.c',
+)
diff --git a/src/backend/optimizer/util/meson.build b/src/backend/optimizer/util/meson.build
new file mode 100644
index 00000000000..e7ceaf566b5
--- /dev/null
+++ b/src/backend/optimizer/util/meson.build
@@ -0,0 +1,16 @@
+backend_sources += files(
+  'appendinfo.c',
+  'clauses.c',
+  'inherit.c',
+  'joininfo.c',
+  'orclauses.c',
+  'paramassign.c',
+  'pathnode.c',
+  'placeholder.c',
+  'plancat.c',
+  'predtest.c',
+  'relnode.c',
+  'restrictinfo.c',
+  'tlist.c',
+  'var.c',
+)
diff --git a/src/backend/parser/meson.build b/src/backend/parser/meson.build
new file mode 100644
index 00000000000..15d5a349eeb
--- /dev/null
+++ b/src/backend/parser/meson.build
@@ -0,0 +1,48 @@
+backend_sources += files(
+  'analyze.c',
+  'parse_agg.c',
+  'parse_clause.c',
+  'parse_coerce.c',
+  'parse_collate.c',
+  'parse_cte.c',
+  'parse_enr.c',
+  'parse_expr.c',
+  'parse_func.c',
+  'parse_merge.c',
+  'parse_node.c',
+  'parse_oper.c',
+  'parse_param.c',
+  'parse_relation.c',
+  'parse_target.c',
+  'parse_type.c',
+  'parse_utilcmd.c',
+  'scansup.c',
+)
+
+# Build a small utility static lib for the parser. The generation of the
+# parser is slow, and building this separately avoids other parts of the
+# backend having to wait till gram.h is generated.
+parser_sources = files('parser.c')
+
+backend_scanner = custom_target('scan',
+  input: 'scan.l',
+  output: 'scan.c',
+  command: [flex_cmd, '--no-backup', '--fix-warnings', '--', '-CF', '-p', '-p'],
+)
+generated_sources += backend_scanner
+parser_sources += backend_scanner
+
+backend_parser = custom_target('gram',
+  input: 'gram.y',
+  kwargs: bison_kw,
+)
+generated_sources += backend_parser.to_list()
+parser_sources += backend_parser
+
+parser = static_library('parser',
+  parser_sources,
+  dependencies: [backend_code],
+  include_directories: include_directories('.'),
+  kwargs: internal_lib_args,
+)
+backend_link_with += parser
diff --git a/src/backend/partitioning/meson.build b/src/backend/partitioning/meson.build
new file mode 100644
index 00000000000..e5e3806a0cc
--- /dev/null
+++ b/src/backend/partitioning/meson.build
@@ -0,0 +1,5 @@
+backend_sources += files(
+  'partbounds.c',
+  'partdesc.c',
+  'partprune.c',
+)
diff --git a/src/backend/po/meson.build b/src/backend/po/meson.build
new file mode 100644
index 00000000000..4ace0554680
--- /dev/null
+++ b/src/backend/po/meson.build
@@ -0,0 +1 @@
+i18n.gettext('postgres-' + pg_version_major.to_string())
diff --git a/src/backend/port/meson.build b/src/backend/port/meson.build
new file mode 100644
index 00000000000..a22c25dd952
--- /dev/null
+++ b/src/backend/port/meson.build
@@ -0,0 +1,31 @@
+backend_sources += files(
+  'atomics.c',
+)
+
+
+if cdata.has('USE_UNNAMED_POSIX_SEMAPHORES') or cdata.has('USE_NAMED_POSIX_SEMAPHORES')
+  backend_sources += files('posix_sema.c')
+endif
+
+if cdata.has('USE_SYSV_SEMAPHORES')
+  backend_sources += files('sysv_sema.c')
+endif
+
+if cdata.has('USE_WIN32_SEMAPHORES')
+  backend_sources += files('win32_sema.c')
+endif
+
+if cdata.has('USE_SYSV_SHARED_MEMORY')
+  backend_sources += files('sysv_shmem.c')
+endif
+
+if cdata.has('USE_WIN32_SHARED_MEMORY')
+  backend_sources += files('win32_shmem.c')
+endif
+
+if host_system == 'windows'
+  subdir('win32')
+endif
+
+# autoconf generates the file there, ensure we get a conflict
+generated_sources_ac += {'src/backend/port': ['pg_sema.c', 'pg_shmem.c', 'tas.s']}
diff --git a/src/backend/port/win32/meson.build b/src/backend/port/win32/meson.build
new file mode 100644
index 00000000000..68fe4cc3cd0
--- /dev/null
+++ b/src/backend/port/win32/meson.build
@@ -0,0 +1,6 @@
+backend_sources += files(
+  'crashdump.c',
+  'signal.c',
+  'socket.c',
+  'timer.c',
+)
diff --git a/src/backend/postmaster/meson.build b/src/backend/postmaster/meson.build
new file mode 100644
index 00000000000..293a44ca295
--- /dev/null
+++ b/src/backend/postmaster/meson.build
@@ -0,0 +1,15 @@
+backend_sources += files(
+  'autovacuum.c',
+  'auxprocess.c',
+  'bgworker.c',
+  'bgwriter.c',
+  'checkpointer.c',
+  'fork_process.c',
+  'interrupt.c',
+  'pgarch.c',
+  'postmaster.c',
+  'shell_archive.c',
+  'startup.c',
+  'syslogger.c',
+  'walwriter.c',
+)
diff --git a/src/backend/regex/meson.build b/src/backend/regex/meson.build
new file mode 100644
index 00000000000..c84e57fdba5
--- /dev/null
+++ b/src/backend/regex/meson.build
@@ -0,0 +1,8 @@
+backend_sources += files(
+  'regcomp.c',
+  'regerror.c',
+  'regexec.c',
+  'regexport.c',
+  'regfree.c',
+  'regprefix.c',
+)
diff --git a/src/backend/replication/libpqwalreceiver/meson.build b/src/backend/replication/libpqwalreceiver/meson.build
new file mode 100644
index 00000000000..3fc786c80a0
--- /dev/null
+++ b/src/backend/replication/libpqwalreceiver/meson.build
@@ -0,0 +1,13 @@
+libpqwalreceiver_sources = files(
+  'libpqwalreceiver.c',
+)
+
+libpqwalreceiver = shared_module('pqwalreceiver',
+  libpqwalreceiver_sources,
+  kwargs: pg_mod_args + {
+    'name_prefix': 'lib',
+    'dependencies': pg_mod_args['dependencies'] + [libpq],
+  }
+)
+
+backend_targets += libpqwalreceiver
diff --git a/src/backend/replication/logical/meson.build b/src/backend/replication/logical/meson.build
new file mode 100644
index 00000000000..773583a12ba
--- /dev/null
+++ b/src/backend/replication/logical/meson.build
@@ -0,0 +1,14 @@
+backend_sources += files(
+  'decode.c',
+  'launcher.c',
+  'logical.c',
+  'logicalfuncs.c',
+  'message.c',
+  'origin.c',
+  'proto.c',
+  'relation.c',
+  'reorderbuffer.c',
+  'snapbuild.c',
+  'tablesync.c',
+  'worker.c',
+)
diff --git a/src/backend/replication/meson.build b/src/backend/replication/meson.build
new file mode 100644
index 00000000000..27b9bf13182
--- /dev/null
+++ b/src/backend/replication/meson.build
@@ -0,0 +1,51 @@
+backend_sources += files(
+  'slot.c',
+  'slotfuncs.c',
+  'syncrep.c',
+  'walreceiver.c',
+  'walreceiverfuncs.c',
+  'walsender.c',
+)
+
+# see ../parser/meson.build
+repl_parser_sources = []
+
+repl_scanner = custom_target('repl_scanner',
+  input: 'repl_scanner.l',
+  output: 'repl_scanner.c',
+  command: flex_cmd,
+)
+generated_sources += repl_scanner
+repl_parser_sources += repl_scanner
+
+repl_gram = custom_target('repl_gram',
+  input: 'repl_gram.y',
+  kwargs: bison_kw,
+)
+generated_sources += repl_gram.to_list()
+repl_parser_sources += repl_gram
+
+syncrep_scanner = custom_target('syncrep_scanner',
+  input: 'syncrep_scanner.l',
+  output: 'syncrep_scanner.c',
+  command: flex_cmd,
+)
+generated_sources += syncrep_scanner
+repl_parser_sources += syncrep_scanner
+
+syncrep_gram = custom_target('syncrep_gram',
+  input: 'syncrep_gram.y',
+  kwargs: bison_kw,
+)
+generated_sources += syncrep_gram.to_list()
+repl_parser_sources += syncrep_gram
+
+repl_parser = static_library('repl_parser',
+  repl_parser_sources,
+  dependencies: [backend_code],
+  include_directories: include_directories('.'),
+  kwargs: internal_lib_args,
+)
+backend_link_with += repl_parser
+
+subdir('logical')
diff --git a/src/backend/replication/pgoutput/meson.build b/src/backend/replication/pgoutput/meson.build
new file mode 100644
index 00000000000..8ff0a0c6133
--- /dev/null
+++ b/src/backend/replication/pgoutput/meson.build
@@ -0,0 +1,11 @@
+pgoutput_sources = files(
+  'pgoutput.c',
+)
+
+pgoutput = shared_module('pgoutput',
+  pgoutput_sources,
+  kwargs: pg_mod_args + {
+  }
+)
+
+backend_targets += pgoutput
diff --git a/src/backend/rewrite/meson.build b/src/backend/rewrite/meson.build
new file mode 100644
index 00000000000..21fa0e230b0
--- /dev/null
+++ b/src/backend/rewrite/meson.build
@@ -0,0 +1,9 @@
+backend_sources += files(
+  'rewriteDefine.c',
+  'rewriteHandler.c',
+  'rewriteManip.c',
+  'rewriteRemove.c',
+  'rewriteSearchCycle.c',
+  'rewriteSupport.c',
+  'rowsecurity.c',
+)
diff --git a/src/backend/snowball/meson.build b/src/backend/snowball/meson.build
new file mode 100644
index 00000000000..8c6f685cb32
--- /dev/null
+++ b/src/backend/snowball/meson.build
@@ -0,0 +1,88 @@
+dict_snowball_sources = files(
+  'libstemmer/api.c',
+  'libstemmer/utilities.c',
+  'dict_snowball.c',
+)
+
+dict_snowball_sources += files(
+  'libstemmer/stem_ISO_8859_1_basque.c',
+  'libstemmer/stem_ISO_8859_1_catalan.c',
+  'libstemmer/stem_ISO_8859_1_danish.c',
+  'libstemmer/stem_ISO_8859_1_dutch.c',
+  'libstemmer/stem_ISO_8859_1_english.c',
+  'libstemmer/stem_ISO_8859_1_finnish.c',
+  'libstemmer/stem_ISO_8859_1_french.c',
+  'libstemmer/stem_ISO_8859_1_german.c',
+  'libstemmer/stem_ISO_8859_1_indonesian.c',
+  'libstemmer/stem_ISO_8859_1_irish.c',
+  'libstemmer/stem_ISO_8859_1_italian.c',
+  'libstemmer/stem_ISO_8859_1_norwegian.c',
+  'libstemmer/stem_ISO_8859_1_porter.c',
+  'libstemmer/stem_ISO_8859_1_portuguese.c',
+  'libstemmer/stem_ISO_8859_1_spanish.c',
+  'libstemmer/stem_ISO_8859_1_swedish.c',
+  'libstemmer/stem_ISO_8859_2_hungarian.c',
+  'libstemmer/stem_ISO_8859_2_romanian.c',
+  'libstemmer/stem_KOI8_R_russian.c',
+  'libstemmer/stem_UTF_8_arabic.c',
+  'libstemmer/stem_UTF_8_armenian.c',
+  'libstemmer/stem_UTF_8_basque.c',
+  'libstemmer/stem_UTF_8_catalan.c',
+  'libstemmer/stem_UTF_8_danish.c',
+  'libstemmer/stem_UTF_8_dutch.c',
+  'libstemmer/stem_UTF_8_english.c',
+  'libstemmer/stem_UTF_8_finnish.c',
+  'libstemmer/stem_UTF_8_french.c',
+  'libstemmer/stem_UTF_8_german.c',
+  'libstemmer/stem_UTF_8_greek.c',
+  'libstemmer/stem_UTF_8_hindi.c',
+  'libstemmer/stem_UTF_8_hungarian.c',
+  'libstemmer/stem_UTF_8_indonesian.c',
+  'libstemmer/stem_UTF_8_irish.c',
+  'libstemmer/stem_UTF_8_italian.c',
+  'libstemmer/stem_UTF_8_lithuanian.c',
+  'libstemmer/stem_UTF_8_nepali.c',
+  'libstemmer/stem_UTF_8_norwegian.c',
+  'libstemmer/stem_UTF_8_porter.c',
+  'libstemmer/stem_UTF_8_portuguese.c',
+  'libstemmer/stem_UTF_8_romanian.c',
+  'libstemmer/stem_UTF_8_russian.c',
+  'libstemmer/stem_UTF_8_serbian.c',
+  'libstemmer/stem_UTF_8_spanish.c',
+  'libstemmer/stem_UTF_8_swedish.c',
+  'libstemmer/stem_UTF_8_tamil.c',
+  'libstemmer/stem_UTF_8_turkish.c',
+  'libstemmer/stem_UTF_8_yiddish.c',
+)
+
+# see comment in src/include/snowball/header.h
+stemmer_inc = include_directories('../../include/snowball')
+
+dict_snowball = shared_module('dict_snowball',
+  dict_snowball_sources,
+  kwargs: pg_mod_args + {
+    'include_directories': [stemmer_inc],
+  }
+)
+
+snowball_create = custom_target('snowball_create',
+  output: ['snowball_create.sql'],
+  depfile: 'snowball_create.dep',
+  command: [
+    perl, files('snowball_create.pl'),
+    '--depfile',
+    '--input', '@CURRENT_SOURCE_DIR@',
+    '--outdir', '@OUTDIR@',
+  ],
+  install: true,
+  install_dir: dir_data,
+)
+generated_sources += snowball_create
+
+install_subdir('stopwords',
+  install_dir: dir_data / 'tsearch_data',
+  strip_directory: true,
+)
+
+backend_targets += dict_snowball
+backend_targets += snowball_create
diff --git a/src/backend/statistics/meson.build b/src/backend/statistics/meson.build
new file mode 100644
index 00000000000..8530c55f73c
--- /dev/null
+++ b/src/backend/statistics/meson.build
@@ -0,0 +1,6 @@
+backend_sources += files(
+  'dependencies.c',
+  'extended_stats.c',
+  'mcv.c',
+  'mvdistinct.c',
+)
diff --git a/src/backend/storage/buffer/meson.build b/src/backend/storage/buffer/meson.build
new file mode 100644
index 00000000000..56a59b52484
--- /dev/null
+++ b/src/backend/storage/buffer/meson.build
@@ -0,0 +1,7 @@
+backend_sources += files(
+  'buf_init.c',
+  'buf_table.c',
+  'bufmgr.c',
+  'freelist.c',
+  'localbuf.c',
+)
diff --git a/src/backend/storage/file/meson.build b/src/backend/storage/file/meson.build
new file mode 100644
index 00000000000..e1d5047d4aa
--- /dev/null
+++ b/src/backend/storage/file/meson.build
@@ -0,0 +1,8 @@
+backend_sources += files(
+  'buffile.c',
+  'copydir.c',
+  'fd.c',
+  'fileset.c',
+  'reinit.c',
+  'sharedfileset.c',
+)
diff --git a/src/backend/storage/freespace/meson.build b/src/backend/storage/freespace/meson.build
new file mode 100644
index 00000000000..e4200ea6527
--- /dev/null
+++ b/src/backend/storage/freespace/meson.build
@@ -0,0 +1,5 @@
+backend_sources += files(
+  'freespace.c',
+  'fsmpage.c',
+  'indexfsm.c',
+)
diff --git a/src/backend/storage/ipc/meson.build b/src/backend/storage/ipc/meson.build
new file mode 100644
index 00000000000..516bc1d0193
--- /dev/null
+++ b/src/backend/storage/ipc/meson.build
@@ -0,0 +1,20 @@
+backend_sources += files(
+  'barrier.c',
+  'dsm.c',
+  'dsm_impl.c',
+  'ipc.c',
+  'ipci.c',
+  'latch.c',
+  'pmsignal.c',
+  'procarray.c',
+  'procsignal.c',
+  'shm_mq.c',
+  'shm_toc.c',
+  'shmem.c',
+  'shmqueue.c',
+  'signalfuncs.c',
+  'sinval.c',
+  'sinvaladt.c',
+  'standby.c',
+
+)
diff --git a/src/backend/storage/large_object/meson.build b/src/backend/storage/large_object/meson.build
new file mode 100644
index 00000000000..8a181ab9b34
--- /dev/null
+++ b/src/backend/storage/large_object/meson.build
@@ -0,0 +1,3 @@
+backend_sources += files(
+  'inv_api.c',
+)
diff --git a/src/backend/storage/lmgr/meson.build b/src/backend/storage/lmgr/meson.build
new file mode 100644
index 00000000000..68237c8a2e8
--- /dev/null
+++ b/src/backend/storage/lmgr/meson.build
@@ -0,0 +1,13 @@
+backend_sources += files(
+  'condition_variable.c',
+  'deadlock.c',
+  'lmgr.c',
+  'lock.c',
+  'lwlock.c',
+  'predicate.c',
+  'proc.c',
+  's_lock.c',
+  'spin.c',
+)
+
+generated_backend_sources += lwlocknames[1]
diff --git a/src/backend/storage/meson.build b/src/backend/storage/meson.build
new file mode 100644
index 00000000000..daad628d74c
--- /dev/null
+++ b/src/backend/storage/meson.build
@@ -0,0 +1,9 @@
+subdir('buffer')
+subdir('file')
+subdir('freespace')
+subdir('ipc')
+subdir('large_object')
+subdir('lmgr')
+subdir('page')
+subdir('smgr')
+subdir('sync')
diff --git a/src/backend/storage/page/meson.build b/src/backend/storage/page/meson.build
new file mode 100644
index 00000000000..2ecd16c952c
--- /dev/null
+++ b/src/backend/storage/page/meson.build
@@ -0,0 +1,5 @@
+backend_sources += files(
+  'bufpage.c',
+  'checksum.c',
+  'itemptr.c',
+)
diff --git a/src/backend/storage/smgr/meson.build b/src/backend/storage/smgr/meson.build
new file mode 100644
index 00000000000..fdeb1223b32
--- /dev/null
+++ b/src/backend/storage/smgr/meson.build
@@ -0,0 +1,4 @@
+backend_sources += files(
+  'md.c',
+  'smgr.c',
+)
diff --git a/src/backend/storage/sync/meson.build b/src/backend/storage/sync/meson.build
new file mode 100644
index 00000000000..05148b91a8e
--- /dev/null
+++ b/src/backend/storage/sync/meson.build
@@ -0,0 +1,4 @@
+backend_sources += files(
+  'sync.c',
+
+)
diff --git a/src/backend/tcop/meson.build b/src/backend/tcop/meson.build
new file mode 100644
index 00000000000..fb54aae8122
--- /dev/null
+++ b/src/backend/tcop/meson.build
@@ -0,0 +1,8 @@
+backend_sources += files(
+  'cmdtag.c',
+  'dest.c',
+  'fastpath.c',
+  'postgres.c',
+  'pquery.c',
+  'utility.c',
+)
diff --git a/src/backend/tsearch/meson.build b/src/backend/tsearch/meson.build
new file mode 100644
index 00000000000..4144e9befc5
--- /dev/null
+++ b/src/backend/tsearch/meson.build
@@ -0,0 +1,21 @@
+backend_sources += files(
+  'dict.c',
+  'dict_ispell.c',
+  'dict_simple.c',
+  'dict_synonym.c',
+  'dict_thesaurus.c',
+  'regis.c',
+  'spell.c',
+  'to_tsany.c',
+  'ts_locale.c',
+  'ts_parse.c',
+  'ts_selfuncs.c',
+  'ts_typanalyze.c',
+  'ts_utils.c',
+  'wparser.c',
+  'wparser_def.c',
+)
+
+install_subdir('dicts',
+  install_dir: dir_data / 'tsearch_data',
+  strip_directory: true)
diff --git a/src/backend/utils/activity/meson.build b/src/backend/utils/activity/meson.build
new file mode 100644
index 00000000000..5b3b558a67d
--- /dev/null
+++ b/src/backend/utils/activity/meson.build
@@ -0,0 +1,18 @@
+backend_sources += files(
+  'backend_progress.c',
+  'backend_status.c',
+  'pgstat.c',
+  'pgstat_archiver.c',
+  'pgstat_bgwriter.c',
+  'pgstat_checkpointer.c',
+  'pgstat_database.c',
+  'pgstat_function.c',
+  'pgstat_relation.c',
+  'pgstat_replslot.c',
+  'pgstat_shmem.c',
+  'pgstat_slru.c',
+  'pgstat_subscription.c',
+  'pgstat_wal.c',
+  'pgstat_xact.c',
+  'wait_event.c',
+)
diff --git a/src/backend/utils/adt/meson.build b/src/backend/utils/adt/meson.build
new file mode 100644
index 00000000000..ed9ceadfef0
--- /dev/null
+++ b/src/backend/utils/adt/meson.build
@@ -0,0 +1,131 @@
+backend_sources += files(
+  'acl.c',
+  'amutils.c',
+  'array_expanded.c',
+  'array_selfuncs.c',
+  'array_typanalyze.c',
+  'array_userfuncs.c',
+  'arrayfuncs.c',
+  'arraysubs.c',
+  'arrayutils.c',
+  'ascii.c',
+  'bool.c',
+  'cash.c',
+  'char.c',
+  'cryptohashfuncs.c',
+  'date.c',
+  'datetime.c',
+  'datum.c',
+  'dbsize.c',
+  'domains.c',
+  'encode.c',
+  'enum.c',
+  'expandeddatum.c',
+  'expandedrecord.c',
+  'float.c',
+  'format_type.c',
+  'formatting.c',
+  'genfile.c',
+  'geo_ops.c',
+  'geo_selfuncs.c',
+  'geo_spgist.c',
+  'hbafuncs.c',
+  'inet_cidr_ntop.c',
+  'inet_net_pton.c',
+  'int.c',
+  'int8.c',
+  'json.c',
+  'jsonb.c',
+  'jsonb_gin.c',
+  'jsonb_op.c',
+  'jsonb_util.c',
+  'jsonbsubs.c',
+  'jsonfuncs.c',
+  'jsonpath.c',
+  'jsonpath_exec.c',
+  'like.c',
+  'like_support.c',
+  'lockfuncs.c',
+  'mac.c',
+  'mac8.c',
+  'mcxtfuncs.c',
+  'misc.c',
+  'multirangetypes.c',
+  'multirangetypes_selfuncs.c',
+  'name.c',
+  'network.c',
+  'network_gist.c',
+  'network_selfuncs.c',
+  'network_spgist.c',
+  'numeric.c',
+  'numutils.c',
+  'oid.c',
+  'oracle_compat.c',
+  'orderedsetaggs.c',
+  'partitionfuncs.c',
+  'pg_locale.c',
+  'pg_lsn.c',
+  'pg_upgrade_support.c',
+  'pgstatfuncs.c',
+  'pseudotypes.c',
+  'quote.c',
+  'rangetypes.c',
+  'rangetypes_gist.c',
+  'rangetypes_selfuncs.c',
+  'rangetypes_spgist.c',
+  'rangetypes_typanalyze.c',
+  'regexp.c',
+  'regproc.c',
+  'ri_triggers.c',
+  'rowtypes.c',
+  'ruleutils.c',
+  'selfuncs.c',
+  'tid.c',
+  'timestamp.c',
+  'trigfuncs.c',
+  'tsginidx.c',
+  'tsgistidx.c',
+  'tsquery.c',
+  'tsquery_cleanup.c',
+  'tsquery_gist.c',
+  'tsquery_op.c',
+  'tsquery_rewrite.c',
+  'tsquery_util.c',
+  'tsrank.c',
+  'tsvector.c',
+  'tsvector_op.c',
+  'tsvector_parser.c',
+  'uuid.c',
+  'varbit.c',
+  'varchar.c',
+  'varlena.c',
+  'version.c',
+  'windowfuncs.c',
+  'xid.c',
+  'xid8funcs.c',
+  'xml.c',
+)
+
+
+jsonpath_scan = custom_target('jsonpath_scan',
+  input: 'jsonpath_scan.l',
+  output: 'jsonpath_scan.c',
+  command: [flex_cmd, '--no-backup', '--', '-CF', '-p', '-p'],
+)
+generated_sources += jsonpath_scan
+
+jsonpath_gram = custom_target('jsonpath_parse',
+  input: 'jsonpath_gram.y',
+  kwargs: bison_kw,
+)
+generated_sources += jsonpath_gram.to_list()
+
+# so we don't need to add . as an include dir for the whole backend
+backend_link_with += static_library('jsonpath',
+  jsonpath_scan, jsonpath_gram,
+  dependencies: [backend_code],
+  include_directories: include_directories('.'),
+  kwargs: internal_lib_args,
+)
+
+#generated_backend_sources += jsonpath_gram.to_list()
diff --git a/src/backend/utils/cache/meson.build b/src/backend/utils/cache/meson.build
new file mode 100644
index 00000000000..4fe6db6bda6
--- /dev/null
+++ b/src/backend/utils/cache/meson.build
@@ -0,0 +1,16 @@
+backend_sources += files(
+  'attoptcache.c',
+  'catcache.c',
+  'evtcache.c',
+  'inval.c',
+  'lsyscache.c',
+  'partcache.c',
+  'plancache.c',
+  'relcache.c',
+  'relfilenumbermap.c',
+  'relmapper.c',
+  'spccache.c',
+  'syscache.c',
+  'ts_cache.c',
+  'typcache.c',
+)
diff --git a/src/backend/utils/error/meson.build b/src/backend/utils/error/meson.build
new file mode 100644
index 00000000000..325446c8f93
--- /dev/null
+++ b/src/backend/utils/error/meson.build
@@ -0,0 +1,6 @@
+backend_sources += files(
+  'assert.c',
+  'csvlog.c',
+  'elog.c',
+  'jsonlog.c',
+)
diff --git a/src/backend/utils/fmgr/meson.build b/src/backend/utils/fmgr/meson.build
new file mode 100644
index 00000000000..e545b424fd2
--- /dev/null
+++ b/src/backend/utils/fmgr/meson.build
@@ -0,0 +1,8 @@
+backend_sources += files(
+  'dfmgr.c',
+  'fmgr.c',
+  'funcapi.c',
+)
+
+# fmgrtab.c
+generated_backend_sources += fmgrtab_target[2]
diff --git a/src/backend/utils/hash/meson.build b/src/backend/utils/hash/meson.build
new file mode 100644
index 00000000000..242e2f0ecdf
--- /dev/null
+++ b/src/backend/utils/hash/meson.build
@@ -0,0 +1,4 @@
+backend_sources += files(
+  'dynahash.c',
+  'pg_crc.c'
+)
diff --git a/src/backend/utils/init/meson.build b/src/backend/utils/init/meson.build
new file mode 100644
index 00000000000..ec9d72c3df1
--- /dev/null
+++ b/src/backend/utils/init/meson.build
@@ -0,0 +1,4 @@
+backend_sources += files(
+  'globals.c',
+  'miscinit.c',
+  'postinit.c')
diff --git a/src/backend/utils/mb/conversion_procs/meson.build b/src/backend/utils/mb/conversion_procs/meson.build
new file mode 100644
index 00000000000..1bc971d1945
--- /dev/null
+++ b/src/backend/utils/mb/conversion_procs/meson.build
@@ -0,0 +1,36 @@
+encodings = {
+  'cyrillic_and_mic': ['cyrillic_and_mic/cyrillic_and_mic.c'],
+  'euc2004_sjis2004': ['euc2004_sjis2004/euc2004_sjis2004.c'],
+  'euc_cn_and_mic': ['euc_cn_and_mic/euc_cn_and_mic.c'],
+  'euc_jp_and_sjis': ['euc_jp_and_sjis/euc_jp_and_sjis.c'],
+  'euc_kr_and_mic': ['euc_kr_and_mic/euc_kr_and_mic.c'],
+  'euc_tw_and_big5': [
+    'euc_tw_and_big5/euc_tw_and_big5.c',
+    'euc_tw_and_big5/big5.c',
+  ],
+  'latin2_and_win1250': ['latin2_and_win1250/latin2_and_win1250.c'],
+  'latin_and_mic': ['latin_and_mic/latin_and_mic.c'],
+  'utf8_and_big5': ['utf8_and_big5/utf8_and_big5.c'],
+  'utf8_and_cyrillic': ['utf8_and_cyrillic/utf8_and_cyrillic.c'],
+  'utf8_and_euc2004': ['utf8_and_euc2004/utf8_and_euc2004.c'],
+  'utf8_and_euc_cn': ['utf8_and_euc_cn/utf8_and_euc_cn.c'],
+  'utf8_and_euc_jp': ['utf8_and_euc_jp/utf8_and_euc_jp.c'],
+  'utf8_and_euc_kr': ['utf8_and_euc_kr/utf8_and_euc_kr.c'],
+  'utf8_and_euc_tw': ['utf8_and_euc_tw/utf8_and_euc_tw.c'],
+  'utf8_and_gb18030': ['utf8_and_gb18030/utf8_and_gb18030.c'],
+  'utf8_and_gbk': ['utf8_and_gbk/utf8_and_gbk.c'],
+  'utf8_and_iso8859': ['utf8_and_iso8859/utf8_and_iso8859.c'],
+  'utf8_and_iso8859_1': ['utf8_and_iso8859_1/utf8_and_iso8859_1.c'],
+  'utf8_and_johab': ['utf8_and_johab/utf8_and_johab.c'],
+  'utf8_and_sjis': ['utf8_and_sjis/utf8_and_sjis.c'],
+  'utf8_and_sjis2004': ['utf8_and_sjis2004/utf8_and_sjis2004.c'],
+  'utf8_and_uhc': ['utf8_and_uhc/utf8_and_uhc.c'],
+  'utf8_and_win': ['utf8_and_win/utf8_and_win.c'],
+}
+
+foreach encoding, sources : encodings
+  backend_targets += shared_module(encoding,
+    sources,
+    kwargs: pg_mod_args,
+  )
+endforeach
diff --git a/src/backend/utils/mb/meson.build b/src/backend/utils/mb/meson.build
new file mode 100644
index 00000000000..39e45638db0
--- /dev/null
+++ b/src/backend/utils/mb/meson.build
@@ -0,0 +1,9 @@
+backend_sources += files(
+  'conv.c',
+  'mbutils.c',
+  'stringinfo_mb.c',
+  'wstrcmp.c',
+  'wstrncmp.c',
+)
+
+# Note we only enter conversion_procs once the backend build is defined
diff --git a/src/backend/utils/meson.build b/src/backend/utils/meson.build
new file mode 100644
index 00000000000..3a916320bb3
--- /dev/null
+++ b/src/backend/utils/meson.build
@@ -0,0 +1,17 @@
+install_data('errcodes.txt',
+  install_dir: dir_data,
+)
+
+subdir('activity')
+subdir('adt')
+subdir('cache')
+subdir('error')
+subdir('fmgr')
+subdir('hash')
+subdir('init')
+subdir('mb')
+subdir('misc')
+subdir('mmgr')
+subdir('resowner')
+subdir('sort')
+subdir('time')
diff --git a/src/backend/utils/misc/meson.build b/src/backend/utils/misc/meson.build
new file mode 100644
index 00000000000..db4de225e18
--- /dev/null
+++ b/src/backend/utils/misc/meson.build
@@ -0,0 +1,35 @@
+backend_sources += files(
+  'guc.c',
+  'guc_funcs.c',
+  'guc_tables.c',
+  'help_config.c',
+  'pg_config.c',
+  'pg_controldata.c',
+  'pg_rusage.c',
+  'ps_status.c',
+  'queryenvironment.c',
+  'queryjumble.c',
+  'rls.c',
+  'sampling.c',
+  'superuser.c',
+  'timeout.c',
+  'tzparser.c',
+)
+
+guc_scan = custom_target('guc_scan',
+  input: 'guc-file.l',
+  output: 'guc-file.c',
+  command: flex_cmd)
+generated_sources += guc_scan
+
+# so we don't need to add . as an include dir for the whole backend
+backend_link_with += static_library('guc-file',
+  guc_scan,
+  dependencies: [backend_code],
+  include_directories: include_directories('.'),
+  kwargs: internal_lib_args,
+)
+
+install_data('postgresql.conf.sample',
+  install_dir: dir_data,
+)
diff --git a/src/backend/utils/mmgr/meson.build b/src/backend/utils/mmgr/meson.build
new file mode 100644
index 00000000000..641bb181ba1
--- /dev/null
+++ b/src/backend/utils/mmgr/meson.build
@@ -0,0 +1,10 @@
+backend_sources += files(
+  'aset.c',
+  'dsa.c',
+  'freepage.c',
+  'generation.c',
+  'mcxt.c',
+  'memdebug.c',
+  'portalmem.c',
+  'slab.c',
+)
diff --git a/src/backend/utils/resowner/meson.build b/src/backend/utils/resowner/meson.build
new file mode 100644
index 00000000000..d30891ca027
--- /dev/null
+++ b/src/backend/utils/resowner/meson.build
@@ -0,0 +1,3 @@
+backend_sources += files(
+  'resowner.c'
+)
diff --git a/src/backend/utils/sort/meson.build b/src/backend/utils/sort/meson.build
new file mode 100644
index 00000000000..1862ceae8c1
--- /dev/null
+++ b/src/backend/utils/sort/meson.build
@@ -0,0 +1,9 @@
+backend_sources += files(
+  'logtape.c',
+  'qsort_interruptible.c',
+  'sharedtuplestore.c',
+  'sortsupport.c',
+  'tuplesort.c',
+  'tuplesortvariants.c',
+  'tuplestore.c',
+)
diff --git a/src/backend/utils/time/meson.build b/src/backend/utils/time/meson.build
new file mode 100644
index 00000000000..6fff8792bb0
--- /dev/null
+++ b/src/backend/utils/time/meson.build
@@ -0,0 +1,4 @@
+backend_sources += files(
+  'combocid.c',
+  'snapmgr.c',
+)
diff --git a/src/fe_utils/meson.build b/src/fe_utils/meson.build
new file mode 100644
index 00000000000..b6bf8e1ca21
--- /dev/null
+++ b/src/fe_utils/meson.build
@@ -0,0 +1,29 @@
+fe_utils_sources = files(
+  'archive.c',
+  'cancel.c',
+  'conditional.c',
+  'connect_utils.c',
+  'mbprint.c',
+  'option_utils.c',
+  'parallel_slot.c',
+  'print.c',
+  'query_utils.c',
+  'recovery_gen.c',
+  'simple_list.c',
+  'string_utils.c',
+)
+
+psqlscan = custom_target('psqlscan',
+  input: 'psqlscan.l',
+  output: 'psqlscan.c',
+  command: [flex_cmd, '--no-backup', '--fix-warnings', '--', '-Cfe', '-p', '-p'],
+)
+generated_sources += psqlscan
+fe_utils_sources += psqlscan
+
+fe_utils = static_library('libpgfeutils',
+  fe_utils_sources + generated_headers,
+  include_directories: [postgres_inc, libpq_inc],
+  dependencies: frontend_common_code,
+  kwargs: default_lib_args,
+)
diff --git a/src/bin/initdb/meson.build b/src/bin/initdb/meson.build
new file mode 100644
index 00000000000..9f213274d2f
--- /dev/null
+++ b/src/bin/initdb/meson.build
@@ -0,0 +1,30 @@
+initdb_sources = files(
+  'findtimezone.c',
+  'initdb.c'
+)
+
+initdb_sources += timezone_localtime_source
+
+#fixme: reimplement libpq_pgport logic
+
+initdb = executable('initdb',
+  initdb_sources,
+  include_directories: [timezone_inc],
+  dependencies: [frontend_code, libpq, icu, icu_i18n],
+  kwargs: default_bin_args,
+)
+bin_targets += initdb
+
+tests += {
+  'name': 'initdb',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'env': {'with_icu': icu.found() ? 'yes' : 'no'},
+    'tests': [
+      't/001_initdb.pl',
+    ],
+  },
+}
+
+subdir('po', if_found: libintl)
diff --git a/src/bin/initdb/po/meson.build b/src/bin/initdb/po/meson.build
new file mode 100644
index 00000000000..8b8a9fd2ce1
--- /dev/null
+++ b/src/bin/initdb/po/meson.build
@@ -0,0 +1 @@
+i18n.gettext('initdb-' + pg_version_major.to_string())
diff --git a/src/bin/meson.build b/src/bin/meson.build
new file mode 100644
index 00000000000..5fd5a9d2f98
--- /dev/null
+++ b/src/bin/meson.build
@@ -0,0 +1,20 @@
+subdir('initdb')
+subdir('pg_amcheck')
+subdir('pg_archivecleanup')
+subdir('pg_basebackup')
+subdir('pg_checksums')
+subdir('pg_config')
+subdir('pg_controldata')
+subdir('pg_ctl')
+subdir('pg_dump')
+subdir('pg_resetwal')
+subdir('pg_rewind')
+subdir('pg_test_fsync')
+subdir('pg_test_timing')
+subdir('pg_upgrade')
+subdir('pg_verifybackup')
+subdir('pg_waldump')
+subdir('pgbench')
+subdir('pgevent')
+subdir('psql')
+subdir('scripts')
diff --git a/src/bin/pg_amcheck/meson.build b/src/bin/pg_amcheck/meson.build
new file mode 100644
index 00000000000..8e197eba5f3
--- /dev/null
+++ b/src/bin/pg_amcheck/meson.build
@@ -0,0 +1,27 @@
+pg_amcheck_sources = files(
+  'pg_amcheck.c'
+)
+
+pg_amcheck = executable('pg_amcheck',
+  pg_amcheck_sources,
+  dependencies: [frontend_code, libpq],
+  kwargs: default_bin_args,
+)
+bin_targets += pg_amcheck
+
+tests += {
+  'name': 'pg_amcheck',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'tests': [
+      't/001_basic.pl',
+      't/002_nonesuch.pl',
+      't/003_check.pl',
+      't/004_verify_heapam.pl',
+      't/005_opclass_damage.pl',
+    ],
+  },
+}
+
+subdir('po', if_found: libintl)
diff --git a/src/bin/pg_amcheck/po/meson.build b/src/bin/pg_amcheck/po/meson.build
new file mode 100644
index 00000000000..b255f552c94
--- /dev/null
+++ b/src/bin/pg_amcheck/po/meson.build
@@ -0,0 +1 @@
+i18n.gettext('pg_amcheck-' + pg_version_major.to_string())
diff --git a/src/bin/pg_archivecleanup/meson.build b/src/bin/pg_archivecleanup/meson.build
new file mode 100644
index 00000000000..87a0d980c4f
--- /dev/null
+++ b/src/bin/pg_archivecleanup/meson.build
@@ -0,0 +1,19 @@
+pg_archivecleanup = executable('pg_archivecleanup',
+  ['pg_archivecleanup.c'],
+  dependencies: [frontend_code],
+  kwargs: default_bin_args,
+)
+bin_targets += pg_archivecleanup
+
+tests += {
+  'name': 'pg_archivecleanup',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'tests': [
+      't/010_pg_archivecleanup.pl',
+    ],
+  },
+}
+
+subdir('po', if_found: libintl)
diff --git a/src/bin/pg_archivecleanup/po/meson.build b/src/bin/pg_archivecleanup/po/meson.build
new file mode 100644
index 00000000000..37935fcabc4
--- /dev/null
+++ b/src/bin/pg_archivecleanup/po/meson.build
@@ -0,0 +1 @@
+i18n.gettext('pg_archivecleanup-' + pg_version_major.to_string())
diff --git a/src/bin/pg_basebackup/meson.build b/src/bin/pg_basebackup/meson.build
new file mode 100644
index 00000000000..d26fed9cd8a
--- /dev/null
+++ b/src/bin/pg_basebackup/meson.build
@@ -0,0 +1,61 @@
+common_sources = files(
+  'bbstreamer_file.c',
+  'bbstreamer_gzip.c',
+  'bbstreamer_inject.c',
+  'bbstreamer_lz4.c',
+  'bbstreamer_tar.c',
+  'bbstreamer_zstd.c',
+  'receivelog.c',
+  'streamutil.c',
+  'walmethods.c',
+)
+
+pg_basebackup_deps = [frontend_code, libpq, lz4, zlib, zstd]
+pg_basebackup_common = static_library('libpg_basebackup_common',
+  common_sources,
+  dependencies: pg_basebackup_deps,
+  kwargs: internal_lib_args,
+)
+
+pg_basebackup = executable('pg_basebackup',
+  'pg_basebackup.c',
+  link_with: [pg_basebackup_common],
+  dependencies: pg_basebackup_deps,
+  kwargs: default_bin_args,
+)
+bin_targets += pg_basebackup
+
+pg_receivewal = executable('pg_receivewal',
+  'pg_receivewal.c',
+  link_with: [pg_basebackup_common],
+  dependencies: pg_basebackup_deps,
+  kwargs: default_bin_args,
+)
+bin_targets += pg_receivewal
+
+pg_recvlogical = executable('pg_recvlogical',
+  'pg_recvlogical.c',
+  link_with: [pg_basebackup_common],
+  dependencies: pg_basebackup_deps,
+  kwargs: default_bin_args,
+)
+bin_targets += pg_recvlogical
+
+tests += {
+  'name': 'pg_basebackup',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'env': {'GZIP_PROGRAM': gzip.path(),
+            'TAR': tar.path(),
+            'LZ4': program_lz4.found() ? program_lz4.path() : '',
+            'ZSTD': program_zstd.found() ? program_zstd.path() : ''},
+    'tests': [
+      't/010_pg_basebackup.pl',
+      't/020_pg_receivewal.pl',
+      't/030_pg_recvlogical.pl',
+    ],
+  },
+}
+
+subdir('po', if_found: libintl)
diff --git a/src/bin/pg_basebackup/po/meson.build b/src/bin/pg_basebackup/po/meson.build
new file mode 100644
index 00000000000..cab021153fe
--- /dev/null
+++ b/src/bin/pg_basebackup/po/meson.build
@@ -0,0 +1 @@
+i18n.gettext('pg_basebackup-' + pg_version_major.to_string())
diff --git a/src/bin/pg_checksums/meson.build b/src/bin/pg_checksums/meson.build
new file mode 100644
index 00000000000..ee1f367bac3
--- /dev/null
+++ b/src/bin/pg_checksums/meson.build
@@ -0,0 +1,21 @@
+pg_checksums = executable('pg_checksums',
+  ['pg_checksums.c'],
+  include_directories: [timezone_inc],
+  dependencies: [frontend_code],
+  kwargs: default_bin_args,
+)
+bin_targets += pg_checksums
+
+tests += {
+  'name': 'pg_checksums',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'tests': [
+      't/001_basic.pl',
+      't/002_actions.pl',
+    ],
+  },
+}
+
+subdir('po', if_found: libintl)
diff --git a/src/bin/pg_checksums/po/meson.build b/src/bin/pg_checksums/po/meson.build
new file mode 100644
index 00000000000..2c47c2338f6
--- /dev/null
+++ b/src/bin/pg_checksums/po/meson.build
@@ -0,0 +1 @@
+i18n.gettext('pg_checksums-' + pg_version_major.to_string())
diff --git a/src/bin/pg_config/meson.build b/src/bin/pg_config/meson.build
new file mode 100644
index 00000000000..0ecbf2f9d28
--- /dev/null
+++ b/src/bin/pg_config/meson.build
@@ -0,0 +1,19 @@
+pg_config = executable('pg_config',
+  ['pg_config.c'],
+  dependencies: [frontend_code],
+  kwargs: default_bin_args,
+)
+bin_targets += pg_config
+
+tests += {
+  'name': 'pg_config',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'tests': [
+      't/001_pg_config.pl',
+    ],
+  },
+}
+
+subdir('po', if_found: libintl)
diff --git a/src/bin/pg_config/po/meson.build b/src/bin/pg_config/po/meson.build
new file mode 100644
index 00000000000..b6fb6db9213
--- /dev/null
+++ b/src/bin/pg_config/po/meson.build
@@ -0,0 +1 @@
+i18n.gettext('pg_config-' + pg_version_major.to_string())
diff --git a/src/bin/pg_controldata/meson.build b/src/bin/pg_controldata/meson.build
new file mode 100644
index 00000000000..557e672beb7
--- /dev/null
+++ b/src/bin/pg_controldata/meson.build
@@ -0,0 +1,19 @@
+pg_controldata = executable('pg_controldata',
+  ['pg_controldata.c'],
+  dependencies: [frontend_code],
+  kwargs: default_bin_args,
+)
+bin_targets += pg_controldata
+
+tests += {
+  'name': 'pg_controldata',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'tests': [
+      't/001_pg_controldata.pl',
+    ],
+  },
+}
+
+subdir('po', if_found: libintl)
diff --git a/src/bin/pg_controldata/po/meson.build b/src/bin/pg_controldata/po/meson.build
new file mode 100644
index 00000000000..31b486d002c
--- /dev/null
+++ b/src/bin/pg_controldata/po/meson.build
@@ -0,0 +1 @@
+i18n.gettext('pg_controldata-' + pg_version_major.to_string())
diff --git a/src/bin/pg_ctl/meson.build b/src/bin/pg_ctl/meson.build
new file mode 100644
index 00000000000..6812e73e329
--- /dev/null
+++ b/src/bin/pg_ctl/meson.build
@@ -0,0 +1,22 @@
+pg_ctl = executable('pg_ctl',
+  ['pg_ctl.c'],
+  dependencies: [frontend_code, libpq],
+  kwargs: default_bin_args,
+)
+bin_targets += pg_ctl
+
+tests += {
+  'name': 'pg_ctl',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'tests': [
+      't/001_start_stop.pl',
+      't/002_status.pl',
+      't/003_promote.pl',
+      't/004_logrotate.pl',
+    ],
+  },
+}
+
+subdir('po', if_found: libintl)
diff --git a/src/bin/pg_ctl/po/meson.build b/src/bin/pg_ctl/po/meson.build
new file mode 100644
index 00000000000..947b5108423
--- /dev/null
+++ b/src/bin/pg_ctl/po/meson.build
@@ -0,0 +1 @@
+i18n.gettext('pg_ctl-' + pg_version_major.to_string())
diff --git a/src/bin/pg_dump/meson.build b/src/bin/pg_dump/meson.build
new file mode 100644
index 00000000000..785ec094dbd
--- /dev/null
+++ b/src/bin/pg_dump/meson.build
@@ -0,0 +1,75 @@
+pg_dump_common_sources = files(
+  'compress_io.c',
+  'dumputils.c',
+  'parallel.c',
+  'pg_backup_archiver.c',
+  'pg_backup_custom.c',
+  'pg_backup_db.c',
+  'pg_backup_directory.c',
+  'pg_backup_null.c',
+  'pg_backup_tar.c',
+  'pg_backup_utils.c',
+)
+
+pg_dump_common = static_library('libpgdump_common',
+  pg_dump_common_sources,
+  dependencies: [frontend_code, libpq, zlib],
+  kwargs: internal_lib_args,
+)
+
+
+pg_dump_sources = files(
+  'common.c',
+  'pg_dump.c',
+  'pg_dump_sort.c',
+)
+
+pg_dump = executable('pg_dump',
+  pg_dump_sources,
+  link_with: [pg_dump_common],
+  dependencies: [frontend_code, libpq, zlib],
+  kwargs: default_bin_args,
+)
+bin_targets += pg_dump
+
+
+pg_dumpall_sources = files(
+  'pg_dumpall.c',
+)
+
+pg_dumpall = executable('pg_dumpall',
+  pg_dumpall_sources,
+  link_with: [pg_dump_common],
+  dependencies: [frontend_code, libpq, zlib],
+  kwargs: default_bin_args,
+)
+bin_targets += pg_dumpall
+
+
+pg_restore_sources = files(
+  'pg_restore.c',
+)
+
+pg_restore = executable('pg_restore',
+  pg_restore_sources,
+  link_with: [pg_dump_common],
+  dependencies: [frontend_code, libpq, zlib],
+  kwargs: default_bin_args,
+)
+bin_targets += pg_restore
+
+tests += {
+  'name': 'pg_dump',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'tests': [
+      't/001_basic.pl',
+      't/002_pg_dump.pl',
+      't/003_pg_dump_with_server.pl',
+      't/010_dump_connstr.pl',
+    ],
+  },
+}
+
+subdir('po', if_found: libintl)
diff --git a/src/bin/pg_dump/po/meson.build b/src/bin/pg_dump/po/meson.build
new file mode 100644
index 00000000000..82e5e537ff4
--- /dev/null
+++ b/src/bin/pg_dump/po/meson.build
@@ -0,0 +1 @@
+i18n.gettext('pg_dump-' + pg_version_major.to_string())
diff --git a/src/bin/pg_resetwal/meson.build b/src/bin/pg_resetwal/meson.build
new file mode 100644
index 00000000000..7c5de134ac0
--- /dev/null
+++ b/src/bin/pg_resetwal/meson.build
@@ -0,0 +1,20 @@
+pg_resetwal = executable('pg_resetwal',
+  files('pg_resetwal.c'),
+  dependencies: [frontend_code],
+  kwargs: default_bin_args,
+)
+bin_targets += pg_resetwal
+
+tests += {
+  'name': 'pg_resetwal',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'tests': [
+      't/001_basic.pl',
+      't/002_corrupted.pl',
+    ],
+  },
+}
+
+subdir('po', if_found: libintl)
diff --git a/src/bin/pg_resetwal/po/meson.build b/src/bin/pg_resetwal/po/meson.build
new file mode 100644
index 00000000000..d130d3b775f
--- /dev/null
+++ b/src/bin/pg_resetwal/po/meson.build
@@ -0,0 +1 @@
+i18n.gettext('pg_resetwal-' + pg_version_major.to_string())
diff --git a/src/bin/pg_rewind/meson.build b/src/bin/pg_rewind/meson.build
new file mode 100644
index 00000000000..d8ec9e482d5
--- /dev/null
+++ b/src/bin/pg_rewind/meson.build
@@ -0,0 +1,42 @@
+pg_rewind_sources = files(
+  'datapagemap.c',
+  'file_ops.c',
+  'filemap.c',
+  'libpq_source.c',
+  'local_source.c',
+  'parsexlog.c',
+  'pg_rewind.c',
+  'timeline.c',
+)
+
+pg_rewind_sources += xlogreader_sources
+
+pg_rewind = executable('pg_rewind',
+  pg_rewind_sources,
+  dependencies: [frontend_code, libpq, lz4, zstd],
+  c_args: ['-DFRONTEND'], # needed for xlogreader et al
+  kwargs: default_bin_args,
+)
+bin_targets += pg_rewind
+
+
+tests += {
+  'name': 'pg_rewind',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'tests': [
+      't/001_basic.pl',
+      't/002_databases.pl',
+      't/003_extrafiles.pl',
+      't/004_pg_xlog_symlink.pl',
+      't/005_same_timeline.pl',
+      't/006_options.pl',
+      't/007_standby_source.pl',
+      't/008_min_recovery_point.pl',
+      't/009_growing_files.pl',
+    ],
+  },
+}
+
+subdir('po', if_found: libintl)
diff --git a/src/bin/pg_rewind/po/meson.build b/src/bin/pg_rewind/po/meson.build
new file mode 100644
index 00000000000..a105600b348
--- /dev/null
+++ b/src/bin/pg_rewind/po/meson.build
@@ -0,0 +1 @@
+i18n.gettext('pg_rewind-' + pg_version_major.to_string())
diff --git a/src/bin/pg_test_fsync/meson.build b/src/bin/pg_test_fsync/meson.build
new file mode 100644
index 00000000000..2c01831e11f
--- /dev/null
+++ b/src/bin/pg_test_fsync/meson.build
@@ -0,0 +1,21 @@
+test_fsync_sources = files('pg_test_fsync.c')
+
+pg_test_fsync = executable('pg_test_fsync',
+  test_fsync_sources,
+  dependencies: [frontend_code],
+  kwargs: default_bin_args,
+)
+bin_targets += pg_test_fsync
+
+tests += {
+  'name': 'pg_test_fsync',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'tests': [
+      't/001_basic.pl',
+    ],
+  },
+}
+
+subdir('po', if_found: libintl)
diff --git a/src/bin/pg_test_fsync/po/meson.build b/src/bin/pg_test_fsync/po/meson.build
new file mode 100644
index 00000000000..2ee1125282d
--- /dev/null
+++ b/src/bin/pg_test_fsync/po/meson.build
@@ -0,0 +1 @@
+i18n.gettext('pg_test_fsync-' + pg_version_major.to_string())
diff --git a/src/bin/pg_test_timing/meson.build b/src/bin/pg_test_timing/meson.build
new file mode 100644
index 00000000000..0a3068f1657
--- /dev/null
+++ b/src/bin/pg_test_timing/meson.build
@@ -0,0 +1,19 @@
+pg_test_timing = executable('pg_test_timing',
+  ['pg_test_timing.c'],
+  dependencies: [frontend_code],
+  kwargs: default_bin_args,
+)
+bin_targets += pg_test_timing
+
+tests += {
+  'name': 'pg_test_timing',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'tests': [
+      't/001_basic.pl',
+    ],
+  },
+}
+
+subdir('po', if_found: libintl)
diff --git a/src/bin/pg_test_timing/po/meson.build b/src/bin/pg_test_timing/po/meson.build
new file mode 100644
index 00000000000..cda8615165b
--- /dev/null
+++ b/src/bin/pg_test_timing/po/meson.build
@@ -0,0 +1 @@
+i18n.gettext('pg_test_timing-' + pg_version_major.to_string())
diff --git a/src/bin/pg_upgrade/meson.build b/src/bin/pg_upgrade/meson.build
new file mode 100644
index 00000000000..02f030e0ccf
--- /dev/null
+++ b/src/bin/pg_upgrade/meson.build
@@ -0,0 +1,40 @@
+pg_upgrade_sources = files(
+  'check.c',
+  'controldata.c',
+  'dump.c',
+  'exec.c',
+  'file.c',
+  'function.c',
+  'info.c',
+  'option.c',
+  'parallel.c',
+  'pg_upgrade.c',
+  'relfilenumber.c',
+  'server.c',
+  'tablespace.c',
+  'util.c',
+  'version.c',
+)
+
+pg_upgrade = executable('pg_upgrade',
+  pg_upgrade_sources,
+  dependencies: [frontend_code, libpq],
+  kwargs: default_bin_args,
+)
+bin_targets += pg_upgrade
+
+
+tests += {
+  'name': 'pg_upgrade',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'tests': [
+      't/001_basic.pl',
+      't/002_pg_upgrade.pl',
+    ],
+    'test_kwargs': {'priority': 40}, # pg_upgrade tests are slow
+  },
+}
+
+subdir('po', if_found: libintl)
diff --git a/src/bin/pg_upgrade/po/meson.build b/src/bin/pg_upgrade/po/meson.build
new file mode 100644
index 00000000000..39301cbede8
--- /dev/null
+++ b/src/bin/pg_upgrade/po/meson.build
@@ -0,0 +1 @@
+i18n.gettext('pg_upgrade-' + pg_version_major.to_string())
diff --git a/src/bin/pg_verifybackup/meson.build b/src/bin/pg_verifybackup/meson.build
new file mode 100644
index 00000000000..4c3b2bb5f97
--- /dev/null
+++ b/src/bin/pg_verifybackup/meson.build
@@ -0,0 +1,33 @@
+pg_verifybackup_sources = files(
+  'parse_manifest.c',
+  'pg_verifybackup.c'
+)
+
+pg_verifybackup = executable('pg_verifybackup',
+  pg_verifybackup_sources,
+  dependencies: [frontend_code, libpq],
+  kwargs: default_bin_args,
+)
+bin_targets += pg_verifybackup
+
+tests += {
+  'name': 'pg_verifybackup',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'tests': [
+      't/001_basic.pl',
+      't/002_algorithm.pl',
+      't/003_corruption.pl',
+      't/004_options.pl',
+      't/005_bad_manifest.pl',
+      't/006_encoding.pl',
+      't/007_wal.pl',
+      't/008_untar.pl',
+      't/009_extract.pl',
+      't/010_client_untar.pl',
+    ],
+  },
+}
+
+subdir('po', if_found: libintl)
diff --git a/src/bin/pg_verifybackup/po/meson.build b/src/bin/pg_verifybackup/po/meson.build
new file mode 100644
index 00000000000..b583f1958ba
--- /dev/null
+++ b/src/bin/pg_verifybackup/po/meson.build
@@ -0,0 +1 @@
+i18n.gettext('pg_verifybackup-' + pg_version_major.to_string())
diff --git a/src/bin/pg_waldump/meson.build b/src/bin/pg_waldump/meson.build
new file mode 100644
index 00000000000..95872652ffd
--- /dev/null
+++ b/src/bin/pg_waldump/meson.build
@@ -0,0 +1,30 @@
+pg_waldump_sources = files(
+  'compat.c',
+  'pg_waldump.c',
+  'rmgrdesc.c',
+)
+
+pg_waldump_sources += rmgr_desc_sources
+pg_waldump_sources += xlogreader_sources
+pg_waldump_sources += files('../../backend/access/transam/xlogstats.c')
+
+pg_waldump = executable('pg_waldump',
+  pg_waldump_sources,
+  dependencies: [frontend_code, lz4, zstd],
+  c_args: ['-DFRONTEND'], # needed for xlogreader et al
+  kwargs: default_bin_args,
+)
+bin_targets += pg_waldump
+
+tests += {
+  'name': 'pg_waldump',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'tests': [
+      't/001_basic.pl',
+    ],
+  },
+}
+
+subdir('po', if_found: libintl)
diff --git a/src/bin/pg_waldump/po/meson.build b/src/bin/pg_waldump/po/meson.build
new file mode 100644
index 00000000000..f335aa4b360
--- /dev/null
+++ b/src/bin/pg_waldump/po/meson.build
@@ -0,0 +1 @@
+i18n.gettext('pg_waldump-' + pg_version_major.to_string())
diff --git a/src/bin/pgbench/meson.build b/src/bin/pgbench/meson.build
new file mode 100644
index 00000000000..6564e54029c
--- /dev/null
+++ b/src/bin/pgbench/meson.build
@@ -0,0 +1,38 @@
+pgbench_sources = files(
+  'pgbench.c',
+)
+
+exprscan = custom_target('exprscan',
+  input: 'exprscan.l',
+  output: 'exprscan.c',
+  command: flex_cmd,
+)
+generated_sources += exprscan
+pgbench_sources += exprscan
+
+exprparse = custom_target('exprparse',
+  input: 'exprparse.y',
+  kwargs: bison_kw,
+)
+generated_sources += exprparse.to_list()
+pgbench_sources += exprparse
+
+pgbench = executable('pgbench',
+  pgbench_sources,
+  dependencies: [frontend_code, libpq, thread_dep],
+  include_directories: include_directories('.'),
+  kwargs: default_bin_args,
+)
+bin_targets += pgbench
+
+tests += {
+  'name': 'pgbench',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'tests': [
+      't/001_pgbench_with_server.pl',
+      't/002_pgbench_no_server.pl',
+    ],
+  },
+}
diff --git a/src/bin/pgevent/meson.build b/src/bin/pgevent/meson.build
new file mode 100644
index 00000000000..5852bca4d87
--- /dev/null
+++ b/src/bin/pgevent/meson.build
@@ -0,0 +1,26 @@
+if host_system != 'windows'
+  subdir_done()
+endif
+
+pgevent_sources = files(
+  'pgevent.c',
+)
+
+pgevent_sources += windows.compile_resources('pgmsgevent.rc')
+
+# FIXME: copied from Mkvcbuild.pm, but I don't think that's the right approach
+pgevent_link_args = []
+if cc.get_id() == 'msvc'
+  pgevent_link_args += '/ignore:4104'
+endif
+
+pgevent = shared_library('pgevent',
+  pgevent_sources,
+  dependencies: [frontend_code],
+  link_args: pgevent_link_args,
+  vs_module_defs: 'pgevent.def',
+  kwargs: default_lib_args + {
+    'name_prefix': '',
+  },
+)
+bin_targets += pgevent
diff --git a/src/bin/psql/meson.build b/src/bin/psql/meson.build
new file mode 100644
index 00000000000..ea850c8fdf5
--- /dev/null
+++ b/src/bin/psql/meson.build
@@ -0,0 +1,67 @@
+psql_sources = files(
+  'command.c',
+  'common.c',
+  'copy.c',
+  'crosstabview.c',
+  'describe.c',
+  'help.c',
+  'input.c',
+  'large_obj.c',
+  'mainloop.c',
+  'prompt.c',
+  'startup.c',
+  'stringutils.c',
+  'tab-complete.c',
+  'variables.c',
+)
+
+psqlscanslash = custom_target('psqlscanslash',
+  input: 'psqlscanslash.l',
+  output: 'psqlscanslash.c',
+  command: [flex_cmd, '--no-backup', '--fix-warnings', '--', '-Cfe', '-p', '-p'])
+generated_sources += psqlscanslash
+psql_sources += psqlscanslash
+bin_targets += psqlscanslash
+
+sql_help = custom_target('psql_help',
+  output: ['sql_help.c', 'sql_help.h'],
+  depfile: 'sql_help.dep',
+  command: [
+    perl, files('create_help.pl'),
+    '--docdir', '@SOURCE_ROOT@/doc/src/sgml/ref',
+    '--depfile', '@DEPFILE@',
+    '--outdir', '@OUTDIR@',
+    '--basename', 'sql_help',
+  ],
+)
+generated_sources += sql_help.to_list()
+psql_sources += sql_help
+bin_targets += sql_help
+
+psql = executable('psql',
+  psql_sources,
+  include_directories: include_directories('.'),
+  dependencies: [frontend_code, libpq, readline],
+  kwargs: default_bin_args,
+)
+bin_targets += psql
+
+install_data('psqlrc.sample',
+  install_dir: dir_data,
+)
+
+tests += {
+  'name': 'psql',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'env': {'with_readline': readline.found() ? 'yes' : 'no'},
+    'tests': [
+      't/001_basic.pl',
+      't/010_tab_completion.pl',
+      't/020_cancel.pl',
+    ],
+  },
+}
+
+subdir('po', if_found: libintl)
diff --git a/src/bin/psql/po/meson.build b/src/bin/psql/po/meson.build
new file mode 100644
index 00000000000..45fe425298d
--- /dev/null
+++ b/src/bin/psql/po/meson.build
@@ -0,0 +1 @@
+i18n.gettext('psql-' + pg_version_major.to_string())
diff --git a/src/bin/scripts/meson.build b/src/bin/scripts/meson.build
new file mode 100644
index 00000000000..eaf250c7f73
--- /dev/null
+++ b/src/bin/scripts/meson.build
@@ -0,0 +1,51 @@
+scripts_common = static_library('libscripts_common',
+  files('common.c'),
+  dependencies: [frontend_code, libpq],
+  kwargs: internal_lib_args,
+)
+
+binaries = [
+  'createdb',
+  'dropdb',
+  'createuser',
+  'dropuser',
+  'clusterdb',
+  'vacuumdb',
+  'reindexdb',
+  'pg_isready',
+]
+
+foreach binary : binaries
+  binary = executable(binary,
+    files(binary + '.c'),
+    link_with: [scripts_common],
+    dependencies: [frontend_code, libpq],
+    kwargs: default_bin_args,
+  )
+  bin_targets += binary
+endforeach
+
+tests += {
+  'name': 'scripts',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'tests': [
+      't/010_clusterdb.pl',
+      't/011_clusterdb_all.pl',
+      't/020_createdb.pl',
+      't/040_createuser.pl',
+      't/050_dropdb.pl',
+      't/070_dropuser.pl',
+      't/080_pg_isready.pl',
+      't/090_reindexdb.pl',
+      't/091_reindexdb_all.pl',
+      't/100_vacuumdb.pl',
+      't/101_vacuumdb_all.pl',
+      't/102_vacuumdb_stages.pl',
+      't/200_connstr.pl',
+    ],
+  },
+}
+
+subdir('po', if_found: libintl)
diff --git a/src/bin/scripts/po/meson.build b/src/bin/scripts/po/meson.build
new file mode 100644
index 00000000000..3c531459c2d
--- /dev/null
+++ b/src/bin/scripts/po/meson.build
@@ -0,0 +1 @@
+i18n.gettext('pgscripts-' + pg_version_major.to_string())
diff --git a/src/interfaces/libpq/meson.build b/src/interfaces/libpq/meson.build
new file mode 100644
index 00000000000..bc047e00d62
--- /dev/null
+++ b/src/interfaces/libpq/meson.build
@@ -0,0 +1,108 @@
+# test/ is entered via top-level meson.build, that way it can use the default
+# args for executables (which depend on libpq).
+
+libpq_sources = files(
+  'fe-auth-scram.c',
+  'fe-auth.c',
+  'fe-connect.c',
+  'fe-exec.c',
+  'fe-lobj.c',
+  'fe-misc.c',
+  'fe-print.c',
+  'fe-protocol3.c',
+  'fe-secure.c',
+  'fe-trace.c',
+  'legacy-pqsignal.c',
+  'libpq-events.c',
+  'pqexpbuffer.c',
+)
+
+if host_system == 'windows'
+  libpq_sources += files('pthread-win32.c', 'win32.c')
+endif
+
+if ssl.found()
+  libpq_sources += files('fe-secure-common.c')
+  libpq_sources += files('fe-secure-openssl.c')
+endif
+
+if gssapi.found()
+  libpq_sources += files(
+    'fe-gssapi-common.c',
+    'fe-secure-gssapi.c',
+  )
+endif
+
+export_file = custom_target('libpq.exports',
+  kwargs: gen_export_kwargs,
+)
+
+# port needs to be in include path due to pthread-win32.h
+libpq_inc = include_directories('.', '../../port')
+
+libpq_st = static_library('libpq',
+  libpq_sources,
+  pic: true,
+  include_directories: [libpq_inc, postgres_inc],
+  c_args: ['-DSO_MAJOR_VERSION=5'],
+  dependencies: libpq_deps,
+  kwargs: default_lib_args,
+)
+
+# not using both_libraries here, causes problems with precompiled headers and
+# resource files with msbuild
+libpq_so = shared_library('libpq',
+  dependencies: libpq_deps,
+  include_directories: [libpq_inc, postgres_inc],
+  c_args: ['-DSO_MAJOR_VERSION=5'],
+  link_whole: libpq_st,
+  version: '5.' + pg_version_major.to_string(),
+  soversion: host_system != 'windows' ? '5' : '',
+  darwin_versions: ['5', '5.' + pg_version_major.to_string()],
+  link_depends: export_file,
+  link_args: export_fmt.format(export_file.full_path()),
+  kwargs: default_lib_args,
+)
+
+libpq = declare_dependency(
+  link_with: [libpq_so],
+  include_directories: [include_directories('.')]
+)
+
+pkgconfig.generate(
+  libpq_so,
+  name: 'libpq',
+  description: 'PostgreSQL libpq library',
+  url: pg_url,
+)
+
+install_headers(
+  'libpq-fe.h',
+  'libpq-events.h',
+)
+
+install_headers(
+  'libpq-int.h',
+  'pqexpbuffer.h',
+  'fe-auth-sasl.h',
+  install_dir: dir_include_internal,
+)
+install_data('pg_service.conf.sample',
+  install_dir: dir_data,
+)
+
+
+tests += {
+  'name': 'libpq',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'tests': [
+      't/001_uri.pl',
+      't/002_api.pl',
+    ],
+    'env': {'with_ssl': get_option('ssl')},
+  },
+}
+
+subdir('po', if_found: libintl)
diff --git a/src/interfaces/libpq/po/meson.build b/src/interfaces/libpq/po/meson.build
new file mode 100644
index 00000000000..eed91110fd6
--- /dev/null
+++ b/src/interfaces/libpq/po/meson.build
@@ -0,0 +1 @@
+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
new file mode 100644
index 00000000000..16f94c1ed8b
--- /dev/null
+++ b/src/interfaces/libpq/test/meson.build
@@ -0,0 +1,15 @@
+executable('libpq_uri_regress',
+  files('libpq_uri_regress.c'),
+  dependencies: [frontend_code, libpq],
+  kwargs: default_bin_args + {
+    'install': false,
+  }
+)
+
+executable('libpq_testclient',
+  files('libpq_testclient.c'),
+  dependencies: [frontend_code, libpq],
+  kwargs: default_bin_args + {
+    'install': false,
+  }
+)
diff --git a/src/pl/meson.build b/src/pl/meson.build
new file mode 100644
index 00000000000..d9a57465441
--- /dev/null
+++ b/src/pl/meson.build
@@ -0,0 +1,5 @@
+subdir('plpgsql')
+
+subdir('plperl')
+subdir('plpython')
+subdir('tcl')
diff --git a/src/pl/plperl/meson.build b/src/pl/plperl/meson.build
new file mode 100644
index 00000000000..73b733dd50b
--- /dev/null
+++ b/src/pl/plperl/meson.build
@@ -0,0 +1,90 @@
+if not perl_dep.found()
+  subdir_done()
+endif
+
+plperl_sources = files(
+  'plperl.c',
+)
+
+subppdir = run_command(perl, '-e', 'use List::Util qw(first); print first { -r "$_/ExtUtils/xsubpp" } @INC',
+  check: true).stdout()
+xsubpp = '@0@/ExtUtils/xsubpp'.format(subppdir)
+typemap = '@0@/ExtUtils/typemap'.format(privlibexp)
+
+plperl_sources += custom_target('perlchunks.h',
+  input: files('plc_perlboot.pl', 'plc_trusted.pl'),
+  output: 'perlchunks.h',
+  capture: true,
+  command: [perl, files('text2macro.pl'), '--strip=^(\#.*|\s*)$', '@INPUT@']
+)
+
+plperl_sources += custom_target('plperl_opmask.h',
+  input: files('plperl_opmask.pl'),
+  output: 'plperl_opmask.h',
+  command: [perl, '@INPUT@', '@OUTPUT@']
+)
+
+foreach n : ['SPI', 'Util']
+  xs = files(n + '.xs')
+  xs_c_name = n + '.c'
+  xs_c = custom_target(xs_c_name,
+    input: xs,
+    output: xs_c_name,
+    command: [perl, xsubpp, '-typemap', typemap, '-output', '@OUTPUT@', '@INPUT@']
+  )
+  plperl_sources += xs_c
+endforeach
+
+plperl_inc = include_directories('.')
+plperl = shared_module('plperl',
+  plperl_sources,
+  include_directories: [plperl_inc, postgres_inc],
+  kwargs: pg_mod_args + {
+    'dependencies': [perl_dep, pg_mod_args['dependencies']],
+    'install_rpath': ':'.join(mod_install_rpaths + ['@0@/CORE'.format(archlibexp)]),
+    'build_rpath': '@0@/CORE'.format(archlibexp),
+  },
+)
+pl_targets += plperl
+
+install_data(
+  'plperl.control',
+  'plperl--1.0.sql',
+  install_dir: dir_data_extension,
+)
+
+install_data(
+  'plperlu.control',
+  'plperlu--1.0.sql',
+  install_dir: dir_data_extension,
+)
+
+install_headers(
+  'plperl.h',
+  'ppport.h',
+  install_dir: dir_include_server,
+)
+
+tests += {
+  'name': 'plperl',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'plperl_setup',
+      'plperl',
+      'plperl_lc',
+      'plperl_trigger',
+      'plperl_shared',
+      'plperl_elog',
+      'plperl_util',
+      'plperl_init',
+      'plperlu',
+      'plperl_array',
+      'plperl_call',
+      'plperl_transaction',
+    ],
+  },
+}
+
+subdir('po', if_found: libintl)
diff --git a/src/pl/plperl/po/meson.build b/src/pl/plperl/po/meson.build
new file mode 100644
index 00000000000..fe0a715bdf0
--- /dev/null
+++ b/src/pl/plperl/po/meson.build
@@ -0,0 +1 @@
+i18n.gettext('plperl-' + pg_version_major.to_string())
diff --git a/src/pl/plpgsql/meson.build b/src/pl/plpgsql/meson.build
new file mode 100644
index 00000000000..9537275d67c
--- /dev/null
+++ b/src/pl/plpgsql/meson.build
@@ -0,0 +1 @@
+subdir('src')
diff --git a/src/pl/plpgsql/src/meson.build b/src/pl/plpgsql/src/meson.build
new file mode 100644
index 00000000000..dd499fdd151
--- /dev/null
+++ b/src/pl/plpgsql/src/meson.build
@@ -0,0 +1,84 @@
+plpgsql_sources = files(
+  'pl_comp.c',
+  'pl_exec.c',
+  'pl_funcs.c',
+  'pl_handler.c',
+  'pl_scanner.c',
+)
+
+pl_gram = custom_target('gram',
+  input: 'pl_gram.y',
+  kwargs: bison_kw,
+)
+generated_sources += pl_gram.to_list()
+plpgsql_sources += pl_gram
+
+gen_plerrcodes = files('generate-plerrcodes.pl')
+pl_errcodes = custom_target('plerrcodes',
+  input: ['../../../../src/backend/utils/errcodes.txt'],
+  output: ['plerrcodes.h'],
+  command: [perl, gen_plerrcodes, '@INPUT0@'],
+  capture: true,
+)
+generated_sources += pl_errcodes
+plpgsql_sources += pl_errcodes
+
+gen_keywordlist = files('../../../../src/tools/gen_keywordlist.pl')
+pl_reserved = custom_target('pl_reserved_kwlist',
+  input: ['pl_reserved_kwlist.h'],
+  output: ['pl_reserved_kwlist_d.h'],
+  command: [perl, '-I', '@SOURCE_ROOT@/src/tools', gen_keywordlist, '--output', '@OUTDIR@', '--varname', 'ReservedPLKeywords', '@INPUT@']
+)
+generated_sources += pl_reserved
+plpgsql_sources += pl_reserved
+
+pl_unreserved = custom_target('pl_unreserved_kwlist',
+  input: ['pl_unreserved_kwlist.h'],
+  output: ['pl_unreserved_kwlist_d.h'],
+  command: [perl, '-I', '@SOURCE_ROOT@/src/tools', gen_keywordlist, '--output', '@OUTDIR@', '--varname', 'UnreservedPLKeywords', '@INPUT@']
+)
+generated_sources += pl_unreserved
+plpgsql_sources += pl_unreserved
+
+plpgsql = shared_module('plpgsql',
+  plpgsql_sources,
+  include_directories: include_directories('.'),
+  kwargs: pg_mod_args,
+)
+pl_targets += plpgsql
+
+install_data(
+  'plpgsql.control',
+  'plpgsql--1.0.sql',
+  install_dir: dir_data_extension,
+)
+
+install_headers(
+  'plpgsql.h',
+  install_dir: dir_include_server
+)
+
+
+tests += {
+  'name': 'plpgsql',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'plpgsql_array',
+      'plpgsql_call',
+      'plpgsql_control',
+      'plpgsql_copy',
+      'plpgsql_domain',
+      'plpgsql_record',
+      'plpgsql_cache',
+      'plpgsql_simple',
+      'plpgsql_transaction',
+      'plpgsql_trap',
+      'plpgsql_trigger',
+      'plpgsql_varprops',
+    ],
+  },
+}
+
+subdir('po', if_found: libintl)
diff --git a/src/pl/plpgsql/src/po/meson.build b/src/pl/plpgsql/src/po/meson.build
new file mode 100644
index 00000000000..29e0b74488f
--- /dev/null
+++ b/src/pl/plpgsql/src/po/meson.build
@@ -0,0 +1 @@
+i18n.gettext('plpgsql-' + pg_version_major.to_string())
diff --git a/src/pl/plpython/meson.build b/src/pl/plpython/meson.build
new file mode 100644
index 00000000000..366b3b171ac
--- /dev/null
+++ b/src/pl/plpython/meson.build
@@ -0,0 +1,99 @@
+if not python3_dep.found()
+  subdir_done()
+endif
+
+plpython_sources = files(
+  'plpy_cursorobject.c',
+  'plpy_elog.c',
+  'plpy_exec.c',
+  'plpy_main.c',
+  'plpy_planobject.c',
+  'plpy_plpymodule.c',
+  'plpy_procedure.c',
+  'plpy_resultobject.c',
+  'plpy_spi.c',
+  'plpy_subxactobject.c',
+  'plpy_typeio.c',
+  'plpy_util.c',
+)
+
+plpython_sources += custom_target('spiexceptions.h',
+  input: files('../../backend/utils/errcodes.txt'),
+  output: 'spiexceptions.h',
+  command: [perl, files('generate-spiexceptions.pl'), '@INPUT@'],
+  capture: true,
+)
+
+
+# FIXME: need to duplicate import library ugliness?
+plpython_inc = include_directories('.')
+
+plpython = shared_module('plpython3',
+  plpython_sources,
+  include_directories: [plpython_inc, postgres_inc],
+  kwargs: pg_mod_args + {
+    'dependencies': [python3_dep, pg_mod_args['dependencies']],
+  },
+)
+pl_targets += plpython
+
+# FIXME: Only install the relevant versions
+install_data(
+  'plpython3u.control',
+  'plpython3u--1.0.sql',
+  install_dir: dir_data_extension,
+)
+
+install_headers(
+  'plpy_cursorobject.h',
+  'plpy_elog.h',
+  'plpy_exec.h',
+  'plpy_main.h',
+  'plpy_planobject.h',
+  'plpy_plpymodule.h',
+  'plpy_procedure.h',
+  'plpy_resultobject.h',
+  'plpy_spi.h',
+  'plpy_subxactobject.h',
+  'plpy_typeio.h',
+  'plpy_util.h',
+  'plpython.h',
+  install_dir: dir_include_server,
+)
+
+plpython_regress = [
+  'plpython_schema',
+  'plpython_populate',
+  'plpython_test',
+  'plpython_do',
+  'plpython_global',
+  'plpython_import',
+  'plpython_spi',
+  'plpython_newline',
+  'plpython_void',
+  'plpython_call',
+  'plpython_params',
+  'plpython_setof',
+  'plpython_record',
+  'plpython_trigger',
+  'plpython_types',
+  'plpython_error',
+  'plpython_ereport',
+  'plpython_unicode',
+  'plpython_quote',
+  'plpython_composite',
+  'plpython_subtransaction',
+  'plpython_transaction',
+  'plpython_drop',
+]
+
+tests += {
+  'name': 'plpython',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': plpython_regress,
+  },
+}
+
+subdir('po', if_found: libintl)
diff --git a/src/pl/plpython/po/meson.build b/src/pl/plpython/po/meson.build
new file mode 100644
index 00000000000..542e27fbe1f
--- /dev/null
+++ b/src/pl/plpython/po/meson.build
@@ -0,0 +1 @@
+i18n.gettext('plpython-' + pg_version_major.to_string())
diff --git a/src/pl/tcl/meson.build b/src/pl/tcl/meson.build
new file mode 100644
index 00000000000..9b6addd7fd5
--- /dev/null
+++ b/src/pl/tcl/meson.build
@@ -0,0 +1,55 @@
+if not tcl_dep.found()
+  subdir_done()
+endif
+
+pltcl_sources = files(
+  'pltcl.c',
+)
+
+gen_pltclerrcodes = files('generate-pltclerrcodes.pl')
+pltcl_sources += custom_target('pltclerrcodes.h',
+  input: files('../../backend/utils/errcodes.txt'),
+  output: 'pltclerrcodes.h',
+  capture: true,
+  command: [perl, gen_pltclerrcodes, '@INPUT@']
+)
+
+pltcl = shared_module('pltcl',
+  pltcl_sources,
+  include_directories: [include_directories('.'), postgres_inc],
+  kwargs: pg_mod_args + {
+    'dependencies': [tcl_dep, pg_mod_args['dependencies']],
+  },
+)
+pl_targets += pltcl
+
+install_data(
+  'pltcl.control',
+  'pltcl--1.0.sql',
+  'pltclu.control',
+  'pltclu--1.0.sql',
+  install_dir: dir_data_extension,
+)
+
+pltcl_regress = [
+  'pltcl_setup',
+  'pltcl_queries',
+  'pltcl_trigger',
+  'pltcl_call',
+  'pltcl_start_proc',
+  'pltcl_subxact',
+  'pltcl_unicode',
+  'pltcl_transaction',
+]
+
+tests += {
+  'name': 'pltcl',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': pltcl_regress,
+    'regress_args': ['--load-extension=pltcl'],
+  },
+}
+
+subdir('po', if_found: libintl)
diff --git a/src/pl/tcl/po/meson.build b/src/pl/tcl/po/meson.build
new file mode 100644
index 00000000000..cc23ef1eb3b
--- /dev/null
+++ b/src/pl/tcl/po/meson.build
@@ -0,0 +1 @@
+i18n.gettext('pltcl-' + pg_version_major.to_string())
diff --git a/contrib/adminpack/meson.build b/contrib/adminpack/meson.build
new file mode 100644
index 00000000000..fc2368d02cf
--- /dev/null
+++ b/contrib/adminpack/meson.build
@@ -0,0 +1,23 @@
+adminpack = shared_module('adminpack',
+  ['adminpack.c'],
+  kwargs: contrib_mod_args,
+)
+contrib_targets += adminpack
+
+install_data(
+  'adminpack.control',
+  'adminpack--1.0.sql',
+  'adminpack--1.0--1.1.sql',
+  'adminpack--1.1--2.0.sql',
+  'adminpack--2.0--2.1.sql',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'adminpack',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': ['adminpack'],
+  },
+}
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
new file mode 100644
index 00000000000..1db3d20349e
--- /dev/null
+++ b/contrib/amcheck/meson.build
@@ -0,0 +1,37 @@
+amcheck = shared_module('amcheck', [
+    'verify_heapam.c',
+    'verify_nbtree.c',
+  ],
+  kwargs: contrib_mod_args,
+)
+contrib_targets += amcheck
+
+install_data(
+  'amcheck.control',
+  'amcheck--1.0.sql',
+  'amcheck--1.0--1.1.sql',
+  'amcheck--1.1--1.2.sql',
+  'amcheck--1.2--1.3.sql',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'amcheck',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'check',
+      'check_btree',
+      'check_heap',
+    ],
+  },
+  'tap': {
+    'tests': [
+      't/001_verify_heapam.pl',
+      't/002_cic.pl',
+      't/003_cic_2pc.pl',
+    ],
+  },
+}
+
diff --git a/contrib/auth_delay/meson.build b/contrib/auth_delay/meson.build
new file mode 100644
index 00000000000..d2e01968f54
--- /dev/null
+++ b/contrib/auth_delay/meson.build
@@ -0,0 +1,5 @@
+autoinc = shared_module('auth_delay',
+  ['auth_delay.c'],
+  kwargs: contrib_mod_args,
+)
+contrib_targets += autoinc
diff --git a/contrib/auto_explain/meson.build b/contrib/auto_explain/meson.build
new file mode 100644
index 00000000000..249a8376faa
--- /dev/null
+++ b/contrib/auto_explain/meson.build
@@ -0,0 +1,16 @@
+auto_explain = shared_module('auto_explain',
+  files('auto_explain.c'),
+  kwargs: contrib_mod_args,
+)
+contrib_targets += auto_explain
+
+tests += {
+  'name': 'auto_explain',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'tests': [
+      't/001_auto_explain.pl',
+    ],
+  },
+}
diff --git a/contrib/basebackup_to_shell/meson.build b/contrib/basebackup_to_shell/meson.build
new file mode 100644
index 00000000000..9f0517f1701
--- /dev/null
+++ b/contrib/basebackup_to_shell/meson.build
@@ -0,0 +1,22 @@
+basebackup_to_shell_sources = files(
+  'basebackup_to_shell.c',
+)
+
+basebackup_to_shell = shared_module('basebackup_to_shell',
+  basebackup_to_shell_sources,
+  kwargs: contrib_mod_args,
+)
+contrib_targets += basebackup_to_shell
+
+tests += {
+  'name': 'basebackup_to_shell',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'tests': [
+      't/001_basic.pl',
+    ],
+    'env': {'GZIP_PROGRAM': gzip.path(),
+            'TAR': tar.path()},
+  },
+}
diff --git a/contrib/basic_archive/meson.build b/contrib/basic_archive/meson.build
new file mode 100644
index 00000000000..b67cbef60bd
--- /dev/null
+++ b/contrib/basic_archive/meson.build
@@ -0,0 +1,23 @@
+basic_archive_sources = files(
+  'basic_archive.c',
+)
+
+basic_archive = shared_module('basic_archive',
+  basic_archive_sources,
+  kwargs: contrib_mod_args,
+)
+contrib_targets += basic_archive
+
+tests += {
+  'name': 'basic_archive',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'basic_archive',
+    ],
+    'regress_args': [
+      '--temp-config', files('basic_archive.conf'),
+    ],
+  },
+}
diff --git a/contrib/bloom/meson.build b/contrib/bloom/meson.build
new file mode 100644
index 00000000000..1fe7632bdbe
--- /dev/null
+++ b/contrib/bloom/meson.build
@@ -0,0 +1,36 @@
+bloom_sources = files(
+  'blcost.c',
+  'blinsert.c',
+  'blscan.c',
+  'blutils.c',
+  'blvacuum.c',
+  'blvalidate.c',
+)
+
+bloom = shared_module('bloom',
+  bloom_sources,
+  kwargs: contrib_mod_args,
+)
+contrib_targets += bloom
+
+install_data(
+  'bloom.control',
+  'bloom--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'bloom',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'bloom',
+    ],
+  },
+  'tap': {
+    'tests': [
+      't/001_wal.pl',
+    ],
+  },
+}
diff --git a/contrib/bool_plperl/meson.build b/contrib/bool_plperl/meson.build
new file mode 100644
index 00000000000..c20b667d75f
--- /dev/null
+++ b/contrib/bool_plperl/meson.build
@@ -0,0 +1,42 @@
+if not perl_dep.found()
+  subdir_done()
+endif
+
+bool_plperl_sources = files(
+  'bool_plperl.c',
+)
+
+bool_plperl = shared_module('bool_plperl',
+  bool_plperl_sources,
+  include_directories: [plperl_inc, include_directories('.')],
+  kwargs: contrib_mod_args + {
+    'dependencies': [perl_dep, contrib_mod_args['dependencies']],
+    'install_rpath': ':'.join(mod_install_rpaths + ['@0@/CORE'.format(archlibexp)]),
+    'build_rpath': '@0@/CORE'.format(archlibexp),
+  },
+)
+contrib_targets += bool_plperl
+
+install_data(
+  'bool_plperl.control',
+  'bool_plperl--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+install_data(
+  'bool_plperlu.control',
+  'bool_plperlu--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'bool_plperl',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'bool_plperl',
+      'bool_plperlu',
+    ],
+  },
+}
diff --git a/contrib/btree_gin/meson.build b/contrib/btree_gin/meson.build
new file mode 100644
index 00000000000..15d6d31a6ee
--- /dev/null
+++ b/contrib/btree_gin/meson.build
@@ -0,0 +1,54 @@
+btree_gin = shared_module('btree_gin',
+  files('btree_gin.c'),
+  kwargs: contrib_mod_args,
+)
+contrib_targets += btree_gin
+
+install_data(
+  'btree_gin.control',
+  'btree_gin--1.0.sql',
+  'btree_gin--1.0--1.1.sql',
+  'btree_gin--1.1--1.2.sql',
+  'btree_gin--1.2--1.3.sql',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'btree_gin',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'install_btree_gin',
+      'int2',
+      'int4',
+      'int8',
+      'float4',
+      'float8',
+      'money',
+      'oid',
+      'timestamp',
+      'timestamptz',
+      'time',
+      'timetz',
+      'date',
+      'interval',
+      'macaddr',
+      'macaddr8',
+      'inet',
+      'cidr',
+      'text',
+      'varchar',
+      'char',
+      'bytea',
+      'bit',
+      'varbit',
+      'numeric',
+      'enum',
+      'uuid',
+      'name',
+      'bool',
+      'bpchar',
+    ],
+  },
+}
diff --git a/contrib/btree_gist/meson.build b/contrib/btree_gist/meson.build
new file mode 100644
index 00000000000..c0a8d238540
--- /dev/null
+++ b/contrib/btree_gist/meson.build
@@ -0,0 +1,84 @@
+btree_gist_sources = files(
+  'btree_bit.c',
+  'btree_bool.c',
+  'btree_bytea.c',
+  'btree_cash.c',
+  'btree_date.c',
+  'btree_enum.c',
+  'btree_float4.c',
+  'btree_float8.c',
+  'btree_gist.c',
+  'btree_inet.c',
+  'btree_int2.c',
+  'btree_int4.c',
+  'btree_int8.c',
+  'btree_interval.c',
+  'btree_macaddr.c',
+  'btree_macaddr8.c',
+  'btree_numeric.c',
+  'btree_oid.c',
+  'btree_text.c',
+  'btree_time.c',
+  'btree_ts.c',
+  'btree_utils_num.c',
+  'btree_utils_var.c',
+  'btree_uuid.c',
+)
+
+btree_gist = shared_module('btree_gist',
+  btree_gist_sources,
+  kwargs: contrib_mod_args,
+)
+contrib_targets += btree_gist
+
+install_data(
+  'btree_gist.control',
+  'btree_gist--1.0--1.1.sql',
+  'btree_gist--1.1--1.2.sql',
+  'btree_gist--1.2.sql',
+  'btree_gist--1.2--1.3.sql',
+  'btree_gist--1.3--1.4.sql',
+  'btree_gist--1.4--1.5.sql',
+  'btree_gist--1.5--1.6.sql',
+  'btree_gist--1.6--1.7.sql',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'btree_gist',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'init',
+      'int2',
+      'int4',
+      'int8',
+      'float4',
+      'float8',
+      'cash',
+      'oid',
+      'timestamp',
+      'timestamptz',
+      'time',
+      'timetz',
+      'date',
+      'interval',
+      'macaddr',
+      'macaddr8',
+      'inet',
+      'cidr',
+      'text',
+      'varchar',
+      'char',
+      'bytea',
+      'bit',
+      'varbit',
+      'numeric',
+      'uuid',
+      'not_equal',
+      'enum',
+      'bool',
+    ],
+  },
+}
diff --git a/contrib/citext/meson.build b/contrib/citext/meson.build
new file mode 100644
index 00000000000..ca60eded80b
--- /dev/null
+++ b/contrib/citext/meson.build
@@ -0,0 +1,34 @@
+citext_sources = files(
+  'citext.c',
+)
+
+citext = shared_module('citext',
+  citext_sources,
+  kwargs: contrib_mod_args,
+)
+contrib_targets += citext
+
+install_data(
+  'citext.control',
+  'citext--1.0--1.1.sql',
+  'citext--1.1--1.2.sql',
+  'citext--1.2--1.3.sql',
+  'citext--1.3--1.4.sql',
+  'citext--1.4.sql',
+  'citext--1.4--1.5.sql',
+  'citext--1.5--1.6.sql',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'citext',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'create_index_acl',
+      'citext',
+      'citext_utf8',
+    ],
+  },
+}
diff --git a/contrib/cube/meson.build b/contrib/cube/meson.build
new file mode 100644
index 00000000000..72342b0c82c
--- /dev/null
+++ b/contrib/cube/meson.build
@@ -0,0 +1,53 @@
+cube_sources = files(
+  'cube.c',
+)
+
+cube_scan = custom_target('cubescan',
+  input: 'cubescan.l',
+  output: 'cubescan.c',
+  command: flex_cmd,
+)
+generated_sources += cube_scan
+cube_sources += cube_scan
+
+cube_parse = custom_target('cubeparse',
+  input: 'cubeparse.y',
+  kwargs: bison_kw,
+)
+generated_sources += cube_parse.to_list()
+cube_sources += cube_parse
+
+cube = shared_module('cube',
+  cube_sources,
+  include_directories: include_directories('.'),
+  kwargs: contrib_mod_args,
+)
+contrib_targets += cube
+
+install_data(
+  'cube.control',
+  'cube--1.0--1.1.sql',
+  'cube--1.1--1.2.sql',
+  'cube--1.2.sql',
+  'cube--1.2--1.3.sql',
+  'cube--1.3--1.4.sql',
+  'cube--1.4--1.5.sql',
+  kwargs: contrib_data_args,
+)
+
+install_headers(
+  'cubedata.h',
+  install_dir: dir_include_extension / 'cube',
+)
+
+tests += {
+  'name': 'cube',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'cube',
+      'cube_sci',
+    ],
+  },
+}
diff --git a/contrib/dblink/meson.build b/contrib/dblink/meson.build
new file mode 100644
index 00000000000..d35f7b5d49e
--- /dev/null
+++ b/contrib/dblink/meson.build
@@ -0,0 +1,31 @@
+dblink_sources = files(
+  'dblink.c',
+)
+
+dblink = shared_module('dblink',
+  dblink_sources,
+  kwargs: contrib_mod_args + {
+    'dependencies': contrib_mod_args['dependencies'] + [libpq],
+  },
+)
+contrib_targets += dblink
+
+install_data(
+  'dblink.control',
+  'dblink--1.0--1.1.sql',
+  'dblink--1.1--1.2.sql',
+  'dblink--1.2.sql',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'dblink',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'dblink',
+    ],
+    'regress_args': ['--dlpath', meson.build_root() / 'src/test/regress'],
+  },
+}
diff --git a/contrib/dict_int/meson.build b/contrib/dict_int/meson.build
new file mode 100644
index 00000000000..f00e8085619
--- /dev/null
+++ b/contrib/dict_int/meson.build
@@ -0,0 +1,22 @@
+dict_int = shared_module('dict_int',
+  files('dict_int.c'),
+  kwargs: contrib_mod_args,
+)
+contrib_targets += dict_int
+
+install_data(
+  'dict_int.control',
+  'dict_int--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'dict_int',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'dict_int',
+    ],
+  },
+}
diff --git a/contrib/dict_xsyn/meson.build b/contrib/dict_xsyn/meson.build
new file mode 100644
index 00000000000..be53f55bb79
--- /dev/null
+++ b/contrib/dict_xsyn/meson.build
@@ -0,0 +1,29 @@
+dict_xsyn = shared_module('dict_xsyn',
+  files('dict_xsyn.c'),
+  kwargs: contrib_mod_args,
+)
+contrib_targets += dict_xsyn
+
+install_data(
+  'dict_xsyn.control',
+  'dict_xsyn--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+install_data(
+  'xsyn_sample.rules',
+  kwargs: contrib_data_args + {
+    'install_dir': dir_data / 'tsearch_data'
+  }
+)
+
+tests += {
+  'name': 'dict_xsyn',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'dict_xsyn',
+    ],
+  },
+}
diff --git a/contrib/earthdistance/meson.build b/contrib/earthdistance/meson.build
new file mode 100644
index 00000000000..807f5cb7de3
--- /dev/null
+++ b/contrib/earthdistance/meson.build
@@ -0,0 +1,23 @@
+earthdistance = shared_module('earthdistance',
+  files('earthdistance.c'),
+  kwargs: contrib_mod_args,
+)
+contrib_targets += earthdistance
+
+install_data(
+  'earthdistance.control',
+  'earthdistance--1.0--1.1.sql',
+  'earthdistance--1.1.sql',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'earthdistance',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'earthdistance',
+    ],
+  },
+}
diff --git a/contrib/file_fdw/meson.build b/contrib/file_fdw/meson.build
new file mode 100644
index 00000000000..f13efb6e38e
--- /dev/null
+++ b/contrib/file_fdw/meson.build
@@ -0,0 +1,22 @@
+file_fdw = shared_module('file_fdw',
+  files('file_fdw.c'),
+  kwargs: contrib_mod_args,
+)
+contrib_targets += file_fdw
+
+install_data(
+  'file_fdw.control',
+  'file_fdw--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'file_fdw',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'file_fdw',
+    ],
+  },
+}
diff --git a/contrib/fuzzystrmatch/meson.build b/contrib/fuzzystrmatch/meson.build
new file mode 100644
index 00000000000..ec278a6211e
--- /dev/null
+++ b/contrib/fuzzystrmatch/meson.build
@@ -0,0 +1,26 @@
+fuzzystrmatch = shared_module('fuzzystrmatch',
+  files(
+    'fuzzystrmatch.c',
+    'dmetaphone.c'
+  ),
+  kwargs: contrib_mod_args,
+)
+contrib_targets += fuzzystrmatch
+
+install_data(
+  'fuzzystrmatch.control',
+  'fuzzystrmatch--1.0--1.1.sql',
+  'fuzzystrmatch--1.1.sql',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'fuzzystrmatch',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'fuzzystrmatch',
+    ],
+  },
+}
diff --git a/contrib/hstore/meson.build b/contrib/hstore/meson.build
new file mode 100644
index 00000000000..07c59f40a97
--- /dev/null
+++ b/contrib/hstore/meson.build
@@ -0,0 +1,44 @@
+# .. so that includes of hstore/hstore.h work
+hstore_inc = include_directories('.', '../')
+
+hstore = shared_module('hstore',
+  files(
+    'hstore_compat.c',
+    'hstore_gin.c',
+    'hstore_gist.c',
+    'hstore_io.c',
+    'hstore_op.c',
+    'hstore_subs.c',
+  ),
+  kwargs: contrib_mod_args,
+)
+contrib_targets += hstore
+
+install_data(
+  'hstore.control',
+  'hstore--1.1--1.2.sql',
+  'hstore--1.2--1.3.sql',
+  'hstore--1.3--1.4.sql',
+  'hstore--1.4.sql',
+  'hstore--1.4--1.5.sql',
+  'hstore--1.5--1.6.sql',
+  'hstore--1.6--1.7.sql',
+  'hstore--1.7--1.8.sql',
+  kwargs: contrib_data_args,
+)
+
+install_headers(
+  'hstore.h',
+  install_dir: dir_include_extension / 'hstore',
+)
+
+tests += {
+  'name': 'hstore',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'hstore',
+    ],
+  },
+}
diff --git a/contrib/hstore_plperl/meson.build b/contrib/hstore_plperl/meson.build
new file mode 100644
index 00000000000..bbafa0221bd
--- /dev/null
+++ b/contrib/hstore_plperl/meson.build
@@ -0,0 +1,43 @@
+if not perl_dep.found()
+  subdir_done()
+endif
+
+hstore_plperl_sources = files(
+  'hstore_plperl.c',
+)
+
+hstore_plperl = shared_module('hstore_plperl',
+  hstore_plperl_sources,
+  include_directories: [plperl_inc, hstore_inc],
+  kwargs: contrib_mod_args + {
+    'dependencies': [perl_dep, contrib_mod_args['dependencies']],
+    'install_rpath': ':'.join(mod_install_rpaths + ['@0@/CORE'.format(archlibexp)]),
+    'build_rpath': '@0@/CORE'.format(archlibexp),
+  },
+)
+contrib_targets += hstore_plperl
+
+install_data(
+  'hstore_plperl.control',
+  'hstore_plperl--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+install_data(
+  'hstore_plperlu.control',
+  'hstore_plperlu--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'hstore_plperl',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'hstore_plperl',
+      'hstore_plperlu',
+      'create_transform',
+    ],
+  },
+}
diff --git a/contrib/hstore_plpython/meson.build b/contrib/hstore_plpython/meson.build
new file mode 100644
index 00000000000..214b48519a9
--- /dev/null
+++ b/contrib/hstore_plpython/meson.build
@@ -0,0 +1,37 @@
+if not python3_dep.found()
+  subdir_done()
+endif
+
+hstore_plpython_sources = files(
+  'hstore_plpython.c',
+)
+
+hstore_plpython = shared_module('hstore_plpython3',
+  hstore_plpython_sources,
+  include_directories: [plpython_inc, hstore_inc, ],
+  c_args: ['-DPLPYTHON_LIBNAME="plpython3"'],
+  kwargs: contrib_mod_args + {
+    'dependencies': [python3_dep, contrib_mod_args['dependencies']],
+  },
+)
+contrib_targets += hstore_plpython
+
+install_data(
+  'hstore_plpython3u--1.0.sql',
+  'hstore_plpython3u.control',
+  kwargs: contrib_data_args,
+)
+
+hstore_plpython_regress = [
+  'hstore_plpython'
+]
+
+tests += {
+  'name': 'hstore_plpython',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': hstore_plpython_regress,
+    'regress_args': ['--load-extension=hstore'],
+  },
+}
diff --git a/contrib/intagg/meson.build b/contrib/intagg/meson.build
new file mode 100644
index 00000000000..a0f39366f47
--- /dev/null
+++ b/contrib/intagg/meson.build
@@ -0,0 +1,6 @@
+install_data(
+  'intagg.control',
+  'intagg--1.0--1.1.sql',
+  'intagg--1.1.sql',
+  kwargs: contrib_data_args,
+)
diff --git a/contrib/intarray/meson.build b/contrib/intarray/meson.build
new file mode 100644
index 00000000000..1655bcbb3fd
--- /dev/null
+++ b/contrib/intarray/meson.build
@@ -0,0 +1,37 @@
+intarray_sources = files(
+  '_int_bool.c',
+  '_int_gin.c',
+  '_int_gist.c',
+  '_int_op.c',
+  '_int_selfuncs.c',
+  '_int_tool.c',
+  '_intbig_gist.c',
+)
+
+intarray = shared_module('_int',
+  intarray_sources,
+  kwargs: contrib_mod_args,
+)
+contrib_targets += intarray
+
+install_data(
+  'intarray.control',
+  'intarray--1.0--1.1.sql',
+  'intarray--1.1--1.2.sql',
+  'intarray--1.2.sql',
+  'intarray--1.2--1.3.sql',
+  'intarray--1.3--1.4.sql',
+  'intarray--1.4--1.5.sql',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'intarray',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      '_int',
+    ],
+  },
+}
diff --git a/contrib/isn/meson.build b/contrib/isn/meson.build
new file mode 100644
index 00000000000..cc30bbeb55c
--- /dev/null
+++ b/contrib/isn/meson.build
@@ -0,0 +1,33 @@
+isn_sources = files(
+  'isn.c',
+)
+
+isn = shared_module('isn',
+  isn_sources,
+  kwargs: contrib_mod_args,
+)
+contrib_targets += isn
+
+install_data(
+  'isn.control',
+  'isn--1.0--1.1.sql',
+  'isn--1.1--1.2.sql',
+  'isn--1.1.sql',
+  kwargs: contrib_data_args,
+)
+
+install_headers(
+  'isn.h',
+  install_dir: dir_include_extension / 'isn',
+)
+
+tests += {
+  'name': 'isn',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'isn',
+    ],
+  },
+}
diff --git a/contrib/jsonb_plperl/meson.build b/contrib/jsonb_plperl/meson.build
new file mode 100644
index 00000000000..5c915d8ed94
--- /dev/null
+++ b/contrib/jsonb_plperl/meson.build
@@ -0,0 +1,43 @@
+if not perl_dep.found()
+  subdir_done()
+endif
+
+jsonb_plperl_sources = files(
+  'jsonb_plperl.c',
+)
+
+jsonb_plperl = shared_module('jsonb_plperl',
+  jsonb_plperl_sources,
+  include_directories: [plperl_inc],
+  kwargs: contrib_mod_args + {
+    'dependencies': [perl_dep, contrib_mod_args['dependencies']],
+    'install_rpath': ':'.join(mod_install_rpaths + ['@0@/CORE'.format(archlibexp)]),
+    'build_rpath': '@0@/CORE'.format(archlibexp),
+  },
+)
+contrib_targets += jsonb_plperl
+
+install_data(
+  'jsonb_plperl.control',
+  'jsonb_plperl--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+install_data(
+  'jsonb_plperlu.control',
+  'jsonb_plperlu--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+
+tests += {
+  'name': 'jsonb_plperl',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'jsonb_plperl',
+      'jsonb_plperlu',
+    ],
+  },
+}
diff --git a/contrib/jsonb_plpython/meson.build b/contrib/jsonb_plpython/meson.build
new file mode 100644
index 00000000000..de8e1105c6a
--- /dev/null
+++ b/contrib/jsonb_plpython/meson.build
@@ -0,0 +1,36 @@
+if not python3_dep.found()
+  subdir_done()
+endif
+
+jsonb_plpython_sources = files(
+  'jsonb_plpython.c',
+)
+
+jsonb_plpython = shared_module('jsonb_plpython3',
+  jsonb_plpython_sources,
+  include_directories: [plpython_inc],
+  c_args: ['-DPLPYTHON_LIBNAME="plpython3"'],
+  kwargs: contrib_mod_args + {
+    'dependencies': [python3_dep, contrib_mod_args['dependencies']],
+  },
+)
+contrib_targets += jsonb_plpython
+
+install_data(
+  'jsonb_plpython3u.control',
+  'jsonb_plpython3u--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+jsonb_plpython_regress = [
+  'jsonb_plpython'
+]
+
+tests += {
+  'name': 'jsonb_plpython',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': jsonb_plpython_regress,
+  },
+}
diff --git a/contrib/lo/meson.build b/contrib/lo/meson.build
new file mode 100644
index 00000000000..9082d5713c7
--- /dev/null
+++ b/contrib/lo/meson.build
@@ -0,0 +1,27 @@
+lo_sources = files(
+  'lo.c',
+)
+
+lo = shared_module('lo',
+  lo_sources,
+  kwargs: contrib_mod_args,
+)
+contrib_targets += lo
+
+install_data(
+  'lo.control',
+  'lo--1.0--1.1.sql',
+  'lo--1.1.sql',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'lo',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'lo',
+    ],
+  },
+}
diff --git a/contrib/ltree/meson.build b/contrib/ltree/meson.build
new file mode 100644
index 00000000000..9463fc2c5e5
--- /dev/null
+++ b/contrib/ltree/meson.build
@@ -0,0 +1,44 @@
+ltree_sources = files(
+  '_ltree_gist.c',
+  '_ltree_op.c',
+  'crc32.c',
+  'lquery_op.c',
+  'ltree_gist.c',
+  'ltree_io.c',
+  'ltree_op.c',
+  'ltxtquery_io.c',
+  'ltxtquery_op.c',
+)
+
+# .. so that includes of ltree/ltree.h work
+ltree_inc = include_directories('.', '../')
+
+ltree = shared_module('ltree',
+  ltree_sources,
+  kwargs: contrib_mod_args,
+)
+contrib_targets += ltree
+
+install_data(
+  'ltree.control',
+  'ltree--1.0--1.1.sql',
+  'ltree--1.1--1.2.sql',
+  'ltree--1.1.sql',
+  kwargs: contrib_data_args,
+)
+
+install_headers(
+  'ltree.h',
+  install_dir: dir_include_extension / 'ltree',
+)
+
+tests += {
+  'name': 'ltree',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'ltree',
+    ],
+  },
+}
diff --git a/contrib/ltree_plpython/meson.build b/contrib/ltree_plpython/meson.build
new file mode 100644
index 00000000000..429d75006aa
--- /dev/null
+++ b/contrib/ltree_plpython/meson.build
@@ -0,0 +1,37 @@
+if not python3_dep.found()
+  subdir_done()
+endif
+
+ltree_plpython_sources = files(
+  'ltree_plpython.c',
+)
+
+ltree_plpython = shared_module('ltree_plpython3',
+  ltree_plpython_sources,
+  include_directories: [plpython_inc, ltree_inc],
+  c_args: ['-DPLPYTHON_LIBNAME="plpython3"'],
+  kwargs: contrib_mod_args + {
+    'dependencies': [python3_dep, contrib_mod_args['dependencies']],
+  },
+)
+contrib_targets += ltree_plpython
+
+install_data(
+  'ltree_plpython3u--1.0.sql',
+  'ltree_plpython3u.control',
+  kwargs: contrib_data_args,
+)
+
+ltree_plpython_regress = [
+  'ltree_plpython'
+]
+
+tests += {
+  'name': 'ltree_plpython',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': ltree_plpython_regress,
+    'regress_args': ['--load-extension=ltree'],
+  },
+}
diff --git a/contrib/meson.build b/contrib/meson.build
new file mode 100644
index 00000000000..84752d4bd0f
--- /dev/null
+++ b/contrib/meson.build
@@ -0,0 +1,66 @@
+contrib_mod_args = pg_mod_args
+
+contrib_data_dir = dir_data_extension
+contrib_data_args = {
+  'install_dir': contrib_data_dir,
+}
+
+subdir('adminpack')
+subdir('amcheck')
+subdir('auth_delay')
+subdir('auto_explain')
+subdir('basic_archive')
+subdir('bloom')
+subdir('basebackup_to_shell')
+subdir('bool_plperl')
+subdir('btree_gin')
+subdir('btree_gist')
+subdir('citext')
+subdir('cube')
+subdir('dblink')
+subdir('dict_int')
+subdir('dict_xsyn')
+subdir('earthdistance')
+subdir('file_fdw')
+subdir('fuzzystrmatch')
+subdir('hstore')
+subdir('hstore_plperl')
+subdir('hstore_plpython')
+subdir('intagg')
+subdir('intarray')
+subdir('isn')
+subdir('jsonb_plperl')
+subdir('jsonb_plpython')
+subdir('lo')
+subdir('ltree')
+subdir('ltree_plpython')
+subdir('oid2name')
+subdir('old_snapshot')
+subdir('pageinspect')
+subdir('passwordcheck')
+subdir('pg_buffercache')
+subdir('pgcrypto')
+subdir('pg_freespacemap')
+subdir('pg_prewarm')
+subdir('pgrowlocks')
+subdir('pg_stat_statements')
+subdir('pgstattuple')
+subdir('pg_surgery')
+subdir('pg_trgm')
+subdir('pg_visibility')
+subdir('pg_walinspect')
+subdir('postgres_fdw')
+subdir('seg')
+subdir('sepgsql')
+subdir('spi')
+subdir('sslinfo')
+# start-scripts doesn't contain build products
+subdir('tablefunc')
+subdir('tcn')
+subdir('test_decoding')
+subdir('tsm_system_rows')
+subdir('tsm_system_time')
+subdir('unaccent')
+subdir('uuid-ossp')
+subdir('vacuumlo')
+subdir('xml2')
diff --git a/contrib/oid2name/meson.build b/contrib/oid2name/meson.build
new file mode 100644
index 00000000000..1dad5d8f6e7
--- /dev/null
+++ b/contrib/oid2name/meson.build
@@ -0,0 +1,17 @@
+oid2name = executable('oid2name',
+  ['oid2name.c'],
+  dependencies: [frontend_code, libpq],
+  kwargs: default_bin_args,
+)
+contrib_targets += oid2name
+
+tests += {
+  'name': 'oid2name',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'tests': [
+      't/001_basic.pl',
+    ],
+  },
+}
diff --git a/contrib/old_snapshot/meson.build b/contrib/old_snapshot/meson.build
new file mode 100644
index 00000000000..8e7ee09a43a
--- /dev/null
+++ b/contrib/old_snapshot/meson.build
@@ -0,0 +1,15 @@
+old_snapshot_sources = files(
+  'time_mapping.c',
+)
+
+old_snapshot = shared_module('old_snapshot',
+  old_snapshot_sources,
+  kwargs: contrib_mod_args,
+)
+contrib_targets += old_snapshot
+
+install_data(
+  'old_snapshot.control',
+  'old_snapshot--1.0.sql',
+  kwargs: contrib_data_args,
+)
diff --git a/contrib/pageinspect/meson.build b/contrib/pageinspect/meson.build
new file mode 100644
index 00000000000..4af8153e4fd
--- /dev/null
+++ b/contrib/pageinspect/meson.build
@@ -0,0 +1,50 @@
+pageinspect_sources = files(
+  'brinfuncs.c',
+  'btreefuncs.c',
+  'fsmfuncs.c',
+  'ginfuncs.c',
+  'gistfuncs.c',
+  'hashfuncs.c',
+  'heapfuncs.c',
+  'rawpage.c',
+)
+
+pageinspect = shared_module('pageinspect',
+  pageinspect_sources,
+  kwargs: contrib_mod_args,
+)
+contrib_targets += pageinspect
+
+install_data(
+  'pageinspect--1.0--1.1.sql',
+  'pageinspect--1.1--1.2.sql',
+  'pageinspect--1.2--1.3.sql',
+  'pageinspect--1.3--1.4.sql',
+  'pageinspect--1.4--1.5.sql',
+  'pageinspect--1.5--1.6.sql',
+  'pageinspect--1.5.sql',
+  'pageinspect--1.6--1.7.sql',
+  'pageinspect--1.7--1.8.sql',
+  'pageinspect--1.8--1.9.sql',
+  'pageinspect--1.9--1.10.sql',
+  'pageinspect.control',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'pageinspect',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'page',
+      'btree',
+      'brin',
+      'gin',
+      'gist',
+      'hash',
+      'checksum',
+      'oldextversions',
+    ],
+  },
+}
diff --git a/contrib/passwordcheck/meson.build b/contrib/passwordcheck/meson.build
new file mode 100644
index 00000000000..7da47d02f1d
--- /dev/null
+++ b/contrib/passwordcheck/meson.build
@@ -0,0 +1,30 @@
+passwordcheck_sources = files(
+  'passwordcheck.c',
+)
+
+passwordcheck_c_args = []
+passwordcheck_deps = []
+
+# uncomment the following two lines to enable cracklib support
+# passwordcheck_c_args += ['-DUSE_CRACKLIB', '-DCRACKLIB_DICTPATH="/usr/lib/cracklib_dict"']
+# passwordcheck_deps += [cc.find_library('crack')]
+
+passwordcheck = shared_module('passwordcheck',
+  passwordcheck_sources,
+  c_args: passwordcheck_c_args,
+  kwargs: contrib_mod_args + {
+    'dependencies': contrib_mod_args.get('dependencies') + passwordcheck_deps,
+  }
+)
+contrib_targets += passwordcheck
+
+tests += {
+  'name': 'passwordcheck',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'passwordcheck',
+    ],
+  },
+}
diff --git a/contrib/pg_buffercache/meson.build b/contrib/pg_buffercache/meson.build
new file mode 100644
index 00000000000..2c69eae3ea2
--- /dev/null
+++ b/contrib/pg_buffercache/meson.build
@@ -0,0 +1,27 @@
+pg_buffercache = shared_module('pg_buffercache',
+  files(
+    'pg_buffercache_pages.c',
+  ),
+  kwargs: contrib_mod_args,
+)
+contrib_targets += pg_buffercache
+
+install_data(
+  'pg_buffercache--1.0--1.1.sql',
+  'pg_buffercache--1.1--1.2.sql',
+  'pg_buffercache--1.2--1.3.sql',
+  'pg_buffercache--1.2.sql',
+  'pg_buffercache.control',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'pg_buffercache',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'pg_buffercache',
+    ],
+  },
+}
diff --git a/contrib/pg_freespacemap/meson.build b/contrib/pg_freespacemap/meson.build
new file mode 100644
index 00000000000..f795014d7ca
--- /dev/null
+++ b/contrib/pg_freespacemap/meson.build
@@ -0,0 +1,29 @@
+pg_freespacemap = shared_module('pg_freespacemap',
+  files(
+    'pg_freespacemap.c',
+  ),
+  kwargs: contrib_mod_args,
+)
+contrib_targets += pg_freespacemap
+
+install_data(
+  'pg_freespacemap--1.0--1.1.sql',
+  'pg_freespacemap--1.1--1.2.sql',
+  'pg_freespacemap--1.1.sql',
+  'pg_freespacemap.control',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'pg_freespacemap',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'pg_freespacemap',
+    ],
+    'regress_args': [
+      '--temp-config', files('pg_freespacemap.conf')
+    ],
+  },
+}
diff --git a/contrib/pg_prewarm/meson.build b/contrib/pg_prewarm/meson.build
new file mode 100644
index 00000000000..bdca9af4f27
--- /dev/null
+++ b/contrib/pg_prewarm/meson.build
@@ -0,0 +1,27 @@
+pg_prewarm = shared_module('pg_prewarm',
+  files(
+    'autoprewarm.c',
+    'pg_prewarm.c',
+  ),
+  kwargs: contrib_mod_args,
+)
+contrib_targets += pg_prewarm
+
+install_data(
+  'pg_prewarm--1.0--1.1.sql',
+  'pg_prewarm--1.1--1.2.sql',
+  'pg_prewarm--1.1.sql',
+  'pg_prewarm.control',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'pg_prewarm',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'tests': [
+      't/001_basic.pl',
+    ],
+  },
+}
diff --git a/contrib/pg_stat_statements/meson.build b/contrib/pg_stat_statements/meson.build
new file mode 100644
index 00000000000..ac117d2fc1d
--- /dev/null
+++ b/contrib/pg_stat_statements/meson.build
@@ -0,0 +1,35 @@
+pg_stat_statements = shared_module('pg_stat_statements',
+  files('pg_stat_statements.c'),
+  kwargs: contrib_mod_args + {
+    'dependencies': contrib_mod_args['dependencies'],
+  },
+)
+contrib_targets += pg_stat_statements
+
+install_data(
+  'pg_stat_statements.control',
+  'pg_stat_statements--1.4.sql',
+  'pg_stat_statements--1.9--1.10.sql',
+  'pg_stat_statements--1.8--1.9.sql',
+  'pg_stat_statements--1.7--1.8.sql',
+  'pg_stat_statements--1.6--1.7.sql',
+  'pg_stat_statements--1.5--1.6.sql',
+  'pg_stat_statements--1.4--1.5.sql',
+  'pg_stat_statements--1.3--1.4.sql',
+  'pg_stat_statements--1.2--1.3.sql',
+  'pg_stat_statements--1.1--1.2.sql',
+  'pg_stat_statements--1.0--1.1.sql',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'pg_stat_statements',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'pg_stat_statements',
+    ],
+    'regress_args': ['--temp-config', files('pg_stat_statements.conf')],
+  },
+}
diff --git a/contrib/pg_surgery/meson.build b/contrib/pg_surgery/meson.build
new file mode 100644
index 00000000000..ac71caa5276
--- /dev/null
+++ b/contrib/pg_surgery/meson.build
@@ -0,0 +1,25 @@
+pg_surgery = shared_module('pg_surgery',
+  files(
+    'heap_surgery.c',
+  ),
+  kwargs: contrib_mod_args,
+)
+contrib_targets += pg_surgery
+
+install_data(
+  'pg_surgery--1.0.sql',
+  'pg_surgery.control',
+  kwargs: contrib_data_args,
+)
+
+
+tests += {
+  'name': 'pg_surgery',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'heap_surgery',
+    ],
+  },
+}
diff --git a/contrib/pg_trgm/meson.build b/contrib/pg_trgm/meson.build
new file mode 100644
index 00000000000..a90628d23c6
--- /dev/null
+++ b/contrib/pg_trgm/meson.build
@@ -0,0 +1,35 @@
+pg_trgm = shared_module('pg_trgm',
+  files(
+    'trgm_gin.c',
+    'trgm_gist.c',
+    'trgm_op.c',
+    'trgm_regexp.c',
+  ),
+  kwargs: contrib_mod_args,
+)
+contrib_targets += pg_trgm
+
+install_data(
+  'pg_trgm--1.0--1.1.sql',
+  'pg_trgm--1.1--1.2.sql',
+  'pg_trgm--1.2--1.3.sql',
+  'pg_trgm--1.3--1.4.sql',
+  'pg_trgm--1.3.sql',
+  'pg_trgm--1.4--1.5.sql',
+  'pg_trgm--1.5--1.6.sql',
+  'pg_trgm.control',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'pg_trgm',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'pg_trgm',
+      'pg_word_trgm',
+      'pg_strict_word_trgm',
+    ],
+  },
+}
diff --git a/contrib/pg_visibility/meson.build b/contrib/pg_visibility/meson.build
new file mode 100644
index 00000000000..933dc99ac4d
--- /dev/null
+++ b/contrib/pg_visibility/meson.build
@@ -0,0 +1,26 @@
+pg_visibility = shared_module('pg_visibility',
+  files(
+    'pg_visibility.c',
+  ),
+  kwargs: contrib_mod_args,
+)
+contrib_targets += pg_visibility
+
+install_data(
+  'pg_visibility--1.0--1.1.sql',
+  'pg_visibility--1.1--1.2.sql',
+  'pg_visibility--1.1.sql',
+  'pg_visibility.control',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'pg_visibility',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'pg_visibility',
+    ],
+  },
+}
diff --git a/contrib/pg_walinspect/meson.build b/contrib/pg_walinspect/meson.build
new file mode 100644
index 00000000000..d6b27877dd0
--- /dev/null
+++ b/contrib/pg_walinspect/meson.build
@@ -0,0 +1,27 @@
+pg_walinspect_sources = files('pg_walinspect.c')
+
+pg_walinspect = shared_module('pg_walinspect',
+  pg_walinspect_sources,
+  kwargs: contrib_mod_args + {
+      'dependencies': contrib_mod_args['dependencies'],
+  },
+)
+contrib_targets += pg_walinspect
+
+install_data(
+  'pg_walinspect.control',
+  'pg_walinspect--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'pg_walinspect',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'pg_walinspect',
+    ],
+    'regress_args': ['--temp-config', files('walinspect.conf')],
+  },
+}
diff --git a/contrib/pgcrypto/meson.build b/contrib/pgcrypto/meson.build
new file mode 100644
index 00000000000..fe0851bf8e8
--- /dev/null
+++ b/contrib/pgcrypto/meson.build
@@ -0,0 +1,100 @@
+if not ssl.found()
+  subdir_done()
+endif
+
+pgcrypto_sources = files(
+  'crypt-blowfish.c',
+  'crypt-des.c',
+  'crypt-gensalt.c',
+  'crypt-md5.c',
+  'mbuf.c',
+  'pgcrypto.c',
+  'pgp-armor.c',
+  'pgp-cfb.c',
+  'pgp-compress.c',
+  'pgp-decrypt.c',
+  'pgp-encrypt.c',
+  'pgp-info.c',
+  'pgp-mpi.c',
+  'pgp-pgsql.c',
+  'pgp-pubdec.c',
+  'pgp-pubenc.c',
+  'pgp-pubkey.c',
+  'pgp-s2k.c',
+  'pgp.c',
+  'px-crypt.c',
+  'px-hmac.c',
+  'px.c',
+)
+
+pgcrypto_regress = [
+  'init',
+  'md5',
+  'sha1',
+  'hmac-md5',
+  'hmac-sha1',
+  'blowfish',
+  'rijndael',
+  'sha2',
+  'des',
+  '3des',
+  'cast5',
+  'crypt-des',
+  'crypt-md5',
+  'crypt-blowfish',
+  'crypt-xdes',
+  'pgp-armor',
+  'pgp-decrypt',
+  'pgp-encrypt',
+  'pgp-pubkey-decrypt',
+  'pgp-pubkey-encrypt',
+  'pgp-info',
+]
+
+pgcrypto_openssl_sources = files(
+  'openssl.c',
+  'pgp-mpi-openssl.c',
+)
+
+pgcrypto_deps = []
+pgcrypto_link_with = []
+
+pgcrypto_deps += ssl
+pgcrypto_sources += pgcrypto_openssl_sources
+
+if zlib.found()
+  pgcrypto_deps += zlib
+  pgcrypto_regress += 'pgp-compression'
+else
+  pgcrypto_regress += 'pgp-zlib-DISABLED'
+endif
+
+pgcrypto = shared_module('pgcrypto',
+  pgcrypto_sources,
+  link_with: pgcrypto_link_with,
+  kwargs: contrib_mod_args + {
+    'dependencies': [pgcrypto_deps, contrib_mod_args['dependencies']]
+  },
+)
+contrib_targets += pgcrypto
+
+install_data(
+  'pgcrypto--1.0--1.1.sql',
+  'pgcrypto--1.1--1.2.sql',
+  'pgcrypto--1.2--1.3.sql',
+  'pgcrypto--1.3.sql',
+  'pgcrypto.control',
+  kwargs: contrib_data_args,
+)
+
+
+tests += {
+  'name': 'pgcrypto',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      pgcrypto_regress,
+    ],
+  },
+}
diff --git a/contrib/pgrowlocks/meson.build b/contrib/pgrowlocks/meson.build
new file mode 100644
index 00000000000..1b41691a2a3
--- /dev/null
+++ b/contrib/pgrowlocks/meson.build
@@ -0,0 +1,27 @@
+pgrowlocks = shared_module('pgrowlocks',
+  files(
+    'pgrowlocks.c',
+  ),
+  kwargs: contrib_mod_args,
+)
+contrib_targets += pgrowlocks
+
+install_data(
+  'pgrowlocks--1.0--1.1.sql',
+  'pgrowlocks--1.1--1.2.sql',
+  'pgrowlocks--1.2.sql',
+  'pgrowlocks.control',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'pgrowlocks',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'isolation': {
+    'specs': [
+      'pgrowlocks',
+    ],
+    'regress_args': ['--load-extension=pgrowlocks'],
+  },
+}
diff --git a/contrib/pgstattuple/meson.build b/contrib/pgstattuple/meson.build
new file mode 100644
index 00000000000..8e828692d5c
--- /dev/null
+++ b/contrib/pgstattuple/meson.build
@@ -0,0 +1,31 @@
+pgstattuple = shared_module('pgstattuple',
+  files(
+    'pgstatapprox.c',
+    'pgstatindex.c',
+    'pgstattuple.c',
+  ),
+  kwargs: contrib_mod_args,
+)
+contrib_targets += pgstattuple
+
+install_data(
+  'pgstattuple--1.0--1.1.sql',
+  'pgstattuple--1.1--1.2.sql',
+  'pgstattuple--1.2--1.3.sql',
+  'pgstattuple--1.3--1.4.sql',
+  'pgstattuple--1.4--1.5.sql',
+  'pgstattuple--1.4.sql',
+  'pgstattuple.control',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'pgstattuple',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'pgstattuple',
+    ],
+  },
+}
diff --git a/contrib/postgres_fdw/meson.build b/contrib/postgres_fdw/meson.build
new file mode 100644
index 00000000000..378885ec93b
--- /dev/null
+++ b/contrib/postgres_fdw/meson.build
@@ -0,0 +1,34 @@
+postgres_fdw_sources = files(
+  'connection.c',
+  'deparse.c',
+  'option.c',
+  'postgres_fdw.c',
+  'shippable.c',
+)
+
+postgres_fdw = shared_module('postgres_fdw',
+  postgres_fdw_sources,
+  kwargs: contrib_mod_args + {
+    'dependencies': contrib_mod_args['dependencies'] + [libpq],
+  },
+)
+contrib_targets += postgres_fdw
+
+install_data(
+  'postgres_fdw.control',
+  'postgres_fdw--1.0.sql',
+  'postgres_fdw--1.0--1.1.sql',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'postgres_fdw',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'postgres_fdw',
+    ],
+    'regress_args': ['--dlpath', meson.build_root() / 'src/test/regress'],
+  },
+}
diff --git a/contrib/seg/meson.build b/contrib/seg/meson.build
new file mode 100644
index 00000000000..e476eab2a77
--- /dev/null
+++ b/contrib/seg/meson.build
@@ -0,0 +1,51 @@
+seg_sources = files(
+  'seg.c',
+)
+
+seg_scan = custom_target('segscan',
+  input: 'segscan.l',
+  output: 'segscan.c',
+  command: flex_cmd,
+)
+generated_sources += seg_scan
+seg_sources += seg_scan
+
+seg_parse = custom_target('segparse',
+  input: 'segparse.y',
+  kwargs: bison_kw,
+)
+generated_sources += seg_parse.to_list()
+seg_sources += seg_parse
+
+seg = shared_module('seg',
+  seg_sources,
+  include_directories: include_directories('.'),
+  kwargs: contrib_mod_args,
+)
+contrib_targets += seg
+
+install_data(
+  'seg.control',
+  'seg--1.0--1.1.sql',
+  'seg--1.1--1.2.sql',
+  'seg--1.1.sql',
+  'seg--1.2--1.3.sql',
+  'seg--1.3--1.4.sql',
+  kwargs: contrib_data_args,
+)
+
+install_headers(
+  'segdata.h',
+  install_dir: dir_include_extension / 'seg',
+)
+
+tests += {
+  'name': 'seg',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'seg',
+    ],
+  },
+}
diff --git a/contrib/sepgsql/meson.build b/contrib/sepgsql/meson.build
new file mode 100644
index 00000000000..60a95e17c2f
--- /dev/null
+++ b/contrib/sepgsql/meson.build
@@ -0,0 +1,34 @@
+if not selinux.found()
+  subdir_done()
+endif
+
+sepgsql_sources = files(
+  'database.c',
+  'dml.c',
+  'hooks.c',
+  'label.c',
+  'proc.c',
+  'relation.c',
+  'schema.c',
+  'selinux.c',
+  'uavc.c',
+)
+
+sepgsql = shared_module('sepgsql',
+  sepgsql_sources,
+  kwargs: contrib_mod_args + {
+    'dependencies': [selinux, contrib_mod_args['dependencies']],
+  }
+)
+contrib_targets += sepgsql
+
+custom_target('sepgsql.sql',
+  input: 'sepgsql.sql.in',
+  output: 'sepgsql.sql',
+  command: [sed, '-e', 's,MODULE_PATHNAME,$libdir/sepgsql,g', '@INPUT@'],
+  capture: true,
+  install: true,
+  install_dir: contrib_data_args['install_dir'],
+)
+
+# TODO: implement sepgsql tests
diff --git a/contrib/spi/meson.build b/contrib/spi/meson.build
new file mode 100644
index 00000000000..98008980ec2
--- /dev/null
+++ b/contrib/spi/meson.build
@@ -0,0 +1,50 @@
+autoinc = shared_module('autoinc',
+  ['autoinc.c'],
+  kwargs: contrib_mod_args,
+)
+contrib_targets += autoinc
+
+install_data('autoinc.control', 'autoinc--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+
+insert_username = shared_module('insert_username',
+  ['insert_username.c'],
+  kwargs: contrib_mod_args,
+)
+contrib_targets += insert_username
+
+install_data(
+  'insert_username.control',
+  'insert_username--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+
+moddatetime = shared_module('moddatetime',
+  ['moddatetime.c'],
+  kwargs: contrib_mod_args,
+)
+contrib_targets += moddatetime
+
+install_data(
+  'moddatetime.control',
+  'moddatetime--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+# this is needed for the regression tests;
+# comment out if you want a quieter refint package for other uses
+refint_cflags = ['-DREFINT_VERBOSE']
+
+refint = shared_module('refint',
+  ['refint.c'],
+  c_args: refint_cflags,
+  kwargs: contrib_mod_args,
+)
+contrib_targets += refint
+
+install_data('refint.control', 'refint--1.0.sql',
+  kwargs: contrib_data_args,
+)
diff --git a/contrib/sslinfo/meson.build b/contrib/sslinfo/meson.build
new file mode 100644
index 00000000000..53f752a08ac
--- /dev/null
+++ b/contrib/sslinfo/meson.build
@@ -0,0 +1,21 @@
+if not ssl.found()
+  subdir_done()
+endif
+
+sslinfo = shared_module('sslinfo',
+  files(
+    'sslinfo.c',
+  ),
+  kwargs: contrib_mod_args + {
+    'dependencies': [ssl, contrib_mod_args['dependencies']],
+  }
+)
+contrib_targets += sslinfo
+
+install_data(
+  'sslinfo--1.0--1.1.sql',
+  'sslinfo--1.1--1.2.sql',
+  'sslinfo--1.2.sql',
+  'sslinfo.control',
+  kwargs: contrib_data_args,
+)
diff --git a/contrib/tablefunc/meson.build b/contrib/tablefunc/meson.build
new file mode 100644
index 00000000000..f4230096c0c
--- /dev/null
+++ b/contrib/tablefunc/meson.build
@@ -0,0 +1,24 @@
+tablefunc = shared_module('tablefunc',
+  files(
+    'tablefunc.c',
+  ),
+  kwargs: contrib_mod_args,
+)
+contrib_targets += tablefunc
+
+install_data(
+  'tablefunc--1.0.sql',
+  'tablefunc.control',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'tablefunc',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'tablefunc',
+    ],
+  },
+}
diff --git a/contrib/tcn/meson.build b/contrib/tcn/meson.build
new file mode 100644
index 00000000000..c3a025247d4
--- /dev/null
+++ b/contrib/tcn/meson.build
@@ -0,0 +1,25 @@
+tcn = shared_module('tcn',
+  files(
+    'tcn.c',
+  ),
+  kwargs: contrib_mod_args,
+)
+contrib_targets += tcn
+
+install_data(
+  'tcn--1.0.sql',
+  'tcn.control',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'tcn',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'isolation': {
+    'specs': [
+      'tcn',
+    ],
+    'regress_args': ['--load-extension=tcn'],
+  },
+}
diff --git a/contrib/test_decoding/meson.build b/contrib/test_decoding/meson.build
new file mode 100644
index 00000000000..dd7cb0101ad
--- /dev/null
+++ b/contrib/test_decoding/meson.build
@@ -0,0 +1,63 @@
+test_decoding_sources = files(
+  'test_decoding.c',
+)
+
+test_decoding = shared_module('test_decoding',
+  test_decoding_sources,
+  kwargs: contrib_mod_args,
+)
+contrib_targets += test_decoding
+
+tests += {
+  'name': 'test_decoding',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'ddl',
+      'xact',
+      'rewrite',
+      'toast',
+      'permissions',
+      'decoding_in_xact',
+      'decoding_into_rel',
+      'binary',
+      'prepared',
+      'replorigin',
+      'time',
+      'messages',
+      'spill',
+      'slot',
+      'truncate',
+      'stream',
+      'stats',
+      'twophase',
+      'twophase_stream',
+    ],
+    'regress_args': [
+      '--temp-config', files('logical.conf'),
+    ],
+  },
+  'isolation': {
+    'specs': [
+      'mxact',
+      'delayed_startup',
+      'ondisk_startup',
+      'concurrent_ddl_dml',
+      'oldest_xmin',
+      'snapshot_transfer',
+      'subxact_without_top',
+      'concurrent_stream',
+      'twophase_snapshot',
+      'slot_creation_error',
+    ],
+    'regress_args': [
+      '--temp-config', files('logical.conf'),
+    ],
+  },
+  'tap': {
+    'tests': [
+      't/001_repl_stats.pl',
+    ],
+  },
+}
diff --git a/contrib/tsm_system_rows/meson.build b/contrib/tsm_system_rows/meson.build
new file mode 100644
index 00000000000..b9cd42115a8
--- /dev/null
+++ b/contrib/tsm_system_rows/meson.build
@@ -0,0 +1,24 @@
+tsm_system_rows = shared_module('tsm_system_rows',
+  files(
+    'tsm_system_rows.c',
+  ),
+  kwargs: contrib_mod_args,
+)
+contrib_targets += tsm_system_rows
+
+install_data(
+  'tsm_system_rows--1.0.sql',
+  'tsm_system_rows.control',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'tsm_system_rows',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'tsm_system_rows',
+    ],
+  },
+}
diff --git a/contrib/tsm_system_time/meson.build b/contrib/tsm_system_time/meson.build
new file mode 100644
index 00000000000..18015912ffb
--- /dev/null
+++ b/contrib/tsm_system_time/meson.build
@@ -0,0 +1,24 @@
+tsm_system_time = shared_module('tsm_system_time',
+  files(
+    'tsm_system_time.c',
+  ),
+  kwargs: contrib_mod_args,
+)
+contrib_targets += tsm_system_time
+
+install_data(
+  'tsm_system_time--1.0.sql',
+  'tsm_system_time.control',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'tsm_system_time',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'tsm_system_time',
+    ],
+  },
+}
diff --git a/contrib/unaccent/meson.build b/contrib/unaccent/meson.build
new file mode 100644
index 00000000000..872b76e3223
--- /dev/null
+++ b/contrib/unaccent/meson.build
@@ -0,0 +1,32 @@
+unaccent = shared_module('unaccent',
+  files(
+    'unaccent.c',
+  ),
+  kwargs: contrib_mod_args,
+)
+contrib_targets += unaccent
+
+install_data(
+  'unaccent--1.0--1.1.sql',
+  'unaccent--1.1.sql',
+  'unaccent.control',
+  kwargs: contrib_data_args,
+)
+
+install_data(
+  'unaccent.rules',
+  install_dir: dir_data / 'tsearch_data'
+)
+
+# XXX: Implement downlo
+tests += {
+  'name': 'unaccent',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'unaccent',
+    ],
+    'regress_args': ['--encoding=UTF8'],
+  },
+}
diff --git a/contrib/uuid-ossp/meson.build b/contrib/uuid-ossp/meson.build
new file mode 100644
index 00000000000..da6d1d75c12
--- /dev/null
+++ b/contrib/uuid-ossp/meson.build
@@ -0,0 +1,31 @@
+if not uuid.found()
+  subdir_done()
+endif
+
+uuid_ossp = shared_module('uuid-ossp',
+  files(
+    'uuid-ossp.c',
+  ),
+  kwargs: contrib_mod_args + {
+    'dependencies': [uuid, contrib_mod_args['dependencies']],
+  },
+)
+contrib_targets += uuid_ossp
+
+install_data(
+  'uuid-ossp--1.0--1.1.sql',
+  'uuid-ossp--1.1.sql',
+  'uuid-ossp.control',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'uuid-ossp',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'uuid_ossp',
+    ],
+  },
+}
diff --git a/contrib/vacuumlo/meson.build b/contrib/vacuumlo/meson.build
new file mode 100644
index 00000000000..7a632b87d1b
--- /dev/null
+++ b/contrib/vacuumlo/meson.build
@@ -0,0 +1,17 @@
+vacuumlo = executable('vacuumlo',
+  ['vacuumlo.c'],
+  dependencies: [frontend_code, libpq],
+  kwargs: default_bin_args,
+)
+contrib_targets += vacuumlo
+
+tests += {
+  'name': 'vacuumlo',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'tests': [
+      't/001_basic.pl',
+    ],
+  },
+}
diff --git a/contrib/xml2/meson.build b/contrib/xml2/meson.build
new file mode 100644
index 00000000000..9c0b56f01f6
--- /dev/null
+++ b/contrib/xml2/meson.build
@@ -0,0 +1,32 @@
+if not libxml.found()
+  subdir_done()
+endif
+
+xml2 = shared_module('pgxml',
+  files(
+    'xpath.c',
+    'xslt_proc.c',
+  ),
+  kwargs: contrib_mod_args + {
+    'dependencies': [libxml, libxslt, contrib_mod_args['dependencies']],
+  },
+)
+contrib_targets += xml2
+
+install_data(
+  'xml2--1.0--1.1.sql',
+  'xml2--1.1.sql',
+  'xml2.control',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'xml2',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'xml2',
+    ],
+  },
+}
diff --git a/src/interfaces/ecpg/compatlib/meson.build b/src/interfaces/ecpg/compatlib/meson.build
new file mode 100644
index 00000000000..5887cb92b52
--- /dev/null
+++ b/src/interfaces/ecpg/compatlib/meson.build
@@ -0,0 +1,22 @@
+export_file = custom_target('libpq.exports', kwargs: gen_export_kwargs)
+
+ecpg_compat = both_libraries('libecpg_compat',
+  'informix.c',
+  include_directories: ['.', ecpg_inc, postgres_inc, libpq_inc],
+  c_args: ['-DSO_MAJOR_VERSION=3'],
+  dependencies: [frontend_code, thread_dep],
+  link_with: [ecpglib, ecpg_pgtypes],
+  soversion: host_system != 'windows' ? '3' : '',
+  darwin_versions: ['3', '3.' + pg_version_major.to_string()],
+  version: '3.' + pg_version_major.to_string(),
+  link_args: export_fmt.format(export_file.full_path()),
+  link_depends: export_file,
+  kwargs: default_lib_args,
+)
+ecpg_targets += [ecpg_compat.get_shared_lib(), ecpg_compat.get_static_lib()]
+
+pkgconfig.generate(
+  ecpg_compat.get_shared_lib(),
+  description: 'PostgreSQL libecpg_compat library',
+  url: pg_url,
+)
diff --git a/src/interfaces/ecpg/ecpglib/meson.build b/src/interfaces/ecpg/ecpglib/meson.build
new file mode 100644
index 00000000000..2da029ec8ea
--- /dev/null
+++ b/src/interfaces/ecpg/ecpglib/meson.build
@@ -0,0 +1,37 @@
+ecpglib_sources = files(
+  'connect.c',
+  'data.c',
+  'descriptor.c',
+  'error.c',
+  'execute.c',
+  'memory.c',
+  'misc.c',
+  'prepare.c',
+  'sqlda.c',
+  'typename.c',
+)
+
+export_file = custom_target('libpq.exports', kwargs: gen_export_kwargs)
+
+ecpglib = both_libraries('libecpg',
+  ecpglib_sources,
+  include_directories: ['.', ecpg_inc, postgres_inc],
+  c_args: ['-DSO_MAJOR_VERSION=6'],
+  dependencies: [frontend_code, libpq, thread_dep],
+  link_with: [ecpg_pgtypes],
+  soversion: host_system != 'windows' ? '6' : '',
+  darwin_versions: ['6', '6.' + pg_version_major.to_string()],
+  version: '6.' + pg_version_major.to_string(),
+  link_args: export_fmt.format(export_file.full_path()),
+  link_depends: export_file,
+  kwargs: default_lib_args,
+)
+ecpg_targets += [ecpglib.get_shared_lib(), ecpglib.get_static_lib()]
+
+pkgconfig.generate(
+  ecpglib.get_shared_lib(),
+  description: 'PostgreSQL libecpg library',
+  url: pg_url,
+)
+
+subdir('po', if_found: libintl)
diff --git a/src/interfaces/ecpg/ecpglib/po/meson.build b/src/interfaces/ecpg/ecpglib/po/meson.build
new file mode 100644
index 00000000000..246e399ebd3
--- /dev/null
+++ b/src/interfaces/ecpg/ecpglib/po/meson.build
@@ -0,0 +1 @@
+i18n.gettext('ecpglib' + '6' + '-' + pg_version_major.to_string())
diff --git a/src/interfaces/ecpg/include/meson.build b/src/interfaces/ecpg/include/meson.build
new file mode 100644
index 00000000000..c95d0455b9a
--- /dev/null
+++ b/src/interfaces/ecpg/include/meson.build
@@ -0,0 +1,51 @@
+ecpg_inc = include_directories('.')
+
+ecpg_conf_keys = [
+  'ENABLE_THREAD_SAFETY',
+  'HAVE_INT64',
+  'HAVE_LONG_INT_64',
+  'HAVE_LONG_LONG_INT_64',
+  'PG_USE_STDBOOL',
+]
+
+ecpg_conf_data = configuration_data()
+
+foreach key : ecpg_conf_keys
+  if cdata.has(key)
+    ecpg_conf_data.set(key, cdata.get(key))
+  endif
+endforeach
+
+ecpg_config_h = configure_file(
+  output: 'ecpg_config.h',
+  configuration: ecpg_conf_data,
+  install_dir: dir_include,
+)
+configure_files += ecpg_config_h
+
+generated_sources_ac += {'src/interfaces/ecpg/include': ['stamp-h']}
+
+install_headers(
+  'ecpg_informix.h',
+  'ecpgerrno.h',
+  'ecpglib.h',
+  'ecpgtype.h',
+  'pgtypes.h',
+  'pgtypes_date.h',
+  'pgtypes_error.h',
+  'pgtypes_interval.h',
+  'pgtypes_numeric.h',
+  'pgtypes_timestamp.h',
+  'sql3types.h',
+  'sqlca.h',
+  'sqlda.h',
+  'sqlda-compat.h',
+  'sqlda-native.h',
+)
+
+install_headers(
+  'datetime.h',
+  'decimal.h',
+  'sqltypes.h',
+  install_dir: dir_include_pkg / 'informix' / 'esql',
+)
diff --git a/src/interfaces/ecpg/meson.build b/src/interfaces/ecpg/meson.build
new file mode 100644
index 00000000000..f079b42269f
--- /dev/null
+++ b/src/interfaces/ecpg/meson.build
@@ -0,0 +1,9 @@
+ecpg_targets = []
+
+subdir('include')
+subdir('pgtypeslib')
+subdir('ecpglib')
+subdir('compatlib')
+subdir('preproc')
+
+alias_target('ecpg', ecpg_targets)
diff --git a/src/interfaces/ecpg/pgtypeslib/meson.build b/src/interfaces/ecpg/pgtypeslib/meson.build
new file mode 100644
index 00000000000..96489d9f1d7
--- /dev/null
+++ b/src/interfaces/ecpg/pgtypeslib/meson.build
@@ -0,0 +1,30 @@
+ecpg_pgtypes_sources = files(
+  'common.c',
+  'datetime.c',
+  'dt_common.c',
+  'interval.c',
+  'numeric.c',
+  'timestamp.c',
+)
+
+export_file = custom_target('libpq.exports', kwargs: gen_export_kwargs)
+
+ecpg_pgtypes = both_libraries('libpgtypes',
+  ecpg_pgtypes_sources,
+  include_directories: ['.', ecpg_inc, postgres_inc],
+  c_args: ['-DSO_MAJOR_VERSION=3'],
+  dependencies: [frontend_code],
+  version: '3.' + pg_version_major.to_string(),
+  soversion: host_system != 'windows' ? '3' : '',
+  darwin_versions: ['3', '3.' + pg_version_major.to_string()],
+  link_args: export_fmt.format(export_file.full_path()),
+  link_depends: export_file,
+  kwargs: default_lib_args,
+)
+ecpg_targets += [ecpg_pgtypes.get_shared_lib(), ecpg_pgtypes.get_static_lib()]
+
+pkgconfig.generate(
+  ecpg_pgtypes.get_shared_lib(),
+  description: 'PostgreSQL libpgtypes library',
+  url: pg_url,
+)
diff --git a/src/interfaces/ecpg/preproc/meson.build b/src/interfaces/ecpg/preproc/meson.build
new file mode 100644
index 00000000000..08956bbdbb6
--- /dev/null
+++ b/src/interfaces/ecpg/preproc/meson.build
@@ -0,0 +1,103 @@
+ecpg_sources = files(
+  '../ecpglib/typename.c',
+  'c_keywords.c',
+  'descriptor.c',
+  'ecpg.c',
+  'ecpg_keywords.c',
+  'keywords.c',
+  'output.c',
+  'parser.c',
+  'type.c',
+  'variable.c',
+)
+
+pgc = custom_target('pgc.c',
+  input: 'pgc.l',
+  output: 'pgc.c',
+  command: flex_cmd,
+)
+generated_sources += pgc
+ecpg_sources += pgc
+
+ecpg_files = [
+  'ecpg.addons',
+  'ecpg.header',
+  'ecpg.tokens',
+  'ecpg.trailer',
+  'ecpg.type',
+]
+
+preproc_y = custom_target('preproc.y',
+  input: [
+    '../../../backend/parser/gram.y',
+    ecpg_files,
+  ],
+  output: ['preproc.y'],
+  command: [
+    perl, files('parse.pl'),
+    '--srcdir', '@CURRENT_SOURCE_DIR@',
+    '--parser', '@INPUT0@',
+    '--output', '@OUTPUT0@',
+  ],
+)
+generated_sources += preproc_y
+
+check_rules = custom_target('preproc.y.check_rules',
+  input: [
+    '../../../backend/parser/gram.y',
+    ecpg_files,
+  ],
+  output: 'preproc.y.check_rules',
+  command: [
+    perl, files('check_rules.pl'),
+    '--srcdir', '@CURRENT_SOURCE_DIR@',
+    '--parser', '@INPUT0@',
+    '--stamp', '@OUTPUT0@',
+  ],
+)
+
+preproc = custom_target('preproc.c',
+  input: preproc_y,
+  kwargs: bison_kw,
+)
+generated_sources += preproc.to_list()
+ecpg_sources += preproc
+
+c_kwlist = custom_target('c_kwlist_d.h',
+  input: ['c_kwlist.h'],
+  output: ['c_kwlist_d.h'],
+  command: [
+    perl,
+    '-I', '@SOURCE_ROOT@/src/tools',
+    '@SOURCE_ROOT@/src/tools/gen_keywordlist.pl',
+    '--output', '@OUTDIR@',
+    '--varname', 'ScanCKeywords',
+    '--no-case-fold', '@INPUT0@',
+  ],
+)
+generated_sources += c_kwlist
+ecpg_sources += c_kwlist
+
+ecpg_kwlist = custom_target('ecpg_kwlist_d.h',
+  input: ['ecpg_kwlist.h'],
+  output: ['ecpg_kwlist_d.h'],
+  command: [
+    perl, '-I',
+    '@SOURCE_ROOT@/src/tools',
+    '@SOURCE_ROOT@/src/tools/gen_keywordlist.pl',
+    '--output', '@OUTDIR@',
+    '--varname', 'ScanECPGKeywords', '@INPUT0@',
+  ]
+)
+generated_sources += ecpg_kwlist
+ecpg_sources += ecpg_kwlist
+
+ecpg_exe = executable('ecpg',
+  ecpg_sources,
+  include_directories: ['.', ecpg_inc, postgres_inc, libpq_inc],
+  dependencies: [frontend_code],
+  kwargs: default_bin_args,
+)
+ecpg_targets += ecpg_exe
+
+subdir('po', if_found: libintl)
diff --git a/src/interfaces/ecpg/preproc/po/meson.build b/src/interfaces/ecpg/preproc/po/meson.build
new file mode 100644
index 00000000000..d73b05afd5e
--- /dev/null
+++ b/src/interfaces/ecpg/preproc/po/meson.build
@@ -0,0 +1 @@
+i18n.gettext('ecpg-' + pg_version_major.to_string())
diff --git a/src/interfaces/ecpg/test/compat_informix/meson.build b/src/interfaces/ecpg/test/compat_informix/meson.build
new file mode 100644
index 00000000000..6bb0d980761
--- /dev/null
+++ b/src/interfaces/ecpg/test/compat_informix/meson.build
@@ -0,0 +1,31 @@
+pgc_files = [
+  'charfuncs',
+  'dec_test',
+  'describe',
+  'rfmtdate',
+  'rfmtlong',
+  'rnull',
+  'sqlda',
+  'test_informix',
+  'test_informix2',
+]
+
+pgc_extra_flags = {
+  'rnull': ['-r', 'no_indicator',],
+}
+
+foreach pgc_file : pgc_files
+  exe_input = custom_target('@0@.c'.format(pgc_file),
+    input: '@0@.pgc'.format(pgc_file),
+    command: ecpg_preproc_test_command_start +
+      ['-C', 'INFORMIX',] +
+      pgc_extra_flags.get(pgc_file, []) +
+      ecpg_preproc_test_command_end,
+    kwargs: ecpg_preproc_kw,
+  )
+
+  ecpg_test_dependencies += executable(pgc_file,
+    exe_input,
+    kwargs: ecpg_test_exec_kw,
+  )
+endforeach
diff --git a/src/interfaces/ecpg/test/compat_oracle/meson.build b/src/interfaces/ecpg/test/compat_oracle/meson.build
new file mode 100644
index 00000000000..2e8794ba386
--- /dev/null
+++ b/src/interfaces/ecpg/test/compat_oracle/meson.build
@@ -0,0 +1,20 @@
+pgc_files = [
+  'char_array',
+]
+
+foreach pgc_file : pgc_files
+  exe_input = custom_target('@0@.c'.format(pgc_file),
+    input: '@0@.pgc'.format(pgc_file),
+    output: '@BASENAME@.c',
+    command: ecpg_preproc_test_command_start +
+      ['-C', 'ORACLE',] +
+      ecpg_preproc_test_command_end,
+    install: false,
+    build_by_default: false,
+  )
+
+  ecpg_test_dependencies += executable(pgc_file,
+    exe_input,
+    kwargs: ecpg_test_exec_kw,
+  )
+endforeach
diff --git a/src/interfaces/ecpg/test/connect/meson.build b/src/interfaces/ecpg/test/connect/meson.build
new file mode 100644
index 00000000000..0b1c3593146
--- /dev/null
+++ b/src/interfaces/ecpg/test/connect/meson.build
@@ -0,0 +1,20 @@
+pgc_files = [
+  'test1',
+  'test2',
+  'test3',
+  'test4',
+  'test5',
+]
+
+foreach pgc_file : pgc_files
+  exe_input = custom_target('@0@.c'.format(pgc_file),
+    input: '@0@.pgc'.format(pgc_file),
+    command: ecpg_preproc_test_command_start + ecpg_preproc_test_command_end,
+    kwargs: ecpg_preproc_kw,
+  )
+
+  ecpg_test_dependencies += executable(pgc_file,
+    exe_input,
+    kwargs: ecpg_test_exec_kw,
+  )
+endforeach
diff --git a/src/interfaces/ecpg/test/meson.build b/src/interfaces/ecpg/test/meson.build
new file mode 100644
index 00000000000..bd2489f2bb1
--- /dev/null
+++ b/src/interfaces/ecpg/test/meson.build
@@ -0,0 +1,79 @@
+pg_regress_ecpg_sources = pg_regress_c + files(
+  'pg_regress_ecpg.c',
+)
+
+pg_regress_ecpg = executable('pg_regress_ecpg',
+  pg_regress_ecpg_sources,
+  c_args: pg_regress_cflags,
+  include_directories: [pg_regress_inc, include_directories('.')],
+  dependencies: [frontend_code],
+  kwargs: default_bin_args + {
+    'install': false
+  },
+)
+testprep_targets += pg_regress_ecpg
+
+# create .c files and executables from .pgc files
+ecpg_test_exec_kw = {
+  'dependencies': [frontend_code, libpq],
+  'include_directories': [ecpg_inc],
+  'link_with': [ecpglib, ecpg_compat, ecpg_pgtypes],
+  'build_by_default': false,
+  'install': false,
+}
+
+ecpg_preproc_kw = {
+  'output': '@BASENAME@.c',
+  'install': false,
+  'build_by_default': false,
+}
+
+ecpg_preproc_test_command_start = [
+  ecpg_exe,
+  '--regression',
+  '-I@CURRENT_SOURCE_DIR@',
+  '-I@SOURCE_ROOT@' + '/src/interfaces/ecpg/include/',
+]
+ecpg_preproc_test_command_end = [
+  '-o', '@OUTPUT@', '@INPUT@'
+]
+
+ecpg_test_dependencies = []
+
+subdir('compat_informix')
+subdir('compat_oracle')
+subdir('connect')
+subdir('pgtypeslib')
+subdir('preproc')
+subdir('sql')
+subdir('thread')
+
+testprep_targets += ecpg_test_dependencies
+
+ecpg_test_files = files(
+  'ecpg_schedule',
+)
+
+ecpg_regress_args = [
+  '--dbname=ecpg1_regression,ecpg2_regression',
+  '--create-role=regress_ecpg_user1,regress_ecpg_user2',
+  '--encoding=SQL_ASCII',
+]
+
+tests += {
+  'name': 'ecpg',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'ecpg': {
+    'expecteddir': meson.current_source_dir(),
+    'inputdir': meson.current_build_dir(),
+    'schedule': ecpg_test_files,
+    'sql': [
+      'sql/twophase',
+    ],
+    'test_kwargs': {
+      'depends': meson.is_cross_build() ? [] : ecpg_test_dependencies,
+    },
+    'regress_args': ecpg_regress_args,
+  },
+}
diff --git a/src/interfaces/ecpg/test/pgtypeslib/meson.build b/src/interfaces/ecpg/test/pgtypeslib/meson.build
new file mode 100644
index 00000000000..2957f12abfc
--- /dev/null
+++ b/src/interfaces/ecpg/test/pgtypeslib/meson.build
@@ -0,0 +1,21 @@
+pgc_files = [
+  'dt_test',
+  'dt_test2',
+  'num_test',
+  'num_test2',
+  'nan_test',
+]
+
+foreach pgc_file : pgc_files
+  exe_input = custom_target('@0@.c'.format(pgc_file),
+    input: '@0@.pgc'.format(pgc_file),
+    command: ecpg_preproc_test_command_start +
+      ecpg_preproc_test_command_end,
+    kwargs: ecpg_preproc_kw,
+  )
+
+  ecpg_test_dependencies += executable(pgc_file,
+    exe_input,
+    kwargs: ecpg_test_exec_kw,
+  )
+endforeach
diff --git a/src/interfaces/ecpg/test/preproc/meson.build b/src/interfaces/ecpg/test/preproc/meson.build
new file mode 100644
index 00000000000..0608df2f2a2
--- /dev/null
+++ b/src/interfaces/ecpg/test/preproc/meson.build
@@ -0,0 +1,37 @@
+pgc_files = [
+  'array_of_struct',
+  'autoprep',
+  'comment',
+  'cursor',
+  'define',
+  'init',
+  'outofscope',
+  'pointer_to_struct',
+  'strings',
+  'type',
+  'variable',
+  'whenever',
+  'whenever_do_continue',
+]
+
+pgc_extra_flags = {
+  'array_of_struct': ['-c'],
+  'pointer_to_struct': ['-c'],
+  'autoprep': ['-r', 'prepare'],
+  'strings': ['-i'],
+}
+
+foreach pgc_file : pgc_files
+  exe_input = custom_target('@0@.c'.format(pgc_file),
+    input: '@0@.pgc'.format(pgc_file),
+    command: ecpg_preproc_test_command_start +
+      pgc_extra_flags.get(pgc_file, []) +
+      ecpg_preproc_test_command_end,
+    kwargs: ecpg_preproc_kw,
+  )
+
+  ecpg_test_dependencies += executable(pgc_file,
+    exe_input,
+    kwargs: ecpg_test_exec_kw,
+  )
+endforeach
diff --git a/src/interfaces/ecpg/test/sql/meson.build b/src/interfaces/ecpg/test/sql/meson.build
new file mode 100644
index 00000000000..bec7d4ed8f6
--- /dev/null
+++ b/src/interfaces/ecpg/test/sql/meson.build
@@ -0,0 +1,46 @@
+pgc_files = [
+  'array',
+  'binary',
+  'bytea',
+  'code100',
+  'copystdout',
+  'createtableas',
+  'declare',
+  'define',
+  'desc',
+  'describe',
+  'dynalloc',
+  'dynalloc2',
+  'dyntest',
+  'execute',
+  'fetch',
+  'func',
+  'indicators',
+  'insupd',
+  'oldexec',
+  'parser',
+  'prepareas',
+  'quote',
+  'show',
+  'sqlda',
+  'twophase',
+]
+
+pgc_extra_flags = {
+  'oldexec': ['-r', 'questionmarks'],
+}
+
+foreach pgc_file : pgc_files
+  exe_input = custom_target('@0@.c'.format(pgc_file),
+    input: '@0@.pgc'.format(pgc_file),
+    command: ecpg_preproc_test_command_start +
+      pgc_extra_flags.get(pgc_file, []) +
+      ecpg_preproc_test_command_end,
+    kwargs: ecpg_preproc_kw,
+  )
+
+  ecpg_test_dependencies += executable(pgc_file,
+    exe_input,
+    kwargs: ecpg_test_exec_kw,
+  )
+endforeach
diff --git a/src/interfaces/ecpg/test/thread/meson.build b/src/interfaces/ecpg/test/thread/meson.build
new file mode 100644
index 00000000000..2f1629e266b
--- /dev/null
+++ b/src/interfaces/ecpg/test/thread/meson.build
@@ -0,0 +1,21 @@
+pgc_files = [
+  'thread_implicit',
+  'thread',
+  'prep',
+  'descriptor',
+  'alloc',
+]
+
+foreach pgc_file : pgc_files
+  exe_input = custom_target('@0@.c'.format(pgc_file),
+    input: '@0@.pgc'.format(pgc_file),
+    command: ecpg_preproc_test_command_start +
+      ecpg_preproc_test_command_end,
+    kwargs: ecpg_preproc_kw,
+  )
+
+  ecpg_test_dependencies += executable(pgc_file,
+    exe_input,
+    kwargs: ecpg_test_exec_kw + {'dependencies': [frontend_code, libpq, thread_dep,]},
+  )
+endforeach
diff --git a/src/interfaces/meson.build b/src/interfaces/meson.build
new file mode 100644
index 00000000000..73fffbee394
--- /dev/null
+++ b/src/interfaces/meson.build
@@ -0,0 +1,2 @@
+# NB: libpq is entered directly from the toplevel meson file
+subdir('ecpg')
diff --git a/doc/src/sgml/meson.build b/doc/src/sgml/meson.build
new file mode 100644
index 00000000000..32b90f4f8c6
--- /dev/null
+++ b/doc/src/sgml/meson.build
@@ -0,0 +1,252 @@
+docs = []
+alldocs = []
+doc_generated = []
+
+xmllint = find_program(get_option('XMLLINT'), native: true, required: false)
+
+
+version_sgml = configure_file(
+  input: 'version.sgml.in',
+  output: 'version.sgml',
+  configuration: cdata,
+)
+configure_files += version_sgml
+
+doc_generated += custom_target('features-supported.sgml',
+  input: files(
+    '../../../src/backend/catalog/sql_feature_packages.txt',
+    '../../../src/backend/catalog/sql_features.txt',
+  ),
+  output: 'features-supported.sgml',
+  command: [perl, files('mk_feature_tables.pl'), 'YES', '@INPUT@'],
+  build_by_default: false,
+  install: false,
+  capture: true,
+)
+
+doc_generated += custom_target('features-unsupported.sgml',
+  input: files(
+    '../../../src/backend/catalog/sql_feature_packages.txt',
+    '../../../src/backend/catalog/sql_features.txt',
+  ),
+  output: 'features-unsupported.sgml',
+  command: [perl, files('mk_feature_tables.pl'), 'NO', '@INPUT@'],
+  build_by_default: false,
+  install: false,
+  capture: true,
+)
+
+doc_generated += custom_target('errcodes-table.sgml',
+  input: files(
+    '../../../src/backend/utils/errcodes.txt'),
+  output: 'errcodes-table.sgml',
+  command: [perl, files('generate-errcodes-table.pl'), '@INPUT@'],
+  build_by_default: false,
+  install: false,
+  capture: true,
+)
+
+# FIXME: this actually has further inputs, adding depfile support to
+# generate-keywords-table.pl is probably the best way to address that
+# robustly.
+doc_generated += custom_target('keywords-table.sgml',
+  input: files(
+    '../../../src/include/parser/kwlist.h'),
+  output: 'keywords-table.sgml',
+  command: [perl, files('generate-keywords-table.pl'), '@CURRENT_SOURCE_DIR@'],
+  build_by_default: false,
+  install: false,
+  capture: true,
+)
+
+# For everything else we need at least xmllint
+if not xmllint.found()
+  subdir_done()
+endif
+
+pandoc = find_program('pandoc', native: true, required: false)
+xsltproc = find_program(get_option('XSLTPROC'), native: true, required: false)
+fop = find_program('fop', native: true, required: false)
+
+# Compute validity just once
+# Run validation only once, common to all subsequent targets.  While
+# we're at it, also resolve all entities (that is, copy all included
+# files into one big file).  This helps tools that don't understand
+# vpath builds (such as dbtoepub).
+postgres_full_xml = custom_target('postgres-full.xml',
+  input: 'postgres.sgml',
+  output: 'postgres-full.xml',
+  command: [xmllint, '--noent', '--valid', '--path', '@OUTDIR@', '-o', '@OUTPUT@', '@INPUT@'],
+  depends: doc_generated,
+  build_by_default: true,
+)
+
+#
+# Full documentation as html, text
+#
+if xsltproc.found()
+  xsltproc_flags = [
+    '--stringparam', 'pg.version', pg_version,
+    '--param', 'website.stylesheet', '1'
+  ]
+
+
+  # FIXME: Should use a wrapper around xsltproc --load-trace to compute a
+  # depfile
+  html = custom_target('html',
+    input: ['stylesheet.xsl', postgres_full_xml],
+    output: 'html',
+    depends: doc_generated,
+    command: [xsltproc, '-o', '@OUTDIR@/', xsltproc_flags, '@INPUT@'],
+    build_by_default: false,
+  )
+  alldocs += html
+
+  # build multi-page html docs as part of docs target
+  docs += html
+
+  html_help = custom_target('html_help',
+    input: ['stylesheet-hh.xsl', postgres_full_xml],
+    output: 'htmlhelp',
+    depends: doc_generated,
+    command: [xsltproc, '--path', '@OUTDIR@', '-o', '@OUTDIR@/', xsltproc_flags, '@INPUT@'],
+    build_by_default: false,
+  )
+  alldocs += html_help
+
+
+  # single-page HTML
+  postgres_html = custom_target('postgres.html',
+    input: ['stylesheet-html-nochunk.xsl', postgres_full_xml],
+    output: 'postgres.html',
+    depends: doc_generated,
+    command: [xsltproc, '--path', '@OUTDIR@', '-o', '@OUTPUT@', xsltproc_flags, '@INPUT@'],
+    build_by_default: false,
+  )
+  alldocs += postgres_html
+
+  # single-page text
+  if pandoc.found()
+    postgres_txt = custom_target('postgres.txt',
+      input: [postgres_html],
+      output: 'postgres.txt',
+      depends: doc_generated,
+      command: [pandoc, '-t', 'plain', '-o', '@OUTPUT@', '@INPUT@'],
+      build_by_default: false,
+    )
+    alldocs += postgres_txt
+  endif
+endif
+
+
+#
+# INSTALL in html, text
+#
+if xsltproc.found()
+  install_xml = custom_target('INSTALL.xml',
+    input: ['standalone-profile.xsl', 'standalone-install.xml'],
+    output: 'INSTALL.xml',
+    depends: doc_generated + [postgres_full_xml],
+    command: [xsltproc, '--path', '@OUTDIR@', '-o', '@OUTPUT@', xsltproc_flags, '--xinclude', '@INPUT@'],
+    build_by_default: false,
+  )
+  install_html = custom_target('INSTALL.html',
+    input: ['stylesheet-text.xsl', install_xml],
+    output: 'INSTALL.html',
+    command: [xsltproc, '--path', '@OUTDIR@', '-o', '@OUTPUT@', xsltproc_flags, '@INPUT@'],
+    build_by_default: false,
+  )
+  alldocs += install_html
+
+  if pandoc.found()
+    # XXX: Makefile does an iconv translit here, but unclear why?
+    install = custom_target('INSTALL',
+      input: [install_html],
+      output: 'INSTALL',
+      command: [pandoc, '-t', 'plain', '-o', '@OUTPUT@', '@INPUT@'],
+      build_by_default: false,
+    )
+    alldocs += install
+  endif
+
+endif
+
+
+#
+# Man pages
+#
+if xsltproc.found()
+  # FIXME: implement / consider sqlmansectnum logic
+  man = custom_target('man',
+    input: ['stylesheet-man.xsl', postgres_full_xml],
+    output: ['man1', 'man3', 'man7'],
+    depends: doc_generated,
+    command: [xsltproc, '--path', '@OUTDIR@', '-o', '@OUTDIR@/', xsltproc_flags, '@INPUT@'],
+    build_by_default: false,
+  )
+
+  # build by default as part of docs target
+  docs += man
+endif
+
+
+#
+# Full documentation as PDF
+#
+if fop.found() and xsltproc.found()
+  xsltproc_fo_flags = xsltproc_flags + ['--stringparam', 'img.src.path', meson.current_source_dir() + '/']
+
+  foreach format, detail: {'A4': 'A4', 'US': 'USletter'}
+    postgres_x_fo_f = 'postgres-@0@.fo'.format(format)
+    postgres_x_pdf_f = 'postgres-@0@.pdf'.format(format)
+
+    postgres_x_fo = custom_target(postgres_x_fo_f,
+      input: ['stylesheet-fo.xsl', postgres_full_xml],
+      output: [postgres_x_fo_f],
+      depends: doc_generated,
+      command: [xsltproc, '--path', '@OUTDIR@/', xsltproc_fo_flags,
+                '--stringparam', 'paper.type', detail,
+                '-o', '@OUTPUT@', '@INPUT@'],
+      build_by_default: false,
+    )
+
+    postgres_x_pdf = custom_target(postgres_x_pdf_f,
+      input: [postgres_x_fo],
+      output: [postgres_x_pdf_f],
+      command: [fop, '-fo', '@INPUT@', '-pdf', '@OUTPUT@'],
+      build_by_default: false,
+    )
+    alldocs += postgres_x_pdf
+  endforeach
+endif
+
+
+#
+# epub
+#
+
+# This was previously implemented using dbtoepub - but that doesn't seem to
+# support running in build != source directory (i.e. VPATH builds already
+# weren't supported).
+if pandoc.found() and xsltproc.found()
+  postgres_epub = custom_target('postgres.epub',
+    input: postgres_full_xml,
+    output: 'postgres.epub',
+    command: [pandoc, '-f', 'docbook', '-t', 'epub', '-o', '@OUTPUT@', '--resource-path=@CURRENT_SOURCE_DIR@',
+              '@INPUT@'],
+    build_by_default: false,
+  )
+  alldocs += postgres_epub
+endif
+
+if docs.length() == 0
+  run_target('docs', command: [missing, 'xsltproc'])
+else
+  alias_target('docs', docs)
+endif
+
+if alldocs.length() == 0
+  run_target('alldocs', command: [missing, 'xsltproc'])
+else
+  alias_target('alldocs', alldocs)
+endif
diff --git a/doc/src/sgml/version.sgml.in b/doc/src/sgml/version.sgml.in
new file mode 100644
index 00000000000..fa5ff343f40
--- /dev/null
+++ b/doc/src/sgml/version.sgml.in
@@ -0,0 +1,2 @@
+<!ENTITY version @PG_VERSION@>
+<!ENTITY majorversion @PG_MAJORVERSION@>
diff --git a/src/test/authentication/meson.build b/src/test/authentication/meson.build
new file mode 100644
index 00000000000..2374028cbda
--- /dev/null
+++ b/src/test/authentication/meson.build
@@ -0,0 +1,11 @@
+tests += {
+  'name': 'authentication',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'tests': [
+      't/001_password.pl',
+      't/002_saslprep.pl',
+    ],
+  },
+}
diff --git a/src/test/icu/meson.build b/src/test/icu/meson.build
new file mode 100644
index 00000000000..5a4f53f37ff
--- /dev/null
+++ b/src/test/icu/meson.build
@@ -0,0 +1,11 @@
+tests += {
+  'name': 'icu',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'tests': [
+      't/010_database.pl',
+    ],
+    'env': {'with_icu': icu.found() ? 'yes' : 'no'},
+  },
+}
diff --git a/src/test/isolation/meson.build b/src/test/isolation/meson.build
new file mode 100644
index 00000000000..c7656fd4609
--- /dev/null
+++ b/src/test/isolation/meson.build
@@ -0,0 +1,58 @@
+# pg_regress_c helpfully provided by regress/meson.build
+
+isolation_sources = pg_regress_c + files(
+  'isolation_main.c',
+)
+
+isolationtester_sources = files(
+  'isolationtester.c',
+)
+
+spec_scanner = custom_target('specscanner',
+  input: 'specscanner.l',
+  output: 'specscanner.c',
+  command: flex_cmd,
+)
+isolationtester_sources += spec_scanner
+generated_sources += spec_scanner
+
+spec_parser = custom_target('specparse',
+  input: 'specparse.y',
+  kwargs: bison_kw,
+)
+isolationtester_sources += spec_parser
+generated_sources += spec_parser.to_list()
+
+pg_isolation_regress = executable('pg_isolation_regress',
+  isolation_sources,
+  c_args: pg_regress_cflags,
+  include_directories: pg_regress_inc,
+  dependencies: frontend_code,
+  kwargs: default_bin_args + {
+    'install_dir': dir_pgxs / 'src/test/isolation',
+  },
+)
+bin_targets += pg_isolation_regress
+
+isolationtester = executable('isolationtester',
+  isolationtester_sources,
+  include_directories: include_directories('.'),
+  dependencies: [frontend_code, libpq],
+  kwargs: default_bin_args + {
+    'install_dir': dir_pgxs / 'src/test/isolation',
+  },
+)
+bin_targets += isolationtester
+
+tests += {
+  'name': 'main',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'isolation': {
+    'schedule': files('isolation_schedule'),
+    'test_kwargs': {
+      'priority': 40,
+      'timeout': 1000,
+    },
+  },
+}
diff --git a/src/test/kerberos/meson.build b/src/test/kerberos/meson.build
new file mode 100644
index 00000000000..7e2b6733fcc
--- /dev/null
+++ b/src/test/kerberos/meson.build
@@ -0,0 +1,15 @@
+tests += {
+  'name': 'kerberos',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'test_kwargs': {'priority': 40}, # kerberos tests are slow, start early
+    'tests': [
+      't/001_auth.pl',
+    ],
+    'env': {
+      'with_gssapi': gssapi.found() ? 'yes' : 'no',
+      'with_krb_srvnam': 'postgres',
+    },
+  },
+}
diff --git a/src/test/ldap/meson.build b/src/test/ldap/meson.build
new file mode 100644
index 00000000000..2211bd5e3ec
--- /dev/null
+++ b/src/test/ldap/meson.build
@@ -0,0 +1,11 @@
+tests += {
+  'name': 'ldap',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'tests': [
+      't/001_auth.pl',
+    ],
+    'env': {'with_ldap': ldap.found() ? 'yes' : 'no'},
+  },
+}
diff --git a/src/test/meson.build b/src/test/meson.build
new file mode 100644
index 00000000000..241d9d48aa5
--- /dev/null
+++ b/src/test/meson.build
@@ -0,0 +1,25 @@
+subdir('regress')
+subdir('isolation')
+
+subdir('authentication')
+subdir('recovery')
+subdir('subscription')
+subdir('modules')
+
+if ssl.found()
+  subdir('ssl')
+endif
+
+if ldap.found()
+  subdir('ldap')
+endif
+
+if gssapi.found()
+  subdir('kerberos')
+endif
+
+if icu.found()
+  subdir('icu')
+endif
+
+subdir('perl')
diff --git a/src/test/modules/brin/meson.build b/src/test/modules/brin/meson.build
new file mode 100644
index 00000000000..58254d093a4
--- /dev/null
+++ b/src/test/modules/brin/meson.build
@@ -0,0 +1,16 @@
+tests += {
+  'name': 'brin',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'isolation': {
+    'specs': [
+      'summarization-and-inprogress-insertion',
+    ],
+  },
+  'tap': {
+    'tests': [
+      't/01_workitems.pl',
+      't/02_wal_consistency.pl',
+    ],
+  },
+}
diff --git a/src/test/modules/commit_ts/meson.build b/src/test/modules/commit_ts/meson.build
new file mode 100644
index 00000000000..60cb12164d2
--- /dev/null
+++ b/src/test/modules/commit_ts/meson.build
@@ -0,0 +1,18 @@
+tests += {
+  'name': 'commit_ts',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'commit_timestamp',
+    ],
+  },
+  'tap': {
+    'tests': [
+      't/001_base.pl',
+      't/002_standby.pl',
+      't/003_standby_2.pl',
+      't/004_restart.pl',
+    ],
+  },
+}
diff --git a/src/test/modules/delay_execution/meson.build b/src/test/modules/delay_execution/meson.build
new file mode 100644
index 00000000000..cf4bdaba637
--- /dev/null
+++ b/src/test/modules/delay_execution/meson.build
@@ -0,0 +1,18 @@
+# FIXME: prevent install during main install, but not during test :/
+delay_execution = shared_module('delay_execution',
+  ['delay_execution.c'],
+  kwargs: pg_mod_args,
+)
+testprep_targets += delay_execution
+
+tests += {
+  'name': 'delay_execution',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'isolation': {
+    'specs': [
+      'partition-addition',
+      'partition-removal-1',
+    ],
+  },
+}
diff --git a/src/test/modules/dummy_index_am/meson.build b/src/test/modules/dummy_index_am/meson.build
new file mode 100644
index 00000000000..56ff5f48001
--- /dev/null
+++ b/src/test/modules/dummy_index_am/meson.build
@@ -0,0 +1,23 @@
+# FIXME: prevent install during main install, but not during test :/
+dummy_index_am = shared_module('dummy_index_am',
+  ['dummy_index_am.c'],
+  kwargs: pg_mod_args,
+)
+testprep_targets += dummy_index_am
+
+install_data(
+  'dummy_index_am.control',
+  'dummy_index_am--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'dummy_index_am',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'reloptions',
+    ],
+  },
+}
diff --git a/src/test/modules/dummy_seclabel/meson.build b/src/test/modules/dummy_seclabel/meson.build
new file mode 100644
index 00000000000..21b7cf8f353
--- /dev/null
+++ b/src/test/modules/dummy_seclabel/meson.build
@@ -0,0 +1,23 @@
+# FIXME: prevent install during main install, but not during test :/
+dummy_seclabel = shared_module('dummy_seclabel',
+  ['dummy_seclabel.c'],
+  kwargs: pg_mod_args,
+)
+testprep_targets += dummy_seclabel
+
+install_data(
+  'dummy_seclabel.control',
+  'dummy_seclabel--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'dummy_seclabel',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'dummy_seclabel',
+    ],
+  },
+}
diff --git a/src/test/modules/libpq_pipeline/meson.build b/src/test/modules/libpq_pipeline/meson.build
new file mode 100644
index 00000000000..8384b6e3b2a
--- /dev/null
+++ b/src/test/modules/libpq_pipeline/meson.build
@@ -0,0 +1,21 @@
+libpq_pipeline = executable('libpq_pipeline',
+  files(
+    'libpq_pipeline.c',
+  ),
+  dependencies: [frontend_code, libpq],
+  kwargs: default_bin_args + {
+    'install': false,
+  },
+)
+testprep_targets += libpq_pipeline
+
+tests += {
+  'name': 'libpq_pipeline',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'tests': [
+      't/001_libpq_pipeline.pl',
+    ],
+  },
+}
diff --git a/src/test/modules/meson.build b/src/test/modules/meson.build
new file mode 100644
index 00000000000..a80e6e2ce29
--- /dev/null
+++ b/src/test/modules/meson.build
@@ -0,0 +1,27 @@
+subdir('brin')
+subdir('commit_ts')
+subdir('delay_execution')
+subdir('dummy_index_am')
+subdir('dummy_seclabel')
+subdir('libpq_pipeline')
+subdir('plsample')
+subdir('snapshot_too_old')
+subdir('spgist_name_ops')
+subdir('ssl_passphrase_callback')
+subdir('test_bloomfilter')
+subdir('test_ddl_deparse')
+subdir('test_extensions')
+subdir('test_ginpostinglist')
+subdir('test_integerset')
+subdir('test_lfind')
+subdir('test_misc')
+subdir('test_oat_hooks')
+subdir('test_parser')
+subdir('test_pg_dump')
+subdir('test_predtest')
+subdir('test_rbtree')
+subdir('test_regex')
+subdir('test_rls_hooks')
+subdir('test_shm_mq')
+subdir('unsafe_tests')
+subdir('worker_spi')
diff --git a/src/test/modules/plsample/meson.build b/src/test/modules/plsample/meson.build
new file mode 100644
index 00000000000..45de3f1990d
--- /dev/null
+++ b/src/test/modules/plsample/meson.build
@@ -0,0 +1,23 @@
+# FIXME: prevent install during main install, but not during test :/
+plsample = shared_module('plsample',
+  ['plsample.c'],
+  kwargs: pg_mod_args,
+)
+testprep_targets += plsample
+
+install_data(
+  'plsample.control',
+  'plsample--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'plsample',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'plsample',
+    ],
+  },
+}
diff --git a/src/test/modules/snapshot_too_old/meson.build b/src/test/modules/snapshot_too_old/meson.build
new file mode 100644
index 00000000000..efd3f1f113b
--- /dev/null
+++ b/src/test/modules/snapshot_too_old/meson.build
@@ -0,0 +1,14 @@
+tests += {
+  'name': 'snapshot_too_old',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'isolation': {
+    'test_kwargs': {'priority': 40}, # sto tests are slow, start early
+    'specs': [
+      'sto_using_cursor',
+      'sto_using_select',
+      'sto_using_hash_index',
+    ],
+    'regress_args': ['--temp-config', files('sto.conf')],
+  },
+}
diff --git a/src/test/modules/spgist_name_ops/meson.build b/src/test/modules/spgist_name_ops/meson.build
new file mode 100644
index 00000000000..857fc7e140e
--- /dev/null
+++ b/src/test/modules/spgist_name_ops/meson.build
@@ -0,0 +1,23 @@
+# FIXME: prevent install during main install, but not during test :/
+spgist_name_ops = shared_module('spgist_name_ops',
+  ['spgist_name_ops.c'],
+  kwargs: pg_mod_args,
+)
+testprep_targets += spgist_name_ops
+
+install_data(
+  'spgist_name_ops.control',
+  'spgist_name_ops--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'spgist_name_ops',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'spgist_name_ops',
+    ],
+  },
+}
diff --git a/src/test/modules/ssl_passphrase_callback/meson.build b/src/test/modules/ssl_passphrase_callback/meson.build
new file mode 100644
index 00000000000..62d2c276513
--- /dev/null
+++ b/src/test/modules/ssl_passphrase_callback/meson.build
@@ -0,0 +1,48 @@
+if not ssl.found()
+  subdir_done()
+endif
+
+# FIXME: prevent install during main install, but not during test :/
+ssl_passphrase_callback = shared_module('ssl_passphrase_func',
+  ['ssl_passphrase_func.c'],
+  kwargs: pg_mod_args + {
+    'dependencies': [ssl, pg_mod_args['dependencies']],
+  },
+)
+testprep_targets += ssl_passphrase_callback
+
+# Targets to generate or remove the ssl certificate and key. Need to be copied
+# to the source afterwards. Normally not needed.
+
+openssl = find_program('openssl', native: true, required: false)
+
+if openssl.found()
+  cert = custom_target('server.crt',
+    output: ['server.crt', 'server.ckey'],
+    command: [openssl, 'req', '-new', '-x509', '-days', '10000', '-nodes', '-out', '@OUTPUT0@',
+      '-keyout', '@OUTPUT1@', '-subj', '/CN=localhost'],
+    build_by_default: false,
+    install: false,
+  )
+
+  # needs to agree with what's in the test script
+  pass = 'FooBaR1'
+
+  enccert = custom_target('server.key',
+    input: [cert[1]],
+    output: ['server.key'],
+    command: [openssl, 'rsa', '-aes256', '-in', '@INPUT0@', '-out', '@OUTPUT0@', '-passout', 'pass:@0@'.format(pass)]
+  )
+endif
+
+tests += {
+  'name': 'ssl_passphrase_callback',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'tests': [
+      't/001_testfunc.pl',
+    ],
+    'env': {'with_ssl': 'openssl'},
+  },
+}
diff --git a/src/test/modules/test_bloomfilter/meson.build b/src/test/modules/test_bloomfilter/meson.build
new file mode 100644
index 00000000000..945eb5a70c4
--- /dev/null
+++ b/src/test/modules/test_bloomfilter/meson.build
@@ -0,0 +1,23 @@
+# FIXME: prevent install during main install, but not during test :/
+test_bloomfilter = shared_module('test_bloomfilter',
+  ['test_bloomfilter.c'],
+  kwargs: pg_mod_args,
+)
+testprep_targets += test_bloomfilter
+
+install_data(
+  'test_bloomfilter.control',
+  'test_bloomfilter--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'test_bloomfilter',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'test_bloomfilter',
+    ],
+  },
+}
diff --git a/src/test/modules/test_ddl_deparse/meson.build b/src/test/modules/test_ddl_deparse/meson.build
new file mode 100644
index 00000000000..81ad5adc526
--- /dev/null
+++ b/src/test/modules/test_ddl_deparse/meson.build
@@ -0,0 +1,43 @@
+# FIXME: prevent install during main install, but not during test :/
+test_ddl_deparse = shared_module('test_ddl_deparse',
+  ['test_ddl_deparse.c'],
+  kwargs: pg_mod_args,
+)
+testprep_targets += test_ddl_deparse
+
+install_data(
+  'test_ddl_deparse.control',
+  'test_ddl_deparse--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'test_ddl_deparse',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'test_ddl_deparse',
+      'create_extension',
+      'create_schema',
+      'create_type',
+      'create_conversion',
+      'create_domain',
+      'create_sequence_1',
+      'create_table',
+      'create_transform',
+      'alter_table',
+      'create_view',
+      'create_trigger',
+      'create_rule',
+      'comment_on',
+      'alter_function',
+      'alter_sequence',
+      'alter_ts_config',
+      'alter_type_enum',
+      'opfamily',
+      'defprivs',
+      'matviews',
+    ],
+  },
+}
diff --git a/src/test/modules/test_extensions/meson.build b/src/test/modules/test_extensions/meson.build
new file mode 100644
index 00000000000..e95a9f2e7eb
--- /dev/null
+++ b/src/test/modules/test_extensions/meson.build
@@ -0,0 +1,45 @@
+# FIXME: prevent install during main install, but not during test :/
+install_data(
+  'test_ext1--1.0.sql',
+  'test_ext1.control',
+  'test_ext2--1.0.sql',
+  'test_ext2.control',
+  'test_ext3--1.0.sql',
+  'test_ext3.control',
+  'test_ext4--1.0.sql',
+  'test_ext4.control',
+  'test_ext5--1.0.sql',
+  'test_ext5.control',
+  'test_ext6--1.0.sql',
+  'test_ext6.control',
+  'test_ext7--1.0--2.0.sql',
+  'test_ext7--1.0.sql',
+  'test_ext7.control',
+  'test_ext8--1.0.sql',
+  'test_ext8.control',
+  'test_ext_cine--1.0.sql',
+  'test_ext_cine--1.0--1.1.sql',
+  'test_ext_cine.control',
+  'test_ext_cor--1.0.sql',
+  'test_ext_cor.control',
+  'test_ext_cyclic1--1.0.sql',
+  'test_ext_cyclic1.control',
+  'test_ext_cyclic2--1.0.sql',
+  'test_ext_cyclic2.control',
+  'test_ext_evttrig--1.0--2.0.sql',
+  'test_ext_evttrig--1.0.sql',
+  'test_ext_evttrig.control',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'test_extensions',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'test_extensions',
+      'test_extdepend',
+    ],
+  },
+}
diff --git a/src/test/modules/test_ginpostinglist/meson.build b/src/test/modules/test_ginpostinglist/meson.build
new file mode 100644
index 00000000000..abf0a3b0430
--- /dev/null
+++ b/src/test/modules/test_ginpostinglist/meson.build
@@ -0,0 +1,23 @@
+# FIXME: prevent install during main install, but not during test :/
+test_ginpostinglist = shared_module('test_ginpostinglist',
+  ['test_ginpostinglist.c'],
+  kwargs: pg_mod_args,
+)
+testprep_targets += test_ginpostinglist
+
+install_data(
+  'test_ginpostinglist.control',
+  'test_ginpostinglist--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'test_ginpostinglist',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'test_ginpostinglist',
+    ],
+  },
+}
diff --git a/src/test/modules/test_integerset/meson.build b/src/test/modules/test_integerset/meson.build
new file mode 100644
index 00000000000..c32c469c69a
--- /dev/null
+++ b/src/test/modules/test_integerset/meson.build
@@ -0,0 +1,23 @@
+# FIXME: prevent install during main install, but not during test :/
+test_integerset = shared_module('test_integerset',
+  ['test_integerset.c'],
+  kwargs: pg_mod_args,
+)
+testprep_targets += test_integerset
+
+install_data(
+  'test_integerset.control',
+  'test_integerset--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'test_integerset',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'test_integerset',
+    ],
+  },
+}
diff --git a/src/test/modules/test_lfind/meson.build b/src/test/modules/test_lfind/meson.build
new file mode 100644
index 00000000000..a388de1156a
--- /dev/null
+++ b/src/test/modules/test_lfind/meson.build
@@ -0,0 +1,23 @@
+# FIXME: prevent install during main install, but not during test :/
+test_lfind = shared_module('test_lfind',
+  ['test_lfind.c'],
+  kwargs: pg_mod_args,
+)
+testprep_targets += test_lfind
+
+install_data(
+  'test_lfind.control',
+  'test_lfind--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'test_lfind',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'test_lfind',
+    ],
+  },
+}
diff --git a/src/test/modules/test_misc/meson.build b/src/test/modules/test_misc/meson.build
new file mode 100644
index 00000000000..cfc830ff399
--- /dev/null
+++ b/src/test/modules/test_misc/meson.build
@@ -0,0 +1,12 @@
+tests += {
+  'name': 'test_misc',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'tests': [
+      't/001_constraint_validation.pl',
+      't/002_tablespace.pl',
+      't/003_check_guc.pl',
+    ],
+  },
+}
diff --git a/src/test/modules/test_oat_hooks/meson.build b/src/test/modules/test_oat_hooks/meson.build
new file mode 100644
index 00000000000..5faf0459777
--- /dev/null
+++ b/src/test/modules/test_oat_hooks/meson.build
@@ -0,0 +1,18 @@
+# FIXME: prevent install during main install, but not during test :/
+test_oat_hooks = shared_module('test_oat_hooks',
+  ['test_oat_hooks.c'],
+  kwargs: pg_mod_args,
+)
+testprep_targets += test_oat_hooks
+
+tests += {
+  'name': 'test_oat_hooks',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'test_oat_hooks',
+    ],
+    'regress_args': ['--no-locale', '--encoding=UTF8'],
+  },
+}
diff --git a/src/test/modules/test_parser/meson.build b/src/test/modules/test_parser/meson.build
new file mode 100644
index 00000000000..b59960f615e
--- /dev/null
+++ b/src/test/modules/test_parser/meson.build
@@ -0,0 +1,23 @@
+# FIXME: prevent install during main install, but not during test :/
+test_parser = shared_module('test_parser',
+  ['test_parser.c'],
+  kwargs: pg_mod_args,
+)
+testprep_targets += test_parser
+
+install_data(
+  'test_parser.control',
+  'test_parser--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'test_parser',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'test_parser',
+    ],
+  },
+}
diff --git a/src/test/modules/test_pg_dump/meson.build b/src/test/modules/test_pg_dump/meson.build
new file mode 100644
index 00000000000..41021829f3a
--- /dev/null
+++ b/src/test/modules/test_pg_dump/meson.build
@@ -0,0 +1,22 @@
+# FIXME: prevent install during main install, but not during test :/
+install_data(
+  'test_pg_dump.control',
+  'test_pg_dump--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'test_pg_dump',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'test_pg_dump',
+    ],
+  },
+  'tap': {
+    'tests': [
+      't/001_base.pl',
+    ],
+  },
+}
diff --git a/src/test/modules/test_predtest/meson.build b/src/test/modules/test_predtest/meson.build
new file mode 100644
index 00000000000..1cfa84b3609
--- /dev/null
+++ b/src/test/modules/test_predtest/meson.build
@@ -0,0 +1,23 @@
+# FIXME: prevent install during main install, but not during test :/
+test_predtest = shared_module('test_predtest',
+  ['test_predtest.c'],
+  kwargs: pg_mod_args,
+)
+testprep_targets += test_predtest
+
+install_data(
+  'test_predtest.control',
+  'test_predtest--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'test_predtest',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'test_predtest',
+    ],
+  },
+}
diff --git a/src/test/modules/test_rbtree/meson.build b/src/test/modules/test_rbtree/meson.build
new file mode 100644
index 00000000000..34cbc3e1624
--- /dev/null
+++ b/src/test/modules/test_rbtree/meson.build
@@ -0,0 +1,23 @@
+# FIXME: prevent install during main install, but not during test :/
+test_rbtree = shared_module('test_rbtree',
+  ['test_rbtree.c'],
+  kwargs: pg_mod_args,
+)
+testprep_targets += test_rbtree
+
+install_data(
+  'test_rbtree.control',
+  'test_rbtree--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'test_rbtree',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'test_rbtree',
+    ],
+  },
+}
diff --git a/src/test/modules/test_regex/meson.build b/src/test/modules/test_regex/meson.build
new file mode 100644
index 00000000000..867a64e57c3
--- /dev/null
+++ b/src/test/modules/test_regex/meson.build
@@ -0,0 +1,24 @@
+# FIXME: prevent install during main install, but not during test :/
+test_regex = shared_module('test_regex',
+  ['test_regex.c'],
+  kwargs: pg_mod_args,
+)
+testprep_targets += test_regex
+
+install_data(
+  'test_regex.control',
+  'test_regex--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'test_regex',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'test_regex',
+      'test_regex_utf8',
+    ],
+  },
+}
diff --git a/src/test/modules/test_rls_hooks/meson.build b/src/test/modules/test_rls_hooks/meson.build
new file mode 100644
index 00000000000..80d8adda332
--- /dev/null
+++ b/src/test/modules/test_rls_hooks/meson.build
@@ -0,0 +1,17 @@
+# FIXME: prevent install during main install, but not during test :/
+test_rls_hooks = shared_module('test_rls_hooks',
+  ['test_rls_hooks.c'],
+  kwargs: pg_mod_args,
+)
+testprep_targets += test_rls_hooks
+
+tests += {
+  'name': 'test_rls_hooks',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'test_rls_hooks',
+    ],
+  },
+}
diff --git a/src/test/modules/test_shm_mq/meson.build b/src/test/modules/test_shm_mq/meson.build
new file mode 100644
index 00000000000..b663543d616
--- /dev/null
+++ b/src/test/modules/test_shm_mq/meson.build
@@ -0,0 +1,27 @@
+# FIXME: prevent install during main install, but not during test :/
+test_shm_mq = shared_module('test_shm_mq',
+  files(
+    'setup.c',
+    'test.c',
+    'worker.c',
+  ),
+  kwargs: pg_mod_args,
+)
+testprep_targets += test_shm_mq
+
+install_data(
+  'test_shm_mq.control',
+  'test_shm_mq--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'test_shm_mq',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'test_shm_mq',
+    ],
+  },
+}
diff --git a/src/test/modules/unsafe_tests/meson.build b/src/test/modules/unsafe_tests/meson.build
new file mode 100644
index 00000000000..d69b0e7ce44
--- /dev/null
+++ b/src/test/modules/unsafe_tests/meson.build
@@ -0,0 +1,11 @@
+tests += {
+  'name': 'unsafe_tests',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'rolenames',
+      'alter_system_table',
+    ],
+  },
+}
diff --git a/src/test/modules/worker_spi/meson.build b/src/test/modules/worker_spi/meson.build
new file mode 100644
index 00000000000..32acad883b2
--- /dev/null
+++ b/src/test/modules/worker_spi/meson.build
@@ -0,0 +1,26 @@
+# FIXME: prevent install during main install, but not during test :/
+test_worker_spi = shared_module('worker_spi',
+  files(
+    'worker_spi.c',
+  ),
+  kwargs: pg_mod_args,
+)
+testprep_targets += test_worker_spi
+
+install_data(
+  'worker_spi.control',
+  'worker_spi--1.0.sql',
+  kwargs: contrib_data_args,
+)
+
+tests += {
+  'name': 'worker_spi',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'worker_spi',
+    ],
+    'regress_args': ['--temp-config', files('dynamic.conf'), '--dbname=contrib_regression'],
+  },
+}
diff --git a/src/test/perl/meson.build b/src/test/perl/meson.build
new file mode 100644
index 00000000000..901bae7a564
--- /dev/null
+++ b/src/test/perl/meson.build
@@ -0,0 +1,12 @@
+# could use install_data's preserve_path option in >=0.64.0
+
+install_data(
+  'PostgreSQL/Version.pm',
+  install_dir: dir_pgxs / 'src/test/perl/PostgreSQL')
+
+install_data(
+  'PostgreSQL/Test/Utils.pm',
+  'PostgreSQL/Test/SimpleTee.pm',
+  'PostgreSQL/Test/RecursiveCopy.pm',
+  'PostgreSQL/Test/Cluster.pm',
+  install_dir: dir_pgxs / 'src/test/perl/PostgreSQL/Test')
diff --git a/src/test/recovery/meson.build b/src/test/recovery/meson.build
new file mode 100644
index 00000000000..b0e398363f7
--- /dev/null
+++ b/src/test/recovery/meson.build
@@ -0,0 +1,43 @@
+tests += {
+  'name': 'recovery',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'test_kwargs': {'priority': 40}, # recovery tests are slow, start early
+    'tests': [
+      't/001_stream_rep.pl',
+      't/002_archiving.pl',
+      't/003_recovery_targets.pl',
+      't/004_timeline_switch.pl',
+      't/005_replay_delay.pl',
+      't/006_logical_decoding.pl',
+      't/007_sync_rep.pl',
+      't/008_fsm_truncation.pl',
+      't/009_twophase.pl',
+      't/010_logical_decoding_timelines.pl',
+      't/011_crash_recovery.pl',
+      't/012_subtransactions.pl',
+      't/013_crash_restart.pl',
+      't/014_unlogged_reinit.pl',
+      't/015_promotion_pages.pl',
+      't/016_min_consistency.pl',
+      't/017_shm.pl',
+      't/018_wal_optimize.pl',
+      't/019_replslot_limit.pl',
+      't/020_archive_status.pl',
+      't/021_row_visibility.pl',
+      't/022_crash_temp_files.pl',
+      't/023_pitr_prepared_xact.pl',
+      't/024_archive_recovery.pl',
+      't/025_stuck_on_old_timeline.pl',
+      't/026_overwrite_contrecord.pl',
+      't/027_stream_regress.pl',
+      't/028_pitr_timelines.pl',
+      't/029_stats_restart.pl',
+      't/030_stats_cleanup_replica.pl',
+      't/031_recovery_conflict.pl',
+      't/032_relfilenode_reuse.pl',
+      't/033_replay_tsp_drops.pl',
+    ],
+  },
+}
diff --git a/src/test/regress/meson.build b/src/test/regress/meson.build
new file mode 100644
index 00000000000..fd8ee995b79
--- /dev/null
+++ b/src/test/regress/meson.build
@@ -0,0 +1,62 @@
+# also used by isolationtester and ecpg tests
+pg_regress_c = files('pg_regress.c')
+pg_regress_inc = include_directories('.')
+
+regress_sources = pg_regress_c + files(
+  'pg_regress_main.c'
+)
+
+pg_regress_cflags = ['-DHOST_TUPLE="frak"', '-DSHELLPROG="/bin/sh"']
+
+pg_regress = executable('pg_regress',
+  regress_sources,
+  c_args: pg_regress_cflags,
+  dependencies: [frontend_code],
+  kwargs: default_bin_args + {
+    'install_dir': dir_pgxs / 'src/test/regress',
+  },
+)
+bin_targets += pg_regress
+
+regress_module = shared_module('regress',
+  ['regress.c'],
+  kwargs: pg_mod_args + {
+    'install': false,
+  },
+)
+testprep_targets += regress_module
+
+# Get some extra C modules from contrib/spi but mark them as not to be
+# installed.
+# FIXME: avoid the duplication.
+
+autoinc_regress = shared_module('autoinc',
+  ['../../../contrib/spi/autoinc.c'],
+  kwargs: pg_mod_args + {
+    'install': false,
+  },
+)
+testprep_targets += autoinc_regress
+
+refint_regress = shared_module('refint',
+  ['../../../contrib/spi/refint.c'],
+  c_args: refint_cflags,
+  kwargs: pg_mod_args + {
+    'install': false,
+  },
+)
+testprep_targets += refint_regress
+
+
+tests += {
+  'name': 'main',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'schedule': files('parallel_schedule'),
+    'test_kwargs': {
+      'priority': 50,
+      'timeout': 1000,
+    },
+  },
+}
diff --git a/src/test/ssl/meson.build b/src/test/ssl/meson.build
new file mode 100644
index 00000000000..e2f021d884a
--- /dev/null
+++ b/src/test/ssl/meson.build
@@ -0,0 +1,13 @@
+tests += {
+  'name': 'ssl',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'env': {'with_ssl': get_option('ssl')},
+    'tests': [
+      't/001_ssltests.pl',
+      't/002_scram.pl',
+      't/003_sslinfo.pl',
+    ],
+  },
+}
diff --git a/src/test/subscription/meson.build b/src/test/subscription/meson.build
new file mode 100644
index 00000000000..85d1dd92951
--- /dev/null
+++ b/src/test/subscription/meson.build
@@ -0,0 +1,42 @@
+tests += {
+  'name': 'subscription',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'tap': {
+    'env': {'with_icu': icu.found() ? 'yes' : 'no'},
+    'tests': [
+      't/001_rep_changes.pl',
+      't/002_types.pl',
+      't/003_constraints.pl',
+      't/004_sync.pl',
+      't/005_encoding.pl',
+      't/006_rewrite.pl',
+      't/007_ddl.pl',
+      't/008_diff_schema.pl',
+      't/009_matviews.pl',
+      't/010_truncate.pl',
+      't/011_generated.pl',
+      't/012_collation.pl',
+      't/013_partition.pl',
+      't/014_binary.pl',
+      't/015_stream.pl',
+      't/016_stream_subxact.pl',
+      't/017_stream_ddl.pl',
+      't/018_stream_subxact_abort.pl',
+      't/019_stream_subxact_ddl_abort.pl',
+      't/020_messages.pl',
+      't/021_twophase.pl',
+      't/022_twophase_cascade.pl',
+      't/023_twophase_stream.pl',
+      't/024_add_drop_pub.pl',
+      't/025_rep_changes_for_schema.pl',
+      't/026_stats.pl',
+      't/027_nosuperuser.pl',
+      't/028_row_filter.pl',
+      't/029_on_error.pl',
+      't/030_origin.pl',
+      't/031_column_list.pl',
+      't/100_bugs.pl',
+    ],
+  },
+}
diff --git a/configure b/configure
index aee8a0d3579..d509c264a0b 100755
--- a/configure
+++ b/configure
@@ -20651,3 +20651,9 @@ if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
 fi
 
+
+# Ensure that any meson build directories would reconfigure and see that
+# there's a conflicting in-tree build and can error out.
+if test "$vpath_build"="no"; then
+  touch meson.build
+fi
diff --git a/configure.ac b/configure.ac
index 33634ccad9d..b2a93b259f1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2467,3 +2467,9 @@ AC_CONFIG_HEADERS([src/interfaces/ecpg/include/ecpg_config.h],
                   [echo >src/interfaces/ecpg/include/stamp-h])
 
 AC_OUTPUT
+
+# Ensure that any meson build directories would reconfigure and see that
+# there's a conflicting in-tree build and can error out.
+if test "$vpath_build"="no"; then
+  touch meson.build
+fi
diff --git a/meson.build b/meson.build
new file mode 100644
index 00000000000..d5411831e82
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,3027 @@
+# Entry point for building PostgreSQL with meson
+#
+# Good starting points for writing meson.build files are:
+#  - https://mesonbuild.com/Syntax.html
+#  - https://mesonbuild.com/Reference-manual.html
+
+project('postgresql',
+  ['c'],
+  version: '16devel',
+  license: 'PostgreSQL',
+
+  # We want < 0.56 for python 3.5 compatibility on old platforms. EPEL for
+  # RHEL 7 has 0.55. < 0.54 would require replacing some uses of the fs
+  # module, < 0.53 all uses of fs. So far there's no need to go to >=0.56.
+  meson_version: '>=0.54',
+  default_options: [
+    'warning_level=1', #-Wall equivalent
+    'buildtype=release',
+  ]
+)
+
+
+
+###############################################################
+# Basic prep
+###############################################################
+
+fs = import('fs')
+pkgconfig = import('pkgconfig')
+
+host_system = host_machine.system()
+host_cpu = host_machine.cpu_family()
+
+cc = meson.get_compiler('c')
+
+not_found_dep = dependency('', required: false)
+thread_dep = dependency('threads')
+
+
+
+###############################################################
+# Safety first
+###############################################################
+
+# It's very easy to get into confusing states when the source directory
+# contains an in-place build. E.g. the wrong pg_config.h will be used. So just
+# refuse to build in that case.
+#
+# There's a more elaborate check later, that checks for conflicts around all
+# generated files. But we can only do that much further down the line, so this
+# quick check seems worth it. Adhering to this advice should clean up the
+# conflict, but won't protect against somebody doing make distclean or just
+# removing pg_config.h
+errmsg_nonclean_base = '''
+****
+Non-clean source code directory detected.
+
+To build with meson the source tree may not have an in-place, ./configure
+style, build configured. You can have both meson and ./configure style builds
+for the same source tree by building out-of-source / VPATH with
+configure. Alternatively use a separate check out for meson based builds.
+
+@0@
+****'''
+if fs.exists(meson.current_source_dir() / 'src' / 'include' / 'pg_config.h')
+  errmsg_cleanup = 'To clean up, run make maintainer-clean in the source tree.'
+  error(errmsg_nonclean_base.format(errmsg_cleanup))
+endif
+
+
+
+###############################################################
+# Variables to be determined
+###############################################################
+
+postgres_inc_d = ['src/include']
+postgres_inc_d += get_option('extra_include_dirs')
+
+postgres_lib_d = get_option('extra_lib_dirs')
+
+cppflags = []
+
+cflags = []
+cxxflags = []
+cflags_warn = []
+cxxflags_warn = []
+cflags_mod = []
+cxxflags_mod = []
+
+ldflags = []
+ldflags_be = []
+ldflags_sl = []
+ldflags_mod = []
+
+test_c_args = []
+
+os_deps = []
+backend_both_deps = []
+backend_deps = []
+libpq_deps = []
+
+pg_sysroot = ''
+
+# source of data for pg_config.h etc
+cdata = configuration_data()
+
+
+
+###############################################################
+# Version and other metadata
+###############################################################
+
+pg_version = meson.project_version()
+
+if pg_version.endswith('devel')
+  pg_version_arr = [pg_version.split('devel')[0], '0']
+elif pg_version.contains('beta')
+  pg_version_arr = [pg_version.split('beta')[0], '0']
+elif pg_version.contains('rc')
+  pg_version_arr = [pg_version.split('rc')[0], '0']
+else
+  pg_version_arr = pg_version.split('.')
+endif
+
+pg_version_major = pg_version_arr[0].to_int()
+pg_version_minor = pg_version_arr[1].to_int()
+pg_version_num = (pg_version_major * 10000) + pg_version_minor
+
+pg_url = 'https://www.postgresql.org/'
+
+cdata.set_quoted('PACKAGE_NAME', 'PostgreSQL')
+cdata.set_quoted('PACKAGE_BUGREPORT', 'pgsql-bugs@lists.postgresql.org')
+cdata.set_quoted('PACKAGE_URL', pg_url)
+cdata.set_quoted('PACKAGE_VERSION', pg_version)
+cdata.set_quoted('PACKAGE_STRING', 'PostgreSQL @0@'.format(pg_version))
+cdata.set_quoted('PACKAGE_TARNAME', 'postgresql')
+
+pg_version += get_option('extra_version')
+cdata.set_quoted('PG_VERSION', pg_version)
+cdata.set_quoted('PG_VERSION_STR', 'PostgreSQL @0@ on @1@, compiled by @2@-@3@'.format(
+  pg_version, build_machine.cpu_family(), cc.get_id(), cc.version()))
+cdata.set_quoted('PG_MAJORVERSION', pg_version_major.to_string())
+cdata.set('PG_MAJORVERSION_NUM', pg_version_major)
+cdata.set('PG_MINORVERSION_NUM', pg_version_minor)
+cdata.set('PG_VERSION_NUM', pg_version_num)
+cdata.set_quoted('CONFIGURE_ARGS', '')
+
+
+
+###############################################################
+# Basic platform specific configuration
+###############################################################
+
+# meson's system names don't quite map to our "traditional" names. In some
+# places we need the "traditional" name, e.g., for mapping
+# src/include/port/$os.h to src/include/pg_config_os.h. Define portname for
+# that purpose.
+portname = host_system
+
+exesuffix = '' # overridden below where necessary
+dlsuffix = '.so' # overridden below where necessary
+library_path_var = 'LD_LIBRARY_PATH'
+
+# Format of file to control exports from libraries, and how to pass them to
+# the compiler. For export_fmt @0@ is the path to the file export file.
+export_file_format = 'gnu'
+export_file_suffix = 'list'
+export_fmt = '-Wl,--version-script=@0@'
+
+# Flags to add when linking a postgres extension, @0@ is path to
+# the relevant object on the platform.
+mod_link_args_fmt = []
+
+memset_loop_limit = 1024
+
+# Choice of shared memory and semaphore implementation
+shmem_kind = 'sysv'
+sema_kind = 'sysv'
+
+# We implement support for some operating systems by pretending they're
+# another. Map here, before determining system properties below
+if host_system == 'dragonfly'
+  # apparently the most similar
+  host_system = 'netbsd'
+endif
+
+if host_system == 'aix'
+  ld_library_path_var = 'LIBPATH'
+
+  export_file_format = 'aix'
+  export_fmt = '-Wl,-bE:@0@'
+  mod_link_args_fmt = ['-Wl,-bI:@0@']
+  mod_link_with_dir = 'libdir'
+  mod_link_with_name = '@0@.imp'
+
+  # M:SRE sets a flag indicating that an object is a shared library. Seems to
+  # work in some circumstances without, but required in others.
+  ldflags_sl += '-Wl,-bM:SRE'
+  ldflags_be += '-Wl,-brtllib'
+
+  # Native memset() is faster, tested on:
+  # - AIX 5.1 and 5.2, XLC 6.0 (IBM's cc)
+  # - AIX 5.3 ML3, gcc 4.0.1
+  memset_loop_limit = 0
+
+elif host_system == 'cygwin'
+  cppflags += '-D_GNU_SOURCE'
+
+elif host_system == 'darwin'
+  dlsuffix = '.dylib'
+  ld_library_path_var = 'DYLD_LIBRARY_PATH'
+
+  export_file_format = 'darwin'
+  export_fmt = '-exported_symbols_list=@0@'
+
+  mod_link_args_fmt = ['-bundle_loader', '@0@']
+  mod_link_with_dir = 'bindir'
+  mod_link_with_name = '@0@'
+
+  sysroot_args = [files('src/tools/darwin_sysroot'), get_option('darwin_sysroot')]
+  pg_sysroot = run_command(sysroot_args, check:true).stdout().strip()
+  message('darwin sysroot: @0@'.format(pg_sysroot))
+  cflags += ['-isysroot', pg_sysroot]
+  ldflags += ['-isysroot', pg_sysroot]
+
+elif host_system == 'freebsd'
+  sema_kind = 'unnamed_posix'
+
+elif host_system == 'linux'
+  sema_kind = 'unnamed_posix'
+  cppflags += '-D_GNU_SOURCE'
+
+elif host_system == 'netbsd'
+  # We must resolve all dynamic linking in the core server at program start.
+  # Otherwise the postmaster can self-deadlock due to signals interrupting
+  # resolution of calls, since NetBSD's linker takes a lock while doing that
+  # and some postmaster signal handlers do things that will also acquire that
+  # lock.  As long as we need "-z now", might as well specify "-z relro" too.
+  # While there's not a hard reason to adopt these settings for our other
+  # executables, there's also little reason not to, so just add them to
+  # LDFLAGS.
+  ldflags += ['-Wl,-z,now', '-Wl,-z,relro']
+
+elif host_system == 'openbsd'
+  # you're ok
+
+elif host_system == 'sunos'
+  portname = 'solaris'
+  export_fmt = '-Wl,-M@0@'
+  cppflags += '-D_POSIX_PTHREAD_SEMANTICS'
+
+elif host_system == 'windows'
+  portname = 'win32'
+  exesuffix = '.exe'
+  dlsuffix = '.dll'
+  ld_library_path_var = ''
+
+  export_file_format = 'win'
+  export_file_suffix = 'def'
+  if cc.get_id() == 'msvc'
+    export_fmt = '/DEF:@0@'
+    mod_link_with_name = '@0@.exe.lib'
+  else
+    export_fmt = '@0@'
+    mod_link_with_name = 'lib@0@.exe.a'
+  endif
+  mod_link_args_fmt = ['@0@']
+  mod_link_with_dir = 'libdir'
+
+  shmem_kind = 'win32'
+  sema_kind = 'win32'
+
+  cdata.set('WIN32_STACK_RLIMIT', 4194304)
+  if cc.get_id() == 'msvc'
+    ldflags += '/INCREMENTAL:NO'
+    ldflags += '/STACK:@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))
+    # ldflags += '/nxcompat' # generated by msbuild, should have it for ninja?
+  else
+    ldflags += '-Wl,--stack,@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))
+  endif
+
+  os_deps += cc.find_library('ws2_32', required: true)
+  secur32_dep = cc.find_library('secur32', required: true)
+  backend_deps += secur32_dep
+  libpq_deps += secur32_dep
+
+  postgres_inc_d += 'src/include/port/win32'
+  if cc.get_id() == 'msvc'
+    postgres_inc_d += 'src/include/port/win32_msvc'
+  endif
+
+  windows = import('windows')
+
+else
+  # XXX: Should we add an option to override the host_system as an escape
+  # hatch?
+  error('unknown host system: @0@'.format(host_system))
+endif
+
+
+
+###############################################################
+# Program paths
+###############################################################
+
+# External programs
+perl = find_program(get_option('PERL'), required: true, native: true)
+python = find_program(get_option('PYTHON'), required: true, native: true)
+flex = find_program(get_option('FLEX'), native: true, version: '>= 2.5.31')
+bison = find_program(get_option('BISON'), native: true, version: '>= 1.875')
+sed = find_program(get_option('SED'), 'sed', native: true)
+prove = find_program(get_option('PROVE'), native: true)
+tar = find_program(get_option('TAR'), native: true)
+gzip = find_program(get_option('GZIP'), native: true)
+program_lz4 = find_program(get_option('LZ4'), native: true, required: false)
+touch = find_program('touch', native: true)
+program_zstd = find_program(get_option('ZSTD'), native: true, required: false)
+dtrace = find_program(get_option('DTRACE'), native: true, required: get_option('dtrace'))
+missing = find_program('config/missing', native: true)
+
+# used by PGXS
+install_sh = find_program('config/install-sh', native: true)
+
+bison_flags = []
+if bison.found()
+  bison_version_c = run_command(bison, '--version', check: true)
+  # bison version string helpfully is something like
+  # >>bison (GNU bison) 3.8.1<<
+  bison_version = bison_version_c.stdout().split(' ')[3].split('\n')[0]
+  if bison_version.version_compare('>=3.0')
+    bison_flags += ['-Wno-deprecated']
+  endif
+endif
+bison_cmd = [bison, bison_flags, '-o', '@OUTPUT0@', '-d', '@INPUT@']
+bison_kw = {
+  'output': ['@BASENAME@.c', '@BASENAME@.h'],
+  'command': bison_cmd,
+}
+
+flex_flags = []
+flex_wrapper = files('src/tools/pgflex')
+flex_cmd = [python, flex_wrapper,
+  '--builddir', '@BUILD_ROOT@',
+  '--srcdir', '@SOURCE_ROOT@',
+  '--privatedir', '@PRIVATE_DIR@',
+  '--flex', flex, '--perl', perl,
+  '-i', '@INPUT@', '-o', '@OUTPUT0@',
+]
+
+wget = find_program('wget', required: false, native: true)
+wget_flags = ['-O', '@OUTPUT0@', '--no-use-server-timestamps']
+
+
+
+###############################################################
+# Path to meson (for tests etc)
+###############################################################
+
+# NB: this should really be part of meson, see
+# https://github.com/mesonbuild/meson/issues/8511
+meson_binpath_r = run_command(python, 'src/tools/find_meson', check: true)
+
+if meson_binpath_r.returncode() != 0 or meson_binpath_r.stdout() == ''
+  error('huh, could not run find_meson.\nerrcode: @0@\nstdout: @1@\nstderr: @2@'.format(
+    meson_binpath_r.returncode(),
+    meson_binpath_r.stdout(),
+    meson_binpath_r.stderr()))
+endif
+
+meson_binpath_s = meson_binpath_r.stdout().split('\n')
+meson_binpath_len = meson_binpath_s.length()
+
+if meson_binpath_len < 1
+  error('unexpected introspect line @0@'.format(meson_binpath_r.stdout()))
+endif
+
+i = 0
+meson_impl = ''
+meson_binpath = ''
+meson_args = []
+foreach e : meson_binpath_s
+  if i == 0
+    meson_impl = e
+  elif i == 1
+    meson_binpath = e
+  else
+    meson_args += e
+  endif
+  i += 1
+endforeach
+
+if meson_impl not in ['muon', 'meson']
+  error('unknown meson implementation "@0@"'.format(meson_impl))
+endif
+
+meson_bin = find_program(meson_binpath, native: true)
+
+
+
+###############################################################
+# Option Handling
+###############################################################
+
+cdata.set('USE_ASSERT_CHECKING', get_option('cassert') ? 1 : false)
+
+cdata.set('BLCKSZ', get_option('blocksize').to_int() * 1024, description:
+'''Size of a disk block --- this also limits the size of a tuple. You can set
+   it bigger if you need bigger tuples (although TOAST should reduce the need
+   to have large tuples, since fields can be spread across multiple tuples).
+   BLCKSZ must be a power of 2. The maximum possible value of BLCKSZ is
+   currently 2^15 (32768). This is determined by the 15-bit widths of the
+   lp_off and lp_len fields in ItemIdData (see include/storage/itemid.h).
+   Changing BLCKSZ requires an initdb.''')
+
+cdata.set('XLOG_BLCKSZ', get_option('wal_blocksize').to_int() * 1024)
+cdata.set('RELSEG_SIZE', get_option('segsize') * 131072)
+cdata.set('DEF_PGPORT', get_option('pgport'))
+cdata.set_quoted('DEF_PGPORT_STR', get_option('pgport').to_string())
+cdata.set_quoted('PG_KRB_SRVNAM', get_option('krb_srvnam'))
+if get_option('system_tzdata') != ''
+  cdata.set_quoted('SYSTEMTZDIR', get_option('system_tzdata'))
+endif
+
+
+
+###############################################################
+# Directories
+###############################################################
+
+# These are set by the equivalent --xxxdir configure options.  We
+# append "postgresql" to some of them, if the string does not already
+# contain "pgsql" or "postgres", in order to avoid directory clutter.
+
+pkg = 'postgresql'
+
+dir_prefix = get_option('prefix')
+
+dir_bin = get_option('bindir')
+
+dir_data = get_option('datadir')
+if not (dir_data.contains('pgsql') or dir_data.contains('postgres'))
+  dir_data = dir_data / pkg
+endif
+
+dir_sysconf = get_option('sysconfdir')
+if not (dir_sysconf.contains('pgsql') or dir_sysconf.contains('postgres'))
+  dir_sysconf = dir_sysconf / pkg
+endif
+
+dir_lib = get_option('libdir')
+
+dir_lib_pkg = dir_lib
+if not (dir_lib_pkg.contains('pgsql') or dir_lib_pkg.contains('postgres'))
+  dir_lib_pkg = dir_lib_pkg / pkg
+endif
+
+dir_pgxs = dir_lib_pkg / 'pgxs'
+
+dir_include = get_option('includedir')
+
+dir_include_pkg = dir_include
+dir_include_pkg_rel = ''
+if not (dir_include_pkg.contains('pgsql') or dir_include_pkg.contains('postgres'))
+  dir_include_pkg = dir_include_pkg / pkg
+  dir_include_pkg_rel = pkg
+endif
+
+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_locale = get_option('localedir')
+
+
+# Derived values
+dir_bitcode = dir_lib_pkg / 'bitcode'
+dir_include_internal = dir_include_pkg / 'internal'
+dir_include_server = dir_include_pkg / 'server'
+dir_include_extension = dir_include_server / 'extension'
+dir_data_extension = dir_data / 'extension'
+
+
+
+###############################################################
+# Search paths, preparation for compiler tests
+#
+# NB: Arguments added later are not automatically used for subsequent
+# configuration-time checks (so they are more isolated). If they should be
+# used, they need to be added to test_c_args as well.
+###############################################################
+
+postgres_inc = [include_directories(postgres_inc_d)]
+test_lib_d = postgres_lib_d
+test_c_args = cppflags + cflags
+
+
+
+###############################################################
+# Library: bsd-auth
+###############################################################
+
+bsd_authopt = get_option('bsd_auth')
+bsd_auth = not_found_dep
+if cc.check_header('bsd_auth.h', required: bsd_authopt,
+    args: test_c_args, include_directories: postgres_inc)
+  cdata.set('USE_BSD_AUTH', 1)
+  bsd_auth = declare_dependency()
+endif
+
+
+
+###############################################################
+# Library: bonjour
+#
+# For now don't search for DNSServiceRegister in a library - only Apple's
+# Bonjour implementation, which is always linked, works.
+###############################################################
+
+bonjouropt = get_option('bonjour')
+bonjour = dependency('', required : false)
+if cc.check_header('dns_sd.h', required: bonjouropt,
+    args: test_c_args, include_directories: postgres_inc) and \
+   cc.has_function('DNSServiceRegister',
+    args: test_c_args, include_directories: postgres_inc)
+  cdata.set('USE_BONJOUR', 1)
+  bonjour = declare_dependency()
+endif
+
+
+
+###############################################################
+# Library: GSSAPI
+###############################################################
+
+gssapiopt = get_option('gssapi')
+krb_srvtab = ''
+have_gssapi = false
+if not gssapiopt.disabled()
+  gssapi = dependency('krb5-gssapi', required: gssapiopt)
+  have_gssapi = gssapi.found()
+
+  if not have_gssapi
+  elif cc.check_header('gssapi/gssapi.h', dependencies: gssapi, required: false,
+      args: test_c_args, include_directories: postgres_inc)
+    cdata.set('HAVE_GSSAPI_GSSAPI_H', 1)
+  elif cc.check_header('gssapi.h', args: test_c_args, dependencies: gssapi, required: gssapiopt)
+    cdata.set('HAVE_GSSAPI_H', 1)
+  else
+    have_gssapi = false
+  endif
+
+  if not have_gssapi
+  elif cc.has_function('gss_init_sec_context', dependencies: gssapi,
+      args: test_c_args, include_directories: postgres_inc)
+    cdata.set('ENABLE_GSS', 1)
+
+    krb_srvtab = 'FILE:/@0@/krb5.keytab)'.format(get_option('sysconfdir'))
+    cdata.set_quoted('PG_KRB_SRVTAB', krb_srvtab)
+  elif gssapiopt.enabled()
+    error('''could not find function 'gss_init_sec_context' required for GSSAPI''')
+  else
+    have_gssapi = false
+  endif
+endif
+if not have_gssapi
+  gssapi = not_found_dep
+endif
+
+
+
+###############################################################
+# Library: ldap
+###############################################################
+
+ldapopt = get_option('ldap')
+if host_system == 'windows'
+  ldap = cc.find_library('wldap32', required: ldapopt)
+  ldap_r = ldap
+else
+  # macos framework dependency is buggy for ldap (one can argue whether it's
+  # Apple's or meson's fault), leading to an endless recursion with ldap.h
+  # including itself. See https://github.com/mesonbuild/meson/issues/10002
+  # Luckily we only need pkg-config support, so the workaround isn't
+  # complicated.
+  ldap = dependency('ldap', method: 'pkg-config', required: false)
+  ldap_r = ldap
+
+  # Before 2.5 openldap didn't have a pkg-config file, and it might not be
+  # installed
+  if not ldap.found()
+    ldap = cc.find_library('ldap', required: ldapopt, dirs: test_lib_d,
+      has_headers: 'ldap.h', header_include_directories: postgres_inc)
+
+    # The separate ldap_r library only exists in OpenLDAP < 2.5, and if we
+    # have 2.5 or later, we shouldn't even probe for ldap_r (we might find a
+    # library from a separate OpenLDAP installation).  The most reliable
+    # way to check that is to check for a function introduced in 2.5.
+    if not ldap.found()
+      # don't have ldap, we shouldn't check for ldap_r
+    elif cc.has_function('ldap_verify_credentials',
+        dependencies: ldap, args: test_c_args)
+      ldap_r = ldap # ldap >= 2.5, no need for ldap_r
+    else
+
+      # Use ldap_r for FE if available, else assume ldap is thread-safe.
+      ldap_r = cc.find_library('ldap_r', required: false, dirs: test_lib_d,
+        has_headers: 'ldap.h', header_include_directories: postgres_inc)
+      if not ldap_r.found()
+        ldap_r = ldap
+      else
+        # On some platforms ldap_r fails to link without PTHREAD_LIBS.
+        ldap_r = declare_dependency(dependencies: [ldap_r, thread_dep])
+      endif
+
+      # PostgreSQL sometimes loads libldap_r and plain libldap into the same
+      # process.  Check for OpenLDAP versions known not to tolerate doing so;
+      # assume non-OpenLDAP implementations are safe.  The dblink test suite
+      # exercises the hazardous interaction directly.
+      compat_test_code = '''
+#include <ldap.h>
+#if !defined(LDAP_VENDOR_VERSION) || \
+     (defined(LDAP_API_FEATURE_X_OPENLDAP) && \
+      LDAP_VENDOR_VERSION >= 20424 && LDAP_VENDOR_VERSION <= 20431)
+choke me
+#endif
+'''
+      if not cc.compiles(compat_test_code,
+          name: 'LDAP implementation compatible',
+          dependencies: ldap, args: test_c_args)
+        warning('''
+*** With OpenLDAP versions 2.4.24 through 2.4.31, inclusive, each backend
+*** process that loads libpq (via WAL receiver, dblink, or postgres_fdw) and
+*** also uses LDAP will crash on exit.''')
+      endif
+    endif
+  endif
+
+  # XXX: this shouldn't be tested in the windows case, but should be tested in
+  # the dependency() success case
+  if ldap.found() and cc.has_function('ldap_initialize',
+      dependencies: ldap, args: test_c_args)
+    cdata.set('HAVE_LDAP_INITIALIZE', 1)
+  endif
+endif
+
+if ldap.found()
+  assert(ldap_r.found())
+  cdata.set('USE_LDAP', 1)
+else
+  assert(not ldap_r.found())
+endif
+
+
+
+###############################################################
+# Library: LLVM
+###############################################################
+
+llvmopt = get_option('llvm')
+if not llvmopt.disabled()
+  add_languages('cpp', required: true, native: false)
+  llvm = dependency('llvm', version: '>=3.9', method: 'config-tool', required: llvmopt)
+
+  if llvm.found()
+
+    cdata.set('USE_LLVM', 1)
+
+    cpp = meson.get_compiler('cpp')
+
+    llvm_binpath = llvm.get_variable(configtool: 'bindir')
+
+    ccache = find_program('ccache', native: true, required: false)
+    clang = find_program(llvm_binpath / 'clang', required: true)
+  endif
+else
+  llvm = not_found_dep
+endif
+
+
+
+###############################################################
+# Library: icu
+###############################################################
+
+icuopt = get_option('icu')
+if not icuopt.disabled()
+  icu = dependency('icu-uc', required: icuopt.enabled())
+  icu_i18n = dependency('icu-i18n', required: icuopt.enabled())
+
+  if icu.found()
+    cdata.set('USE_ICU', 1)
+  endif
+
+else
+  icu = not_found_dep
+  icu_i18n = not_found_dep
+endif
+
+
+
+###############################################################
+# Library: libxml
+###############################################################
+
+libxmlopt = get_option('libxml')
+if not libxmlopt.disabled()
+  libxml = dependency('libxml-2.0', required: libxmlopt, version: '>= 2.6.23')
+
+  if libxml.found()
+    cdata.set('USE_LIBXML', 1)
+  endif
+else
+  libxml = not_found_dep
+endif
+
+
+
+###############################################################
+# Library: libxslt
+###############################################################
+
+libxsltopt = get_option('libxslt')
+if not libxsltopt.disabled()
+  libxslt = dependency('libxslt', required: libxsltopt)
+
+  if libxslt.found()
+    cdata.set('USE_LIBXSLT', 1)
+  endif
+else
+  libxslt = not_found_dep
+endif
+
+
+
+###############################################################
+# Library: lz4
+###############################################################
+
+lz4opt = get_option('lz4')
+if not lz4opt.disabled()
+  lz4 = dependency('liblz4', required: lz4opt)
+
+  if lz4.found()
+    cdata.set('USE_LZ4', 1)
+    cdata.set('HAVE_LIBLZ4', 1)
+  endif
+
+else
+  lz4 = not_found_dep
+endif
+
+
+
+###############################################################
+# Library: Tcl (for pltcl)
+#
+# NB: tclConfig.sh is used in autoconf build for getting
+# TCL_SHARED_BUILD, TCL_INCLUDE_SPEC, TCL_LIBS and TCL_LIB_SPEC
+# variables. For now we have not seen a need to copy
+# that behaviour to the meson build.
+###############################################################
+
+tclopt = get_option('pltcl')
+tcl_version = get_option('tcl_version')
+tcl_dep = not_found_dep
+if not tclopt.disabled()
+
+  # via pkg-config
+  tcl_dep = dependency(tcl_version, required: false)
+
+  if not tcl_dep.found()
+    tcl_dep = cc.find_library(tcl_version,
+      required: tclopt,
+      dirs: test_lib_d)
+  endif
+
+  if not cc.has_header('tcl.h', dependencies: tcl_dep, required: tclopt)
+    tcl_dep = not_found_dep
+  endif
+endif
+
+
+
+###############################################################
+# Library: pam
+###############################################################
+
+pamopt = get_option('pam')
+if not pamopt.disabled()
+  pam = dependency('pam', required: false)
+
+  if not pam.found()
+    pam = cc.find_library('pam', required: pamopt, dirs: test_lib_d)
+  endif
+
+  if pam.found()
+    pam_header_found = false
+
+    # header file <security/pam_appl.h> or <pam/pam_appl.h> is required for PAM.
+    if cc.check_header('security/pam_appl.h', dependencies: pam, required: false,
+        args: test_c_args, include_directories: postgres_inc)
+      cdata.set('HAVE_SECURITY_PAM_APPL_H', 1)
+      pam_header_found = true
+    elif cc.check_header('pam/pam_appl.h', dependencies: pam, required: pamopt,
+        args: test_c_args, include_directories: postgres_inc)
+      cdata.set('HAVE_PAM_PAM_APPL_H', 1)
+      pam_header_found = true
+    endif
+
+    if pam_header_found
+      cdata.set('USE_PAM', 1)
+    else
+      pam = not_found_dep
+    endif
+  endif
+else
+  pam = not_found_dep
+endif
+
+
+
+###############################################################
+# Library: Perl (for plperl)
+###############################################################
+
+perlopt = get_option('plperl')
+perl_dep = not_found_dep
+if not perlopt.disabled()
+  perl_may_work = true
+
+  # First verify that perl has the necessary dependencies installed
+  perl_mods = run_command(
+    [perl,
+     '-MConfig', '-MOpcode', '-MExtUtils::Embed', '-MExtUtils::ParseXS',
+     '-e', ''],
+    check: false)
+  if perl_mods.returncode() != 0
+    perl_may_work = false
+    perl_msg = 'perl installation does not have the required modules'
+  endif
+
+  # Then inquire perl about its configuration
+  if perl_may_work
+    perl_conf_cmd = [perl, '-MConfig', '-e', 'print $Config{$ARGV[0]}']
+    perlversion = run_command(perl_conf_cmd, 'api_versionstring', check: true).stdout()
+    archlibexp = run_command(perl_conf_cmd, 'archlibexp', check: true).stdout()
+    privlibexp = run_command(perl_conf_cmd, 'privlibexp', check: true).stdout()
+    useshrplib = run_command(perl_conf_cmd, 'useshrplib', check: true).stdout()
+
+    perl_inc_dir = '@0@/CORE'.format(archlibexp)
+
+    if useshrplib != 'true'
+      perl_may_work = false
+      perl_msg = 'need a shared perl'
+    endif
+  endif
+
+  if perl_may_work
+    # On most platforms, archlibexp is also where the Perl include files live ...
+    perl_ccflags = ['-I@0@'.format(perl_inc_dir)]
+    # ... but on newer macOS versions, we must use -iwithsysroot to look
+    # under sysroot
+    if not fs.is_file('@0@/perl.h'.format(perl_inc_dir)) and \
+       fs.is_file('@0@@1@/perl.h'.format(pg_sysroot, perl_inc_dir))
+      perl_ccflags = ['-iwithsysroot', perl_inc_dir]
+    endif
+
+    # check compiler finds header
+    if not cc.has_header('perl.h', required: false,
+        args: test_c_args + perl_ccflags, include_directories: postgres_inc)
+      perl_may_work = false
+      perl_msg = 'missing perl.h'
+    endif
+  endif
+
+  if perl_may_work
+    perl_ccflags_r = run_command(perl_conf_cmd, 'ccflags', check: true).stdout()
+
+    # See comments for PGAC_CHECK_PERL_EMBED_CCFLAGS in perl.m4
+    foreach flag : perl_ccflags_r.split(' ')
+      if flag.startswith('-D') and \
+          (not flag.startswith('-D_') or flag == '_USE_32BIT_TIME_T')
+        perl_ccflags += flag
+      endif
+    endforeach
+
+    if host_system == 'windows'
+      perl_ccflags += ['-DPLPERL_HAVE_UID_GID']
+    endif
+
+    message('CCFLAGS recommended by perl: @0@'.format(perl_ccflags_r))
+    message('CCFLAGS for embedding perl: @0@'.format(' '.join(perl_ccflags)))
+
+    # We are after Embed's ldopts, but without the subset mentioned in
+    # Config's ccdlflags and ldflags.  (Those are the choices of those who
+    # built the Perl installation, which are not necessarily appropriate
+    # for building PostgreSQL.)
+    ldopts = run_command(perl, '-MExtUtils::Embed', '-e', 'ldopts', check: true).stdout().strip()
+    undesired = run_command(perl_conf_cmd, 'ccdlflags', check: true).stdout().split()
+    undesired += run_command(perl_conf_cmd, 'ldflags', check: true).stdout().split()
+
+    perl_ldopts = []
+    foreach ldopt : ldopts.split(' ')
+      if ldopt == '' or ldopt in undesired
+        continue
+      endif
+
+      perl_ldopts += ldopt.strip('"')
+    endforeach
+
+    message('LDFLAGS recommended by perl: "@0@"'.format(ldopts))
+    message('LDFLAGS for embedding perl: "@0@"'.format(' '.join(perl_ldopts)))
+
+    perl_dep_int = declare_dependency(
+      compile_args: perl_ccflags,
+      link_args: perl_ldopts,
+      version: perlversion,
+    )
+
+    # While we're at it, check that we can link to libperl.
+    # On most platforms, if perl.h is there then libperl.so will be too, but
+    # at this writing Debian packages them separately.  This doesn't work on
+    # old meson versions, but that's ok, it's just nicer to test here.
+    perl_link_test = '''
+/* see plperl.h */
+#ifdef _MSC_VER
+#define __inline__ inline
+#endif
+#include <EXTERN.h>
+#include <perl.h>
+int main(void)
+{
+perl_alloc();
+}'''
+    if meson.version().version_compare('>=0.57') and not \
+        cc.links(perl_link_test, name: 'libperl',
+          args: test_c_args + perl_ccflags + perl_ldopts,
+          include_directories: postgres_inc)
+      perl_may_work = false
+      perl_msg = 'missing libperl'
+    endif
+
+  endif # perl_may_work
+
+  if perl_may_work
+    perl_dep = perl_dep_int
+  else
+    if perlopt.enabled()
+      error('dependency plperl failed: @0@'.format(perl_msg))
+    else
+      message('disabling optional dependency plperl: @0@'.format(perl_msg))
+    endif
+  endif
+endif
+
+
+
+###############################################################
+# Library: Python (for plpython)
+###############################################################
+
+pyopt = get_option('plpython')
+if not pyopt.disabled()
+  pm = import('python')
+  python3_inst = pm.find_installation(required: pyopt.enabled())
+  python3_dep = python3_inst.dependency(embed: true, required: pyopt.enabled())
+  if not cc.check_header('Python.h', dependencies: python3_dep, required: pyopt.enabled())
+    python3_dep = not_found_dep
+  endif
+else
+  python3_dep = not_found_dep
+endif
+
+
+
+###############################################################
+# Library: Readline
+###############################################################
+
+if not get_option('readline').disabled()
+  libedit_preferred = get_option('libedit_preferred')
+  # Set the order of readline dependencies
+  check_readline_deps = libedit_preferred ? \
+    ['libedit', 'readline'] : ['readline', 'libedit']
+
+  foreach readline_dep : check_readline_deps
+    readline = dependency(readline_dep, required: false)
+    if not readline.found()
+      readline = cc.find_library(readline_dep,
+        required: get_option('readline').enabled(),
+        dirs: test_lib_d)
+    endif
+    if readline.found()
+      break
+    endif
+  endforeach
+
+  if readline.found()
+    cdata.set('HAVE_LIBREADLINE', 1)
+
+    editline_prefix = {
+      'header_prefix': 'editline/',
+      'flag_prefix': 'EDITLINE_',
+    }
+    readline_prefix = {
+      'header_prefix': 'readline/',
+      'flag_prefix': 'READLINE_',
+    }
+    default_prefix = {
+      'header_prefix': '',
+      'flag_prefix': '',
+    }
+
+    # Set the order of prefixes
+    prefixes = libedit_preferred ? \
+      [editline_prefix, default_prefix, readline_prefix] : \
+      [readline_prefix, default_prefix, editline_prefix]
+
+    at_least_one_header_found = false
+    foreach header : ['history', 'readline']
+      is_found = false
+      foreach prefix : prefixes
+        header_file = '@0@@1@.h'.format(prefix['header_prefix'], header)
+        # Check history.h and readline.h
+        if not is_found and cc.has_header(header_file,
+            args: test_c_args, include_directories: postgres_inc,
+            dependencies: [readline], required: false)
+          if header == 'readline'
+            readline_h = header_file
+          endif
+          cdata.set('HAVE_@0@@1@_H'.format(prefix['flag_prefix'], header).to_upper(), 1)
+          is_found = true
+          at_least_one_header_found = true
+        endif
+      endforeach
+    endforeach
+
+    if not at_least_one_header_found
+      error('''readline header not found
+If you have @0@ already installed, see see meson-log/meson-log.txt for details on the
+failure. It is possible the compiler isn't looking in the proper directory.
+Use -Dreadline=false to disable readline support.'''.format(readline_dep))
+    endif
+
+    check_funcs = [
+      'append_history',
+      'history_truncate_file',
+      'rl_completion_matches',
+      'rl_filename_completion_function',
+      'rl_reset_screen_size',
+      'rl_variable_bind',
+    ]
+
+    foreach func : check_funcs
+      found = cc.has_function(func, dependencies: [readline],
+        args: test_c_args, include_directories: postgres_inc)
+      cdata.set('HAVE_'+func.to_upper(), found ? 1 : false)
+    endforeach
+
+    check_vars = [
+      'rl_completion_suppress_quote',
+      'rl_filename_quote_characters',
+      'rl_filename_quoting_function',
+    ]
+
+    foreach var : check_vars
+      cdata.set('HAVE_'+var.to_upper(),
+        cc.has_header_symbol(readline_h, var,
+          args: test_c_args, include_directories: postgres_inc,
+          prefix: '#include <stdio.h>',
+          dependencies: [readline]) ? 1 : false)
+    endforeach
+
+    # If found via cc.find_library() ensure headers are found when using the
+    # dependency. On meson < 0.57 one cannot do compiler checks using the
+    # dependency returned by declare_dependency(), so we can't do this above.
+    if readline.type_name() == 'library'
+      readline = declare_dependency(dependencies: readline,
+        include_directories: postgres_inc)
+    endif
+  endif
+
+  # XXX: Figure out whether to implement mingw warning equivalent
+else
+  readline = not_found_dep
+endif
+
+
+
+###############################################################
+# Library: selinux
+###############################################################
+
+selinux = not_found_dep
+selinuxopt = get_option('selinux')
+if meson.version().version_compare('>=0.59')
+  selinuxopt = selinuxopt.disable_auto_if(host_system != 'linux')
+endif
+selinux = dependency('libselinux', required: selinuxopt, version: '>= 2.1.10')
+cdata.set('HAVE_LIBSELINUX',
+  selinux.found() ? 1 : false)
+
+
+
+###############################################################
+# Library: systemd
+###############################################################
+
+systemd = not_found_dep
+systemdopt = get_option('systemd')
+if meson.version().version_compare('>=0.59')
+  systemdopt = systemdopt.disable_auto_if(host_system != 'linux')
+endif
+systemd = dependency('libsystemd', required: systemdopt)
+cdata.set('USE_SYSTEMD', systemd.found() ? 1 : false)
+
+
+
+###############################################################
+# Library: SSL
+###############################################################
+
+if get_option('ssl') == 'openssl'
+
+  # Try to find openssl via pkg-config et al, if that doesn't work
+  # (e.g. because it's provided as part of the OS, like on FreeBSD), look for
+  # the library names that we know about.
+
+  # via pkg-config et al
+  ssl = dependency('openssl', required: false)
+
+  # via library + headers
+  if not ssl.found()
+    ssl_lib = cc.find_library('ssl',
+      dirs: test_lib_d,
+      header_include_directories: postgres_inc,
+      has_headers: ['openssl/ssl.h', 'openssl/err.h'])
+    crypto_lib = cc.find_library('crypto',
+      dirs: test_lib_d,
+      header_include_directories: postgres_inc)
+    ssl_int = [ssl_lib, crypto_lib]
+
+    ssl = declare_dependency(dependencies: ssl_int,
+                             include_directories: postgres_inc)
+  else
+    cc.has_header('openssl/ssl.h', args: test_c_args, dependencies: ssl, required: true)
+    cc.has_header('openssl/err.h', args: test_c_args, dependencies: ssl, required: true)
+
+    ssl_int = [ssl]
+  endif
+
+  check_funcs = [
+    ['CRYPTO_new_ex_data', {'required': true}],
+    ['SSL_new', {'required': true}],
+
+    # Function introduced in OpenSSL 1.0.2.
+    ['X509_get_signature_nid'],
+
+    # Functions introduced in OpenSSL 1.1.0. We used to check for
+    # OPENSSL_VERSION_NUMBER, but that didn't work with 1.1.0, because LibreSSL
+    # defines OPENSSL_VERSION_NUMBER to claim version 2.0.0, even though it
+    # doesn't have these OpenSSL 1.1.0 functions. So check for individual
+    # functions.
+    ['OPENSSL_init_ssl'],
+    ['BIO_get_data'],
+    ['BIO_meth_new'],
+    ['ASN1_STRING_get0_data'],
+    ['HMAC_CTX_new'],
+    ['HMAC_CTX_free'],
+
+    # OpenSSL versions before 1.1.0 required setting callback functions, for
+    # thread-safety. In 1.1.0, it's no longer required, and CRYPTO_lock()
+    # function was removed.
+    ['CRYPTO_lock'],
+  ]
+
+  foreach c : check_funcs
+    func = c.get(0)
+    val = cc.has_function(func, args: test_c_args, dependencies: ssl_int)
+    required = c.get(1, {}).get('required', false)
+    if required and not val
+      error('openssl function @0@ is required'.format(func))
+    elif not required
+      cdata.set('HAVE_' + func.to_upper(), val ? 1 : false)
+    endif
+  endforeach
+
+  cdata.set('USE_OPENSSL', 1,
+            description: 'Define to 1 to build with OpenSSL support. (-Dssl=openssl)')
+  cdata.set('OPENSSL_API_COMPAT', '0x10001000L',
+            description: '''Define to the OpenSSL API version in use. This avoids deprecation warnings from newer OpenSSL versions.''')
+else
+  ssl = not_found_dep
+endif
+
+
+
+###############################################################
+# Library: uuid
+###############################################################
+
+uuidopt = get_option('uuid')
+if uuidopt != 'none'
+  uuidname = uuidopt.to_upper()
+  if uuidopt == 'e2fs'
+    uuid = dependency('uuid', required: true)
+    uuidfunc = 'uuid_generate'
+    uuidheader = 'uuid/uuid.h'
+  elif uuidopt == 'bsd'
+    # libc should have uuid function
+    uuid = declare_dependency()
+    uuidfunc = 'uuid_to_string'
+    uuidheader = 'uuid.h'
+  elif uuidopt == 'ossp'
+    uuid = dependency('ossp-uuid', required: true)
+    uuidfunc = 'uuid_export'
+    uuidheader = 'ossp/uuid.h'
+  else
+    error('huh')
+  endif
+
+  if not cc.has_header_symbol(uuidheader, uuidfunc, args: test_c_args, dependencies: uuid)
+    error('uuid library @0@ missing required function @1@'.format(uuidopt, uuidfunc))
+  endif
+  cdata.set('HAVE_@0@'.format(uuidheader.underscorify().to_upper()), 1)
+
+  cdata.set('HAVE_UUID_@0@'.format(uuidname), 1,
+           description: 'Define to 1 if you have @0@ UUID support.'.format(uuidname))
+else
+  uuid = not_found_dep
+endif
+
+
+
+###############################################################
+# Library: zlib
+###############################################################
+
+zlibopt = get_option('zlib')
+zlib = not_found_dep
+if not zlibopt.disabled()
+  zlib_t = dependency('zlib', required: zlibopt)
+
+  if zlib_t.type_name() == 'internal'
+    # if fallback was used, we don't need to test if headers are present (they
+    # aren't built yet, so we can't test)
+    zlib = zlib_t
+  elif not zlib_t.found()
+    warning('did not find zlib')
+  elif not cc.has_header('zlib.h',
+      args: test_c_args, include_directories: postgres_inc,
+      dependencies: [zlib_t], required: zlibopt.enabled())
+    warning('zlib header not found')
+  elif not cc.has_type('z_streamp',
+      dependencies: [zlib_t], prefix: '#include <zlib.h>',
+      args: test_c_args, include_directories: postgres_inc)
+    if zlibopt.enabled()
+      error('zlib version is too old')
+    else
+      warning('zlib version is too old')
+    endif
+  else
+    zlib = zlib_t
+  endif
+
+  if zlib.found()
+    cdata.set('HAVE_LIBZ', 1)
+  endif
+endif
+
+
+
+###############################################################
+# Library: tap test dependencies
+###############################################################
+
+# Check whether tap tests are enabled or not
+tap_tests_enabled = false
+tapopt = get_option('tap_tests')
+if not tapopt.disabled()
+  # Checking for perl modules for tap tests
+  perl_ipc_run_check = run_command(perl, 'config/check_modules.pl', check: false)
+  if perl_ipc_run_check.returncode() != 0
+    message(perl_ipc_run_check.stderr().strip())
+    if tapopt.enabled()
+      error('Additional Perl modules are required to run TAP tests.')
+    else
+      warning('Additional Perl modules are required to run TAP tests.')
+    endif
+  else
+    tap_tests_enabled = true
+  endif
+endif
+
+
+
+###############################################################
+# Library: zstd
+###############################################################
+
+zstdopt = get_option('zstd')
+if not zstdopt.disabled()
+  zstd = dependency('libzstd', required: zstdopt, version: '>=1.4.0')
+
+  if zstd.found()
+    cdata.set('USE_ZSTD', 1)
+    cdata.set('HAVE_LIBZSTD', 1)
+  endif
+
+else
+  zstd = not_found_dep
+endif
+
+
+
+###############################################################
+# Compiler tests
+###############################################################
+
+# Do we need -std=c99 to compile C99 code? We don't want to add -std=c99
+# unnecessarily, because we optionally rely on newer features.
+c99_test = '''
+#include <stdbool.h>
+#include <complex.h>
+#include <tgmath.h>
+#include <inttypes.h>
+
+struct named_init_test {
+  int a;
+  int b;
+};
+
+extern void structfunc(struct named_init_test);
+
+int main(int argc, char **argv)
+{
+  struct named_init_test nit = {
+    .a = 3,
+    .b = 5,
+  };
+
+  for (int loop_var = 0; loop_var < 3; loop_var++)
+  {
+    nit.a += nit.b;
+  }
+
+  structfunc((struct named_init_test){1, 0});
+
+  return nit.a != 0;
+}
+'''
+
+if not cc.compiles(c99_test, name: 'c99', args: test_c_args)
+  if cc.compiles(c99_test, name: 'c99 with -std=c99',
+        args: test_c_args + ['-std=c99'])
+    test_c_args += '-std=c99'
+    cflags += '-std=c99'
+  else
+    error('C compiler does not support C99')
+  endif
+endif
+
+sizeof_long = cc.sizeof('long', args: test_c_args)
+cdata.set('SIZEOF_LONG', sizeof_long)
+if sizeof_long == 8
+  cdata.set('HAVE_LONG_INT_64', 1)
+  cdata.set('PG_INT64_TYPE', 'long int')
+  cdata.set_quoted('INT64_MODIFIER', 'l')
+elif sizeof_long == 4 and cc.sizeof('long long', args: test_c_args) == 8
+  cdata.set('HAVE_LONG_LONG_INT_64', 1)
+  cdata.set('PG_INT64_TYPE', 'long long int')
+  cdata.set_quoted('INT64_MODIFIER', 'll')
+else
+  error('do not know how to get a 64bit int')
+endif
+
+if host_machine.endian() == 'big'
+  cdata.set('WORDS_BIGENDIAN', 1)
+endif
+
+alignof_types = ['short', 'int', 'long', 'double']
+maxalign = 0
+foreach t : alignof_types
+  align = cc.alignment(t, args: test_c_args)
+  if maxalign < align
+    maxalign = align
+  endif
+  cdata.set('ALIGNOF_@0@'.format(t.to_upper()), align)
+endforeach
+cdata.set('MAXIMUM_ALIGNOF', maxalign)
+
+cdata.set('SIZEOF_VOID_P', cc.sizeof('void *', args: test_c_args))
+cdata.set('SIZEOF_SIZE_T', cc.sizeof('size_t', args: test_c_args))
+
+
+# Check if __int128 is a working 128 bit integer type, and if so
+# define PG_INT128_TYPE to that typename.
+#
+# This currently only detects a GCC/clang extension, but support for other
+# environments may be added in the future.
+#
+# For the moment we only test for support for 128bit math; support for
+# 128bit literals and snprintf is not required.
+if cc.links('''
+  /*
+   * We don't actually run this test, just link it to verify that any support
+   * functions needed for __int128 are present.
+   *
+   * These are globals to discourage the compiler from folding all the
+   * arithmetic tests down to compile-time constants.  We do not have
+   * convenient support for 128bit literals at this point...
+   */
+  __int128 a = 48828125;
+  __int128 b = 97656250;
+
+  int main(void)
+  {
+      __int128 c,d;
+      a = (a << 12) + 1; /* 200000000001 */
+      b = (b << 12) + 5; /* 400000000005 */
+      /* try the most relevant arithmetic ops */
+      c = a * b;
+      d = (c + b) / b;
+      /* must use the results, else compiler may optimize arithmetic away */
+      return d != a+1;
+  }''',
+  name: '__int128',
+  args: test_c_args)
+
+  buggy_int128 = false
+
+  # Use of non-default alignment with __int128 tickles bugs in some compilers.
+  # If not cross-compiling, we can test for bugs and disable use of __int128
+  # with buggy compilers.  If cross-compiling, hope for the best.
+  # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83925
+  if not meson.is_cross_build()
+    r = cc.run('''
+    /* This must match the corresponding code in c.h: */
+    #if defined(__GNUC__) || defined(__SUNPRO_C) || defined(__IBMC__)
+    #define pg_attribute_aligned(a) __attribute__((aligned(a)))
+    #endif
+    typedef __int128 int128a
+    #if defined(pg_attribute_aligned)
+    pg_attribute_aligned(8)
+    #endif
+    ;
+
+    int128a holder;
+    void pass_by_val(void *buffer, int128a par) { holder = par; }
+
+    int main(void)
+    {
+        long int i64 = 97656225L << 12;
+        int128a q;
+        pass_by_val(main, (int128a) i64);
+        q = (int128a) i64;
+        return q != holder;
+    }''',
+    name: '__int128 alignment bug',
+    args: test_c_args)
+    assert(r.compiled())
+    if r.returncode() != 0
+      buggy_int128 = true
+      message('__int128 support present but buggy and thus disabled')
+    endif
+  endif
+
+  if not buggy_int128
+    cdata.set('PG_INT128_TYPE', '__int128')
+    cdata.set('ALIGNOF_PG_INT128_TYPE', cc.
+      alignment('__int128', args: test_c_args))
+  endif
+endif
+
+
+# Check if the C compiler knows computed gotos (gcc extension, also
+# available in at least clang).  If so, define HAVE_COMPUTED_GOTO.
+#
+# Checking whether computed gotos are supported syntax-wise ought to
+# be enough, as the syntax is otherwise illegal.
+if cc.compiles('''
+    static inline int foo(void)
+    {
+      void *labeladdrs[] = {&&my_label};
+      goto *labeladdrs[0];
+      my_label:
+      return 1;
+    }''',
+    args: test_c_args)
+  cdata.set('HAVE_COMPUTED_GOTO', 1)
+endif
+
+
+# Check if the C compiler understands _Static_assert(),
+# and define HAVE__STATIC_ASSERT if so.
+#
+# We actually check the syntax ({ _Static_assert(...) }), because we need
+# gcc-style compound expressions to be able to wrap the thing into macros.
+if cc.compiles('''
+    int main(int arg, char **argv)
+    {
+        ({ _Static_assert(1, "foo"); });
+    }
+    ''',
+    args: test_c_args)
+  cdata.set('HAVE__STATIC_ASSERT', 1)
+endif
+
+
+# We use <stdbool.h> if we have it and it declares type bool as having
+# size 1.  Otherwise, c.h will fall back to declaring bool as unsigned char.
+if cc.has_type('_Bool', args: test_c_args) \
+  and cc.has_type('bool', prefix: '#include <stdbool.h>', args: test_c_args) \
+  and cc.sizeof('bool', prefix: '#include <stdbool.h>', args: test_c_args) == 1
+  cdata.set('HAVE__BOOL', 1)
+  cdata.set('PG_USE_STDBOOL', 1)
+endif
+
+
+# Need to check a call with %m because netbsd supports gnu_printf but emits a
+# warning for each use of %m.
+printf_attributes = ['gnu_printf', '__syslog__', 'printf']
+testsrc = '''
+extern void emit_log(int ignore, const char *fmt,...) __attribute__((format(@0@, 2,3)));
+static void call_log(void)
+{
+    emit_log(0, "error: %s: %m", "foo");
+}
+'''
+attrib_error_args = cc.get_supported_arguments('-Werror=format', '-Werror=ignored-attributes')
+foreach a : printf_attributes
+  if cc.compiles(testsrc.format(a),
+      args: test_c_args + attrib_error_args, name: 'format ' + a)
+    cdata.set('PG_PRINTF_ATTRIBUTE', a)
+    break
+  endif
+endforeach
+
+
+if cc.has_function_attribute('visibility:default') and \
+  cc.has_function_attribute('visibility:hidden')
+  cdata.set('HAVE_VISIBILITY_ATTRIBUTE', 1)
+
+  # Only newer versions of meson know not to apply gnu_symbol_visibility =
+  # inlineshidden to C code as well... Any either way, we want to put these
+  # flags into exported files (pgxs, .pc files).
+  cflags_mod += '-fvisibility=hidden'
+  cxxflags_mod += ['-fvisibility=hidden', '-fvisibility-inlines-hidden']
+  ldflags_mod += '-fvisibility=hidden'
+endif
+
+
+# Check if various builtins exist. Some builtins are tested separately,
+# because we want to test something more complicated than the generic case.
+builtins = [
+  'bswap16',
+  'bswap32',
+  'bswap64',
+  'clz',
+  'ctz',
+  'constant_p',
+  'frame_address',
+  'popcount',
+  'unreachable',
+]
+
+foreach builtin : builtins
+  fname = '__builtin_@0@'.format(builtin)
+  if cc.has_function(fname, args: test_c_args)
+    cdata.set('HAVE@0@'.format(fname.to_upper()), 1)
+  endif
+endforeach
+
+
+# Check if the C compiler understands __builtin_types_compatible_p,
+# and define HAVE__BUILTIN_TYPES_COMPATIBLE_P if so.
+#
+# We check usage with __typeof__, though it's unlikely any compiler would
+# have the former and not the latter.
+if cc.compiles('''
+    static int x;
+    static int y[__builtin_types_compatible_p(__typeof__(x), int)];
+    ''',
+    name: '__builtin_types_compatible_p',
+    args: test_c_args)
+  cdata.set('HAVE__BUILTIN_TYPES_COMPATIBLE_P', 1)
+endif
+
+
+# Check if the C compiler understands __builtin_$op_overflow(),
+# and define HAVE__BUILTIN_OP_OVERFLOW if so.
+#
+# Check for the most complicated case, 64 bit multiplication, as a
+# proxy for all of the operations.  To detect the case where the compiler
+# knows the function but library support is missing, we must link not just
+# compile, and store the results in global variables so the compiler doesn't
+# optimize away the call.
+if cc.links('''
+    INT64 a = 1;
+    INT64 b = 1;
+    INT64 result;
+
+    int main(void)
+    {
+        return __builtin_mul_overflow(a, b, &result);
+    }''',
+    name: '__builtin_mul_overflow',
+    args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))],
+    )
+  cdata.set('HAVE__BUILTIN_OP_OVERFLOW', 1)
+endif
+
+
+# XXX: The configure.ac check for __cpuid() is broken, we don't copy that
+# here. To prevent problems due to two detection methods working, stop
+# checking after one.
+if cc.links('''
+    #include <cpuid.h>
+    int main(int arg, char **argv)
+    {
+        unsigned int exx[4] = {0, 0, 0, 0};
+        __get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
+    }
+    ''', name: '__get_cpuid',
+    args: test_c_args)
+  cdata.set('HAVE__GET_CPUID', 1)
+elif cc.links('''
+    #include <intrin.h>
+    int main(int arg, char **argv)
+    {
+        unsigned int exx[4] = {0, 0, 0, 0};
+        __cpuid(exx, 1);
+    }
+    ''', name: '__cpuid',
+    args: test_c_args)
+  cdata.set('HAVE__CPUID', 1)
+endif
+
+
+# Defend against clang being used on x86-32 without SSE2 enabled.  As current
+# versions of clang do not understand -fexcess-precision=standard, the use of
+# x87 floating point operations leads to problems like isinf possibly returning
+# false for a value that is infinite when converted from the 80bit register to
+# the 8byte memory representation.
+#
+# Only perform the test if the compiler doesn't understand
+# -fexcess-precision=standard, that way a potentially fixed compiler will work
+# automatically.
+if '-fexcess-precision=standard' not in cflags
+  if not cc.compiles('''
+#if defined(__clang__) && defined(__i386__) && !defined(__SSE2_MATH__)
+choke me
+#endif''',
+      name: '', args: test_c_args)
+    error('Compiling PostgreSQL with clang, on 32bit x86, requires SSE2 support. Use -msse2 or use gcc.')
+  endif
+endif
+
+
+
+###############################################################
+# Compiler flags
+###############################################################
+
+common_functional_flags = [
+  # Disable strict-aliasing rules; needed for gcc 3.3+
+  '-fno-strict-aliasing',
+  # Disable optimizations that assume no overflow; needed for gcc 4.3+
+  '-fwrapv',
+  '-fexcess-precision=standard',
+]
+
+cflags += cc.get_supported_arguments(common_functional_flags)
+if llvm.found()
+  cxxflags += cpp.get_supported_arguments(common_functional_flags)
+endif
+
+vectorize_cflags = cc.get_supported_arguments(['-ftree-vectorize'])
+unroll_loops_cflags = cc.get_supported_arguments(['-funroll-loops'])
+
+common_warning_flags = [
+  '-Wmissing-prototypes',
+  '-Wpointer-arith',
+  # Really don't want VLAs to be used in our dialect of C
+  '-Werror=vla',
+  # On macOS, complain about usage of symbols newer than the deployment target
+  '-Werror=unguarded-availability-new',
+  '-Wendif-labels',
+  '-Wmissing-format-attribute',
+  '-Wimplicit-fallthrough=3',
+  '-Wcast-function-type',
+  # This was included in -Wall/-Wformat in older GCC versions
+  '-Wformat-security',
+]
+
+cflags_warn += cc.get_supported_arguments(common_warning_flags)
+if llvm.found()
+  cxxflags_warn += cpp.get_supported_arguments(common_warning_flags)
+endif
+
+# A few places with imported code get a pass on -Wdeclaration-after-statement, remember
+# the result for them
+if cc.has_argument('-Wdeclaration-after-statement')
+  cflags_warn += '-Wdeclaration-after-statement'
+  using_declaration_after_statement_warning = true
+else
+  using_declaration_after_statement_warning = false
+endif
+
+
+# The following tests want to suppress various unhelpful warnings by adding
+# -Wno-foo switches.  But gcc won't complain about unrecognized -Wno-foo
+# switches, so we have to test for the positive form and if that works,
+# add the negative form.
+
+negative_warning_flags = [
+  # Suppress clang's unhelpful unused-command-line-argument warnings.
+  'unused-command-line-argument',
+
+  # Remove clang 12+'s compound-token-split-by-macro, as this causes a lot
+  # of warnings when building plperl because of usages in the Perl headers.
+  'compound-token-split-by-macro',
+
+  # Similarly disable useless truncation warnings from gcc 8+
+  'format-truncation',
+  'stringop-truncation',
+
+  # To make warning_level=2 / -Wextra work, we'd need at least the following
+  # 'clobbered',
+  # 'missing-field-initializers',
+  # 'sign-compare',
+  # 'unused-parameter',
+]
+
+foreach w : negative_warning_flags
+  if cc.has_argument('-W' + w)
+    cflags_warn += '-Wno-' + w
+  endif
+  if llvm.found() and cpp.has_argument('-W' + w)
+    cxxflags_warn += '-Wno-' + w
+  endif
+endforeach
+
+
+# From Project.pm
+if cc.get_id() == 'msvc'
+  cflags_warn += [
+    '/wd4018', # signed/unsigned mismatch
+    '/wd4244', # conversion from 'type1' to 'type2', possible loss of data
+    '/wd4273', # inconsistent DLL linkage
+    '/wd4101', # unreferenced local variable
+    '/wd4102', # unreferenced label
+    '/wd4090', # different 'modifier' qualifiers
+    '/wd4267', # conversion from 'size_t' to 'type', possible loss of data
+  ]
+
+  cppflags += [
+    '/DWIN32',
+    '/DWINDOWS',
+    '/D__WINDOWS__',
+    '/D__WIN32__',
+    '/D_CRT_SECURE_NO_DEPRECATE',
+    '/D_CRT_NONSTDC_NO_DEPRECATE',
+  ]
+
+  # We never need export libraries. As link.exe reports their creation, they
+  # are unnecessarily noisy. Similarly, we don't need import library for
+  # modules, we only import them dynamically, and they're also noisy.
+  ldflags += '/NOEXP'
+  ldflags_mod += '/NOIMPLIB'
+endif
+
+
+
+###############################################################
+# Atomics
+###############################################################
+
+if not get_option('spinlocks')
+  warning('Not using spinlocks will cause poor performance')
+else
+  cdata.set('HAVE_SPINLOCKS', 1)
+endif
+
+if not get_option('atomics')
+  warning('Not using atomics will cause poor performance')
+else
+  # XXX: perhaps we should require some atomics support in this case these
+  # days?
+  cdata.set('HAVE_ATOMICS', 1)
+
+  atomic_checks = [
+    {'name': 'HAVE_GCC__SYNC_CHAR_TAS',
+     'desc': '__sync_lock_test_and_set(char)',
+     'test': '''
+char lock = 0;
+__sync_lock_test_and_set(&lock, 1);
+__sync_lock_release(&lock);'''},
+
+    {'name': 'HAVE_GCC__SYNC_INT32_TAS',
+     'desc': '__sync_lock_test_and_set(int32)',
+     'test': '''
+int lock = 0;
+__sync_lock_test_and_set(&lock, 1);
+__sync_lock_release(&lock);'''},
+
+    {'name': 'HAVE_GCC__SYNC_INT32_CAS',
+     'desc': '__sync_val_compare_and_swap(int32)',
+     'test': '''
+int val = 0;
+__sync_val_compare_and_swap(&val, 0, 37);'''},
+
+    {'name': 'HAVE_GCC__SYNC_INT64_CAS',
+     'desc': '__sync_val_compare_and_swap(int64)',
+     'test': '''
+INT64 val = 0;
+__sync_val_compare_and_swap(&val, 0, 37);'''},
+
+    {'name': 'HAVE_GCC__ATOMIC_INT32_CAS',
+     'desc': ' __atomic_compare_exchange_n(int32)',
+     'test': '''
+int val = 0;
+int expect = 0;
+__atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
+
+    {'name': 'HAVE_GCC__ATOMIC_INT64_CAS',
+     'desc': ' __atomic_compare_exchange_n(int64)',
+     'test': '''
+INT64 val = 0;
+INT64 expect = 0;
+__atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
+  ]
+
+  foreach check : atomic_checks
+    test = '''
+int main(void)
+{
+@0@
+}'''.format(check['test'])
+
+    cdata.set(check['name'],
+      cc.links(test,
+        name: check['desc'],
+        args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))]) ? 1 : false
+    )
+  endforeach
+
+endif
+
+
+
+###############################################################
+# Select CRC-32C implementation.
+#
+# If we are targeting a processor that has Intel SSE 4.2 instructions, we can
+# use the special CRC instructions for calculating CRC-32C. If we're not
+# targeting such a processor, but we can nevertheless produce code that uses
+# the SSE intrinsics, perhaps with some extra CFLAGS, compile both
+# implementations and select which one to use at runtime, depending on whether
+# SSE 4.2 is supported by the processor we're running on.
+#
+# Similarly, if we are targeting an ARM processor that has the CRC
+# instructions that are part of the ARMv8 CRC Extension, use them. And if
+# we're not targeting such a processor, but can nevertheless produce code that
+# uses the CRC instructions, compile both, and select at runtime.
+###############################################################
+
+have_optimized_crc = false
+cflags_crc = []
+if host_cpu == 'x86' or host_cpu == 'x86_64'
+
+  if cc.get_id() == 'msvc'
+    cdata.set('USE_SSE42_CRC32C', false)
+    cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
+    have_optimized_crc = true
+  else
+
+    prog = '''
+#include <nmmintrin.h>
+
+int main(void)
+{
+    unsigned int crc = 0;
+    crc = _mm_crc32_u8(crc, 0);
+    crc = _mm_crc32_u32(crc, 0);
+    /* return computed value, to prevent the above being optimized away */
+    return crc == 0;
+}
+'''
+
+    if cc.links(prog, name: '_mm_crc32_u8 and _mm_crc32_u32 without -msse4.2',
+          args: test_c_args)
+      # Use Intel SSE 4.2 unconditionally.
+      cdata.set('USE_SSE42_CRC32C', 1)
+      have_optimized_crc = true
+    elif cc.links(prog, name: '_mm_crc32_u8 and _mm_crc32_u32 with -msse4.2',
+          args: test_c_args + ['-msse4.2'])
+      # Use Intel SSE 4.2, with runtime check. The CPUID instruction is needed for
+      # the runtime check.
+      cflags_crc += '-msse4.2'
+      cdata.set('USE_SSE42_CRC32C', false)
+      cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
+      have_optimized_crc = true
+    endif
+
+  endif
+
+elif host_cpu == 'arm' or host_cpu == 'aarch64'
+
+  prog = '''
+#include <arm_acle.h>
+
+int main(void)
+{
+    unsigned int crc = 0;
+    crc = __crc32cb(crc, 0);
+    crc = __crc32ch(crc, 0);
+    crc = __crc32cw(crc, 0);
+    crc = __crc32cd(crc, 0);
+
+    /* return computed value, to prevent the above being optimized away */
+    return crc == 0;
+}
+'''
+
+  if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
+      args: test_c_args)
+    # Use ARM CRC Extension unconditionally
+    cdata.set('USE_ARMV8_CRC32C', 1)
+    have_optimized_crc = true
+  elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc',
+      args: test_c_args + ['-march=armv8-a+crc'])
+    # Use ARM CRC Extension, with runtime check
+    cflags_crc += '-march=armv8-a+crc'
+    cdata.set('USE_ARMV8_CRC32C', false)
+    cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
+    have_optimized_crc = true
+  endif
+endif
+
+if not have_optimized_crc
+  # fall back to slicing-by-8 algorithm, which doesn't require any special CPU
+  # support.
+  cdata.set('USE_SLICING_BY_8_CRC32C', 1)
+endif
+
+
+
+###############################################################
+# Other CPU specific stuff
+###############################################################
+
+if host_cpu == 'x86_64'
+
+  if cc.compiles('''
+      void main(void)
+      {
+          long long x = 1; long long r;
+          __asm__ __volatile__ (" popcntq %1,%0\n" : "=q"(r) : "rm"(x));
+      }''',
+      name: '@0@: popcntq instruction'.format(host_cpu),
+      args: test_c_args)
+    cdata.set('HAVE_X86_64_POPCNTQ', 1)
+  endif
+
+elif host_cpu == 'ppc' or host_cpu == 'ppc64'
+  # Check if compiler accepts "i"(x) when __builtin_constant_p(x).
+  if cdata.has('HAVE__BUILTIN_CONSTANT_P')
+    if cc.compiles('''
+      static inline int
+      addi(int ra, int si)
+      {
+          int res = 0;
+          if (__builtin_constant_p(si))
+              __asm__ __volatile__(
+                  " addi %0,%1,%2\n" : "=r"(res) : "b"(ra), "i"(si));
+          return res;
+      }
+      int test_adds(int x) { return addi(3, x) + addi(x, 5); }
+      ''',
+      args: test_c_args)
+      cdata.set('HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P', 1)
+    endif
+  endif
+endif
+
+
+
+###############################################################
+# Library / OS tests
+###############################################################
+
+# XXX: Might be worth conditioning some checks on the OS, to avoid doing
+# unnecessary checks over and over, particularly on windows.
+header_checks = [
+  'atomic.h',
+  'copyfile.h',
+  'crtdefs.h',
+  'execinfo.h',
+  'getopt.h',
+  'ifaddrs.h',
+  'langinfo.h',
+  'mbarrier.h',
+  'stdbool.h',
+  'strings.h',
+  'sys/epoll.h',
+  'sys/event.h',
+  'sys/personality.h',
+  'sys/prctl.h',
+  'sys/procctl.h',
+  'sys/signalfd.h',
+  'sys/ucred.h',
+  'termios.h',
+  'ucred.h',
+]
+
+foreach header : header_checks
+  varname = 'HAVE_' + header.underscorify().to_upper()
+
+  # Emulate autoconf behaviour of not-found->undef, found->1
+  found = cc.has_header(header,
+    include_directories: postgres_inc, args: test_c_args)
+  cdata.set(varname, found ? 1 : false,
+            description: 'Define to 1 if you have the <@0@> header file.'.format(header))
+endforeach
+
+
+decl_checks = [
+  ['F_FULLFSYNC', 'fcntl.h'],
+  ['fdatasync', 'unistd.h'],
+  ['posix_fadvise', 'fcntl.h'],
+  ['strlcat', 'string.h'],
+  ['strlcpy', 'string.h'],
+  ['strnlen', 'string.h'],
+]
+
+# Need to check for function declarations for these functions, because
+# checking for library symbols wouldn't handle deployment target
+# restrictions on macOS
+decl_checks += [
+  ['preadv', 'sys/uio.h'],
+  ['pwritev', 'sys/uio.h'],
+]
+
+foreach c : decl_checks
+  func = c.get(0)
+  header = c.get(1)
+  args = c.get(2, {})
+  varname = 'HAVE_DECL_' + func.underscorify().to_upper()
+
+  found = cc.has_header_symbol(header, func,
+    args: test_c_args, include_directories: postgres_inc,
+    kwargs: args)
+  cdata.set10(varname, found, description:
+'''Define to 1 if you have the declaration of `@0@', and to 0 if you
+   don't.'''.format(func))
+endforeach
+
+
+if cc.has_type('struct cmsgcred',
+    args: test_c_args + ['@0@'.format(cdata.get('HAVE_SYS_UCRED_H')) == 'false' ? '' : '-DHAVE_SYS_UCRED_H'],
+    include_directories: postgres_inc,
+    prefix: '''
+#include <sys/socket.h>
+#include <sys/param.h>
+#ifdef HAVE_SYS_UCRED_H
+#include <sys/ucred.h>
+#endif''')
+  cdata.set('HAVE_STRUCT_CMSGCRED', 1)
+else
+  cdata.set('HAVE_STRUCT_CMSGCRED', false)
+endif
+
+if cc.has_type('struct option',
+    args: test_c_args, include_directories: postgres_inc,
+    prefix: '@0@'.format(cdata.get('HAVE_GETOPT_H')) == '1' ? '#include <getopt.h>' : '')
+  cdata.set('HAVE_STRUCT_OPTION', 1)
+endif
+
+
+foreach c : ['opterr', 'optreset']
+  varname = 'HAVE_INT_' + c.underscorify().to_upper()
+
+  if cc.links('''
+#include <unistd.h>
+int main(void)
+{
+    extern int @0@;
+    @0@ = 1;
+}
+'''.format(c), name: c, args: test_c_args)
+    cdata.set(varname, 1)
+  else
+    cdata.set(varname, false)
+  endif
+endforeach
+
+if cc.has_type('socklen_t',
+    args: test_c_args, include_directories: postgres_inc,
+    prefix: '''
+#include <sys/socket.h>''')
+  cdata.set('HAVE_SOCKLEN_T', 1)
+endif
+
+if cc.has_member('struct sockaddr', 'sa_len',
+    args: test_c_args, include_directories: postgres_inc,
+    prefix: '''
+#include <sys/types.h>
+#include <sys/socket.h>''')
+  cdata.set('HAVE_STRUCT_SOCKADDR_SA_LEN', 1)
+endif
+
+if cc.has_member('struct tm', 'tm_zone',
+    args: test_c_args, include_directories: postgres_inc,
+    prefix: '''
+#include <sys/types.h>
+#include <time.h>
+''')
+  cdata.set('HAVE_STRUCT_TM_TM_ZONE', 1)
+endif
+
+if cc.compiles('''
+#include <time.h>
+extern int foo(void);
+int foo(void)
+{
+    return timezone / 60;
+}
+''',
+    name: 'global variable `timezone\' exists',
+    args: test_c_args, include_directories: postgres_inc)
+  cdata.set('HAVE_INT_TIMEZONE', 1)
+else
+  cdata.set('HAVE_INT_TIMEZONE', false)
+endif
+
+if cc.has_type('union semun',
+    args: test_c_args,
+    include_directories: postgres_inc,
+    prefix: '''
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+''')
+  cdata.set('HAVE_UNION_SEMUN', 1)
+endif
+
+if cc.compiles('''
+#include <string.h>
+int main(void)
+{
+  char buf[100];
+  switch (strerror_r(1, buf, sizeof(buf)))
+  { case 0: break; default: break; }
+}''',
+    name: 'strerror_r',
+    args: test_c_args, include_directories: postgres_inc)
+  cdata.set('STRERROR_R_INT', 1)
+else
+  cdata.set('STRERROR_R_INT', false)
+endif
+
+# Check for the locale_t type and find the right header file.  macOS
+# needs xlocale.h; standard is locale.h, but glibc also has an
+# xlocale.h file that we should not use.
+if cc.has_type('locale_t', prefix: '#include <locale.h>')
+  cdata.set('HAVE_LOCALE_T', 1)
+elif cc.has_type('locale_t', prefix: '#include <xlocale.h>')
+  cdata.set('HAVE_LOCALE_T', 1)
+  cdata.set('LOCALE_T_IN_XLOCALE', 1)
+endif
+
+# Check if the C compiler understands typeof or a variant.  Define
+# HAVE_TYPEOF if so, and define 'typeof' to the actual key word.
+foreach kw : ['typeof', '__typeof__', 'decltype']
+  if cc.compiles('''
+int main(void)
+{
+    int x = 0;
+    @0@(x) y;
+    y = x;
+    return y;
+}
+'''.format(kw),
+    name: 'typeof()',
+    args: test_c_args, include_directories: postgres_inc)
+
+    cdata.set('HAVE_TYPEOF', 1)
+    if kw != 'typeof'
+      cdata.set('typeof', kw)
+    endif
+
+    break
+  endif
+endforeach
+
+
+# Try to find a declaration for wcstombs_l().  It might be in stdlib.h
+# (following the POSIX requirement for wcstombs()), or in locale.h, or in
+# xlocale.h.  If it's in the latter, define WCSTOMBS_L_IN_XLOCALE.
+wcstombs_l_test = '''
+#include <stdlib.h>
+#include <locale.h>
+@0@
+
+void main(void)
+{
+#ifndef wcstombs_l
+    (void) wcstombs_l;
+#endif
+}
+'''
+if (not cc.compiles(wcstombs_l_test.format(''),
+      name: 'wcstombs_l') and
+    cc.compiles(wcstombs_l_test.format('#include <xlocale.h>'),
+      name: 'wcstombs_l in xlocale.h'))
+    cdata.set('WCSTOMBS_L_IN_XLOCALE', 1)
+endif
+
+
+# MSVC doesn't cope well with defining restrict to __restrict, the spelling it
+# understands, because it conflicts with __declspec(restrict). Therefore we
+# define pg_restrict to the appropriate definition, which presumably won't
+# conflict.
+#
+# We assume C99 support, so we don't need to make this conditional.
+#
+# XXX: Historically we allowed platforms to disable restrict in template
+# files, but that was only added for AIX when building with XLC, which we
+# don't support yet.
+cdata.set('pg_restrict', '__restrict')
+
+
+if cc.links('''
+#include <machine/vmparam.h>
+#include <sys/exec.h>
+
+int main(void)
+{
+    PS_STRINGS->ps_nargvstr = 1;
+    PS_STRINGS->ps_argvstr = "foo";
+}
+''',
+  name: 'PS_STRINGS', args: test_c_args)
+  cdata.set('HAVE_PS_STRINGS', 1)
+else
+  cdata.set('HAVE_PS_STRINGS', false)
+endif
+
+
+# Most libraries are included only if they demonstrably provide a function we
+# need, but libm is an exception: always include it, because there are too
+# many compilers that play cute optimization games that will break probes for
+# standard functions such as pow().
+os_deps += cc.find_library('m', required: false)
+
+rt_dep = cc.find_library('rt', required: false)
+
+dl_dep = cc.find_library('dl', required: false)
+
+util_dep = cc.find_library('util', required: false)
+posix4_dep = cc.find_library('posix4', required: false)
+
+getopt_dep = cc.find_library('getopt', required: false)
+gnugetopt_dep = cc.find_library('gnugetopt', required: false)
+
+# Required on BSDs
+execinfo_dep = cc.find_library('execinfo', required: false)
+
+if host_system == 'cygwin'
+  cygipc_dep = cc.find_library('cygipc', required: false)
+else
+  cygipc_dep = not_found_dep
+endif
+
+if host_system == 'sunos'
+  socket_dep = cc.find_library('socket', required: false)
+else
+  socket_dep = not_found_dep
+endif
+
+# XXX: Might be worth conditioning some checks on the OS, to avoid doing
+# unnecessary checks over and over, particularly on windows.
+func_checks = [
+  ['_configthreadlocale', {'skip': host_system != 'windows'}],
+  ['backtrace_symbols', {'dependencies': [execinfo_dep]}],
+  ['clock_gettime', {'dependencies': [rt_dep, posix4_dep], 'define': false}],
+  ['copyfile'],
+  # gcc/clang's sanitizer helper library provides dlopen but not dlsym, thus
+  # when enabling asan the dlopen check doesn't notice that -ldl is actually
+  # required. Just checking for dlsym() ought to suffice.
+  ['dlsym', {'dependencies': [dl_dep], 'define': false}],
+  ['explicit_bzero'],
+  ['fdatasync', {'dependencies': [rt_dep, posix4_dep], 'define': false}], # Solaris
+  ['getifaddrs'],
+  ['getopt', {'dependencies': [getopt_dep, gnugetopt_dep]}],
+  ['getopt_long', {'dependencies': [getopt_dep, gnugetopt_dep]}],
+  ['getpeereid'],
+  ['getpeerucred'],
+  ['inet_aton'],
+  ['inet_pton'],
+  ['kqueue'],
+  ['mbstowcs_l'],
+  ['memset_s'],
+  ['mkdtemp'],
+  ['posix_fadvise'],
+  ['posix_fallocate'],
+  ['ppoll'],
+  ['pstat'],
+  ['pthread_barrier_wait', {'dependencies': [thread_dep]}],
+  ['pthread_is_threaded_np', {'dependencies': [thread_dep]}],
+  ['sem_init', {'dependencies': [rt_dep, thread_dep], 'skip': sema_kind != 'unnamed_posix', 'define': false}],
+  ['setproctitle', {'dependencies': [util_dep]}],
+  ['setproctitle_fast'],
+  ['shm_open', {'dependencies': [rt_dep], 'define': false}],
+  ['shm_unlink', {'dependencies': [rt_dep], 'define': false}],
+  ['shmget', {'dependencies': [cygipc_dep], 'define': false}],
+  ['socket', {'dependencies': [socket_dep], 'define': false}],
+  ['strchrnul'],
+  ['strerror_r', {'dependencies': [thread_dep]}],
+  ['strlcat'],
+  ['strlcpy'],
+  ['strnlen'],
+  ['strsignal'],
+  ['sync_file_range'],
+  ['syncfs'],
+  ['uselocale'],
+  ['wcstombs_l'],
+]
+
+func_check_results = {}
+foreach c : func_checks
+  func = c.get(0)
+  kwargs = c.get(1, {})
+  deps = kwargs.get('dependencies', [])
+
+  if kwargs.get('skip', false)
+    continue
+  endif
+
+  found = cc.has_function(func, args: test_c_args)
+
+  if not found
+    foreach dep : deps
+      if not dep.found()
+        continue
+      endif
+      found = cc.has_function(func, args: test_c_args,
+                              dependencies: [dep])
+      if found
+        os_deps += dep
+        break
+      endif
+    endforeach
+  endif
+
+  func_check_results += {func: found}
+
+  if kwargs.get('define', true)
+    # Emulate autoconf behaviour of not-found->undef, found->1
+    cdata.set('HAVE_' + func.underscorify().to_upper(),
+              found  ? 1 : false,
+              description: 'Define to 1 if you have the `@0@\' function.'.format(func))
+  endif
+endforeach
+
+
+if cc.has_function('syslog', args: test_c_args) and \
+    cc.check_header('syslog.h', args: test_c_args)
+  cdata.set('HAVE_SYSLOG', 1)
+endif
+
+
+# if prerequisites for unnamed posix semas aren't fulfilled, fall back to sysv
+# semaphores
+if sema_kind == 'unnamed_posix' and \
+   not func_check_results.get('sem_init', false)
+  sema_kind = 'sysv'
+endif
+
+cdata.set('USE_@0@_SHARED_MEMORY'.format(shmem_kind.to_upper()), 1)
+cdata.set('USE_@0@_SEMAPHORES'.format(sema_kind.to_upper()), 1)
+
+cdata.set('MEMSET_LOOP_LIMIT', memset_loop_limit)
+cdata.set_quoted('DLSUFFIX', dlsuffix)
+
+
+
+###############################################################
+# Threading
+###############################################################
+
+# XXX: About to rely on thread safety in the autoconf build, so not worth
+# implementing a fallback.
+cdata.set('ENABLE_THREAD_SAFETY', 1)
+
+
+
+###############################################################
+# NLS / Gettext
+###############################################################
+
+nlsopt = get_option('nls')
+libintl = not_found_dep
+
+if not nlsopt.disabled()
+  # otherwise there'd be lots of
+  # "Gettext not found, all translation (po) targets will be ignored."
+  # warnings if not found.
+  msgfmt = find_program('msgfmt', required: nlsopt.enabled(), native: true)
+
+  # meson 0.59 has this wrapped in dependency('int')
+  if (msgfmt.found() and
+      cc.check_header('libintl.h', required: nlsopt,
+        args: test_c_args, include_directories: postgres_inc))
+
+    # in libc
+    if cc.has_function('ngettext')
+      libintl = declare_dependency()
+    else
+      libintl = cc.find_library('intl',
+        has_headers: ['libintl.h'], required: nlsopt,
+        header_include_directories: postgres_inc,
+        dirs: test_lib_d)
+    endif
+  endif
+
+  if libintl.found()
+    i18n = import('i18n')
+    cdata.set('ENABLE_NLS', 1)
+  endif
+endif
+
+
+
+###############################################################
+# Build
+###############################################################
+
+# Set up compiler / linker arguments to be used everywhere, individual targets
+# can add further args directly, or indirectly via dependencies
+add_project_arguments(cflags, language: ['c'])
+add_project_arguments(cppflags, language: ['c'])
+add_project_arguments(cflags_warn, language: ['c'])
+add_project_arguments(cxxflags, language: ['cpp'])
+add_project_arguments(cppflags, language: ['cpp'])
+add_project_arguments(cxxflags_warn, language: ['cpp'])
+add_project_link_arguments(ldflags, language: ['c', 'cpp'])
+
+
+# Collect a number of lists of things while recursing through the source
+# tree. Later steps then can use those.
+
+# list of targets for various alias targets
+backend_targets = []
+bin_targets = []
+pl_targets = []
+contrib_targets = []
+testprep_targets = []
+
+
+# Define the tests to distribute them to the correct test styles later
+test_deps = []
+tests = []
+
+
+# Default options for targets
+
+# First identify rpaths
+bin_install_rpaths = []
+lib_install_rpaths = []
+mod_install_rpaths = []
+
+# Add extra_lib_dirs to rpath. Not needed on darwin, as the install_name of
+# libraries in extra_lib_dirs will be used anyway.
+if host_system != 'darwin'
+  bin_install_rpaths += postgres_lib_d
+  lib_install_rpaths += postgres_lib_d
+  mod_install_rpaths += postgres_lib_d
+endif
+
+
+# Define arguments for default targets
+
+default_target_args = {
+  'implicit_include_directories': false,
+  'install': true,
+}
+
+default_lib_args = default_target_args + {
+  'name_prefix': '',
+  'install_rpath': ':'.join(lib_install_rpaths),
+}
+
+internal_lib_args = default_lib_args + {
+  'build_by_default': false,
+  'install': false,
+}
+
+default_mod_args = default_lib_args + {
+  'name_prefix': '',
+  'install_dir': dir_lib_pkg,
+  'install_rpath': ':'.join(mod_install_rpaths),
+}
+
+default_bin_args = default_target_args + {
+  'install_dir': dir_bin,
+  'install_rpath': ':'.join(bin_install_rpaths),
+}
+
+
+
+# Helper for exporting a limited number of symbols
+gen_export_kwargs = {
+  'input': 'exports.txt',
+  'output': '@BASENAME@.'+export_file_suffix,
+  'command': [perl, files('src/tools/gen_export.pl'),
+   '--format', export_file_format,
+   '--input', '@INPUT0@', '--output', '@OUTPUT0@'],
+  'build_by_default': false,
+  'install': false,
+}
+
+
+
+# headers that the whole build tree depends on
+generated_headers = []
+# headers that the backend build depends on
+generated_backend_headers = []
+# configure_files() output, needs a way of converting to file names
+configure_files = []
+
+# generated files that might conflict with a partial in-tree autoconf build
+generated_sources = []
+# same, for paths that differ between autoconf / meson builds
+# elements are [dir, [files]]
+generated_sources_ac = {}
+
+
+# First visit src/include - all targets creating headers are defined
+# within. That makes it easy to add the necessary dependencies for the
+# subsequent build steps.
+
+subdir('src/include')
+
+subdir('config')
+
+# Then through src/port and src/common, as most other things depend on them
+
+frontend_port_code = declare_dependency(
+  compile_args: ['-DFRONTEND'],
+  include_directories: [postgres_inc],
+  dependencies: os_deps,
+)
+
+backend_port_code = declare_dependency(
+  compile_args: ['-DBUILDING_DLL'],
+  include_directories: [postgres_inc],
+  sources: [errcodes], # errcodes.h is needed due to use of ereport
+  dependencies: os_deps,
+)
+
+subdir('src/port')
+
+frontend_common_code = declare_dependency(
+  compile_args: ['-DFRONTEND'],
+  include_directories: [postgres_inc],
+  sources: generated_headers,
+  dependencies: [os_deps, zlib, zstd],
+)
+
+backend_common_code = declare_dependency(
+  compile_args: ['-DBUILDING_DLL'],
+  include_directories: [postgres_inc],
+  sources: generated_headers,
+  dependencies: [os_deps, zlib, zstd],
+)
+
+subdir('src/common')
+
+frontend_shlib_code = declare_dependency(
+  compile_args: ['-DFRONTEND'],
+  include_directories: [postgres_inc],
+  link_args: ldflags_sl,
+  link_with: [pgport_shlib, common_shlib],
+  sources: generated_headers,
+  dependencies: [os_deps, libintl],
+)
+
+libpq_deps += [
+  frontend_shlib_code,
+  thread_dep,
+
+  gssapi,
+  ldap_r,
+  libintl,
+  ssl,
+]
+
+subdir('src/interfaces/libpq')
+# fe_utils depends on libpq
+subdir('src/fe_utils')
+
+frontend_code = declare_dependency(
+  include_directories: [postgres_inc],
+  link_with: [fe_utils, common_static, pgport_static],
+  sources: generated_headers,
+  dependencies: [os_deps, libintl],
+)
+
+backend_both_deps += [
+  thread_dep,
+  bsd_auth,
+  gssapi,
+  icu,
+  icu_i18n,
+  ldap,
+  libintl,
+  libxml,
+  lz4,
+  pam,
+  ssl,
+  systemd,
+  zlib,
+  zstd,
+]
+
+backend_mod_deps = backend_both_deps + os_deps
+
+backend_code = declare_dependency(
+  compile_args: ['-DBUILDING_DLL'],
+  include_directories: [postgres_inc],
+  link_args: ldflags_be,
+  link_with: [],
+  sources: generated_headers + generated_backend_headers,
+  dependencies: os_deps + backend_both_deps + backend_deps,
+)
+
+# src/backend/meson.build defines backend_mod_code used for extension
+# libraries.
+
+
+# Then through the main sources. That way contrib can have dependencies on
+# main sources. Note that this explicitly doesn't enter src/test, right now a
+# few regression tests depend on contrib files.
+
+subdir('src')
+
+subdir('contrib')
+
+subdir('src/test')
+subdir('src/interfaces/libpq/test')
+subdir('src/interfaces/ecpg/test')
+
+subdir('doc/src/sgml')
+
+generated_sources_ac += {'': ['GNUmakefile']}
+
+
+# If there are any files in the source directory that we also generate in the
+# build directory, they might get preferred over the newly generated files,
+# e.g. because of a #include "file", which always will search in the current
+# directory first.
+message('checking for file conflicts between source and build directory')
+conflicting_files = []
+potentially_conflicting_files_t = []
+potentially_conflicting_files_t += generated_headers
+potentially_conflicting_files_t += generated_backend_headers
+potentially_conflicting_files_t += generated_backend_sources
+potentially_conflicting_files_t += generated_sources
+
+potentially_conflicting_files = []
+
+# convert all sources of potentially conflicting files into uniform shape
+foreach t : potentially_conflicting_files_t
+  potentially_conflicting_files += t.full_path()
+endforeach
+foreach t : configure_files
+  t = '@0@'.format(t)
+  potentially_conflicting_files += meson.current_build_dir() / t
+endforeach
+foreach sub, fnames : generated_sources_ac
+  sub = meson.build_root() / sub
+  foreach fname : fnames
+    potentially_conflicting_files += sub / fname
+  endforeach
+endforeach
+
+# find and report conflicting files
+foreach build_path : potentially_conflicting_files
+  build_path = host_system == 'windows' ? fs.as_posix(build_path) : build_path
+  # str.replace is in 0.56
+  src_path = meson.current_source_dir() / build_path.split(meson.current_build_dir() / '')[1]
+  if fs.exists(src_path) or fs.is_symlink(src_path)
+    conflicting_files += src_path
+  endif
+endforeach
+# XXX: Perhaps we should generate a file that would clean these up? The list
+# can be long.
+if conflicting_files.length() > 0
+  errmsg_cleanup = '''
+Conflicting files in source directory:
+  @0@
+
+The conflicting files need to be removed, either by removing the files listed
+above, or by running configure and then make maintainer-clean.
+'''
+  errmsg_cleanup = errmsg_cleanup.format(' '.join(conflicting_files))
+  error(errmsg_nonclean_base.format(errmsg_cleanup))
+endif
+
+
+
+###############################################################
+# Test prep
+###############################################################
+
+# The determination of where a DESTDIR install points to is ugly, it's somewhat hard
+# to combine two absolute paths portably...
+
+prefix = get_option('prefix')
+
+test_prefix = prefix
+
+if fs.is_absolute(get_option('prefix'))
+  if host_system == 'windows'
+    if prefix.split(':\\').length() == 1
+      # just a drive
+      test_prefix = ''
+    else
+      test_prefix = prefix.split(':\\')[1]
+    endif
+  else
+    assert(prefix.startswith('/'))
+    test_prefix = './@0@'.format(prefix)
+  endif
+endif
+
+# DESTDIR for the installation used to run tests in
+test_install_destdir = meson.build_root() / 'tmp_install/'
+# DESTDIR + prefix appropriately munged
+test_install_location = test_install_destdir / test_prefix
+
+
+meson_install_args = meson_args + ['install'] + {
+    'meson': ['--quiet', '--only-changed', '--no-rebuild'],
+    'muon': []
+}[meson_impl]
+
+test('tmp_install',
+    meson_bin, args: meson_install_args ,
+    env: {'DESTDIR':test_install_destdir},
+    priority: 100,
+    timeout: 300,
+    is_parallel: false,
+    suite: ['setup'])
+
+test_result_dir = meson.build_root() / 'testrun'
+
+
+# XXX: pg_regress doesn't assign unique ports on windows. To avoid the
+# inevitable conflicts from running tests in parallel, hackishly assign
+# different ports for different tests.
+
+testport = 40000
+
+test_env = environment()
+
+temp_install_bindir = test_install_location / get_option('bindir')
+test_env.set('PG_REGRESS', pg_regress.full_path())
+test_env.set('REGRESS_SHLIB', regress_module.full_path())
+
+# Test suites that are not safe by default but can be run if selected
+# by the user via the whitespace-separated list in variable PG_TEST_EXTRA.
+# Export PG_TEST_EXTRA so it can be checked in individual tap tests.
+test_env.set('PG_TEST_EXTRA', get_option('PG_TEST_EXTRA'))
+
+# Add the temporary installation to the library search path on platforms where
+# that works (everything but windows, basically). On windows everything
+# library-like gets installed into bindir, solving that issue.
+if library_path_var != ''
+  test_env.prepend(library_path_var, test_install_location / get_option('libdir'))
+endif
+
+
+
+###############################################################
+# Test Generation
+###############################################################
+
+testwrap = files('src/tools/testwrap')
+
+foreach test_dir : tests
+  testwrap_base = [
+    testwrap,
+    '--basedir', meson.build_root(),
+    '--srcdir', test_dir['sd'],
+    '--testgroup', test_dir['name'],
+  ]
+
+  foreach kind, v : test_dir
+    if kind in ['sd', 'bd', 'name']
+      continue
+    endif
+
+    t = test_dir[kind]
+
+    if kind in ['regress', 'isolation', 'ecpg']
+      if kind == 'regress'
+        runner = pg_regress
+      elif kind == 'isolation'
+        runner = pg_isolation_regress
+      elif kind == 'ecpg'
+        runner = pg_regress_ecpg
+      endif
+
+      test_output = test_result_dir / test_dir['name'] / kind
+
+      test_command = [
+        runner.full_path(),
+        '--inputdir', t.get('inputdir', test_dir['sd']),
+        '--expecteddir', t.get('expecteddir', test_dir['sd']),
+        '--outputdir', test_output,
+        '--temp-instance', test_output / 'tmp_check',
+        '--bindir', '',
+        '--dlpath', test_dir['bd'],
+        '--max-concurrent-tests=20',
+        '--port', testport.to_string(),
+      ] + t.get('regress_args', [])
+
+      if t.has_key('schedule')
+        test_command += ['--schedule', t['schedule'],]
+      endif
+
+      if kind == 'isolation'
+        test_command += t.get('specs', [])
+      else
+        test_command += t.get('sql', [])
+      endif
+
+      env = test_env
+      env.prepend('PATH', temp_install_bindir, test_dir['bd'])
+
+      test_kwargs = {
+        'suite': [test_dir['name']],
+        'priority': 10,
+        'timeout': 1000,
+        'depends': test_deps + t.get('deps', []),
+        'env': env,
+      } + t.get('test_kwargs', {})
+
+      test(test_dir['name'] / kind,
+        python,
+        args: testwrap_base + [
+          '--testname', kind,
+          '--', test_command,
+        ],
+        kwargs: test_kwargs,
+      )
+
+      testport += 1
+    elif kind == 'tap'
+      if not tap_tests_enabled
+        continue
+      endif
+
+      test_command = [
+        perl.path(),
+        '-I', meson.source_root() / 'src/test/perl',
+        '-I', test_dir['sd'],
+      ]
+
+      # Add temporary install, the build directory for non-installed binaries and
+      # also test/ for non-installed test binaries built separately.
+      env = test_env
+      env.prepend('PATH', temp_install_bindir, test_dir['bd'], test_dir['bd'] / 'test')
+
+      foreach name, value : t.get('env', {})
+        env.set(name, value)
+      endforeach
+
+      test_kwargs = {
+        'protocol': 'tap',
+        'suite': [test_dir['name']],
+        'timeout': 1000,
+        'depends': test_deps + t.get('deps', []),
+        'env': env,
+      } + t.get('test_kwargs', {})
+
+      foreach onetap : t['tests']
+        # Make tap test names prettier, remove t/ and .pl
+        onetap_p = onetap
+        if onetap_p.startswith('t/')
+          onetap_p = onetap.split('t/')[1]
+        endif
+        if onetap_p.endswith('.pl')
+          onetap_p = fs.stem(onetap_p)
+        endif
+
+        test(test_dir['name'] / onetap_p,
+          python,
+          kwargs: test_kwargs,
+          args: testwrap_base + [
+            '--testname', onetap_p,
+            '--', test_command,
+            test_dir['sd'] / onetap,
+          ],
+        )
+      endforeach
+    else
+      error('unknown kind @0@ of test in @1@'.format(kind, test_dir['sd']))
+    endif
+
+  endforeach # kinds of tests
+
+endforeach # directories with tests
+
+
+
+###############################################################
+# Pseudo targets
+###############################################################
+
+alias_target('backend', backend_targets)
+alias_target('bin', bin_targets + [libpq_st])
+alias_target('pl', pl_targets)
+alias_target('contrib', contrib_targets)
+alias_target('testprep', testprep_targets)
+
+
+
+###############################################################
+# The End, The End, My Friend
+###############################################################
+
+if meson.version().version_compare('>=0.57')
+
+  summary(
+    {
+      'data block size': cdata.get('BLCKSZ'),
+      'WAL block size': cdata.get('XLOG_BLCKSZ') / 1024,
+      'segment size': cdata.get('RELSEG_SIZE') / 131072,
+    },
+    section: 'Data layout',
+  )
+
+  summary(
+    {
+      'host system': '@0@ @1@'.format(host_system, host_cpu),
+      'build system': '@0@ @1@'.format(build_machine.system(),
+                                       build_machine.cpu_family()),
+    },
+    section: 'System',
+  )
+
+  summary(
+    {
+      'linker': '@0@'.format(cc.get_linker_id()),
+      'C compiler': '@0@ @1@'.format(cc.get_id(), cc.version()),
+    },
+    section: 'Compiler',
+  )
+
+  summary(
+    {
+      'CPP FLAGS': ' '.join(cppflags),
+      'C FLAGS, functional': ' '.join(cflags),
+      'C FLAGS, warnings': ' '.join(cflags_warn),
+    },
+    section: 'Compiler Flags',
+  )
+
+  if llvm.found()
+    summary(
+      {
+        'C++ compiler': '@0@ @1@'.format(cpp.get_id(), cpp.version()),
+      },
+      section: 'Compiler',
+    )
+
+    summary(
+      {
+        'C++ FLAGS, functional': ' '.join(cxxflags),
+        'C++ FLAGS, warnings': ' '.join(cxxflags_warn),
+      },
+      section: 'Compiler Flags',
+    )
+  endif
+
+  summary(
+    {
+      'bison': '@0@ @1@'.format(bison.full_path(), bison_version),
+      'dtrace': dtrace,
+    },
+    section: 'Programs',
+  )
+
+  summary(
+    {
+      'bonjour': bonjour,
+      'bsd_auth': bsd_auth,
+      'gss': gssapi,
+      'icu': icu,
+      'ldap': ldap,
+      'libxml': libxml,
+      'libxslt': libxslt,
+      'llvm': llvm,
+      'lz4': lz4,
+      'nls': libintl,
+      'pam': pam,
+      'plperl': perl_dep,
+      'plpython': python3_dep,
+      'pltcl': tcl_dep,
+      'readline': readline,
+      'selinux': selinux,
+      'ssl': ssl,
+      'systemd': systemd,
+      'uuid': uuid,
+      'zlib': zlib,
+      'zstd': zstd,
+    },
+    section: 'External libraries',
+  )
+
+endif
diff --git a/meson_options.txt b/meson_options.txt
new file mode 100644
index 00000000000..e847755caa4
--- /dev/null
+++ b/meson_options.txt
@@ -0,0 +1,185 @@
+# Data layout influencing options
+
+option('blocksize', type : 'combo',
+  choices : ['1', '2', '4', '8', '16', '32'],
+  value : '8',
+  description: 'set relation block size in kB')
+
+option('wal_blocksize', type : 'combo',
+  choices: ['1', '2', '4', '8', '16', '32', '64'],
+  value: '8',
+  description : '''WAL block size, in kilobytes''')
+
+option('segsize', type : 'integer', value : 1,
+  description : '''Segment size, in gigabytes''')
+
+
+# Miscellaneous options
+
+option('krb_srvnam', type : 'string', value : 'postgres',
+  description : '''Default Kerberos service principal for GSSAPI''')
+
+option('system_tzdata', type: 'string', value: '',
+  description: 'use system time zone data in specified directory')
+
+
+# Defaults
+
+option('pgport', type : 'integer', value : 5432,
+  min: 1, max: 65535,
+  description : '''Default port number for server and clients''')
+
+
+# Developer options
+
+option('cassert', type : 'boolean', value: false,
+  description: 'enable assertion checks (for debugging)')
+
+option('tap_tests', type : 'feature', value : 'auto',
+  description : 'Whether to enable tap tests')
+
+option('PG_TEST_EXTRA', type : 'string', value: 'kerberos ldap ssl',
+  description: 'Enable selected extra tests')
+
+option('atomics', type : 'boolean', value: true,
+  description: 'whether to use atomic operations')
+
+option('spinlocks', type : 'boolean', value: true,
+  description: 'whether to use spinlocks')
+
+
+# Compilation options
+
+option('extra_include_dirs', type : 'array', value: [],
+  description: 'non-default directories to be searched for headers')
+
+option('extra_lib_dirs', type : 'array', value: [],
+  description: 'non-default directories to be searched for libs')
+
+option('extra_version', type : 'string', value: '',
+  description: 'append STRING to the PostgreSQL version number')
+
+option('darwin_sysroot', type : 'string', value: '',
+  description: 'select a non-default sysroot path')
+
+
+# External dependencies
+
+option('bonjour', type : 'feature', value: 'auto',
+  description: 'build with Bonjour support')
+
+option('bsd_auth', type : 'feature', value: 'auto',
+  description: 'build with BSD Authentication support')
+
+option('dtrace', type : 'feature', value: 'disabled',
+  description: 'DTrace support')
+
+option('gssapi', type : 'feature', value: 'auto',
+  description: 'GSSAPI support')
+
+option('icu', type : 'feature', value: 'auto',
+  description: 'ICU support')
+
+option('ldap', type : 'feature', value: 'auto',
+  description: 'LDAP support')
+
+option('libedit_preferred', type : 'boolean', value: false,
+  description: 'Prefer BSD Libedit over GNU Readline')
+
+option('libxml', type : 'feature', value: 'auto',
+  description: 'XML support')
+
+option('libxslt', type : 'feature', value: 'auto',
+  description: 'XSLT support in contrib/xml2')
+
+option('llvm', type : 'feature', value: 'disabled',
+  description: 'whether to use llvm')
+
+option('lz4', type : 'feature', value: 'auto',
+  description: 'LZ4 support')
+
+option('nls', type: 'feature', value: 'auto',
+  description: 'native language support')
+
+option('pam', type : 'feature', value: 'auto',
+  description: 'build with PAM support')
+
+option('plperl', type : 'feature', value: 'auto',
+  description: 'build Perl modules (PL/Perl)')
+
+option('plpython', type : 'feature', value: 'auto',
+  description: 'build Python modules (PL/Python)')
+
+option('pltcl', type : 'feature', value: 'auto',
+  description: 'build with TCL support')
+
+option('tcl_version', type : 'string', value : 'tcl',
+  description: 'specify TCL version')
+
+option('readline', type : 'feature', value : 'auto',
+  description: 'use GNU Readline or BSD Libedit for editing')
+
+option('selinux', type : 'feature', value : 'disabled',
+  description: 'build with SELinux support')
+
+option('ssl', type : 'combo', choices : ['none', 'openssl'],
+  value : 'none',
+  description: 'use LIB for SSL/TLS support (openssl)')
+
+option('systemd', type : 'feature', value: 'auto',
+  description: 'build with systemd support')
+
+option('uuid', type : 'combo', choices : ['none', 'bsd', 'e2fs', 'ossp'],
+  value : 'none',
+  description: 'build contrib/uuid-ossp using LIB')
+
+option('zlib', type : 'feature', value: 'auto',
+  description: 'whether to use zlib')
+
+option('zstd', type : 'feature', value: 'auto',
+  description: 'whether to use zstd')
+
+
+# Programs
+
+option('BISON', type : 'array', value: ['bison', 'win_bison'],
+  description: 'path to bison binary')
+
+option('DTRACE', type : 'string', value: 'dtrace',
+  description: 'path to dtrace binary')
+
+option('FLEX', type : 'array', value: ['flex', 'win_flex'],
+  description: 'path to flex binary')
+
+option('GZIP', type : 'string', value: 'gzip',
+  description: 'path to gzip binary')
+
+option('LZ4', type : 'string', value: 'lz4',
+  description: 'path to lz4 binary')
+
+option('PERL', type : 'string', value: 'perl',
+  description: 'path to perl binary')
+
+option('PROVE', type : 'string', value: 'prove',
+  description: 'path to prove binary')
+
+option('PYTHON', type : 'array', value: ['python3', 'python'],
+  description: 'path to python binary')
+
+option('SED', type : 'string', value: 'gsed',
+  description: 'path to sed binary')
+
+option('TAR', type : 'string', value: 'tar',
+  description: 'path to tar binary')
+
+option('XMLLINT', type : 'string', value: 'xmllint',
+  description: 'path to xmllint binary')
+
+option('XSLTPROC', type : 'string', value: 'xsltproc',
+  description: 'path to xsltproc binary')
+
+option('ZSTD', type : 'string', value: 'zstd',
+  description: 'path to zstd binary')
+
+option('ZIC', type : 'string', value: 'zic',
+  description: 'path to zic binary, when cross-compiling')
diff --git a/src/meson.build b/src/meson.build
new file mode 100644
index 00000000000..a7fdd5a13ed
--- /dev/null
+++ b/src/meson.build
@@ -0,0 +1,12 @@
+# libraries that other subsystems might depend uppon first, in their
+# respective dependency order
+
+subdir('timezone')
+
+subdir('backend')
+
+subdir('bin')
+
+subdir('pl')
+
+subdir('interfaces')
diff --git a/src/timezone/meson.build b/src/timezone/meson.build
new file mode 100644
index 00000000000..daf8b4aa44f
--- /dev/null
+++ b/src/timezone/meson.build
@@ -0,0 +1,56 @@
+# files to build into backend
+timezone_sources = files(
+  'localtime.c',
+  'pgtz.c',
+  'strftime.c',
+)
+
+
+timezone_inc = include_directories('.')
+
+timezone_localtime_source = files('localtime.c')
+
+# files needed to build zic utility program
+zic_sources = files(
+   'zic.c'
+)
+
+# we now distribute the timezone data as a single file
+tzdata = files(
+  'data/tzdata.zi'
+)
+
+
+if get_option('system_tzdata') == ''
+  # FIXME: For cross builds, it would need a native built libpgport/pgcommon to
+  # build our zic. But for that we'd need to run a good chunk of the configure
+  # tests both natively and cross. Unclear if it's worth it.
+  if meson.is_cross_build()
+    zic = find_program(get_option('ZIC'), native: true, required: true)
+  else
+    zic = executable('zic', zic_sources,
+                     dependencies: [frontend_code],
+                     kwargs: default_bin_args + {'install': false}
+                    )
+  endif
+
+  tzdata = custom_target('tzdata',
+    input: tzdata,
+    output: ['timezone'],
+    command: [zic, '-d', '@OUTPUT@', '@INPUT@'],
+    install: true,
+    install_dir: dir_data,
+  )
+
+  bin_targets += tzdata
+
+  # FIXME: make sorts this - but the file isn't actually used, so ...
+  custom_target('abbrevs.txt',
+    input: tzdata,
+    output: ['abbrevs.txt'],
+    command: [zic, '-P', '-b', 'fat', 'junkdir', '@INPUT@'],
+    capture: true)
+
+endif
+
+subdir('tznames')
diff --git a/src/timezone/tznames/meson.build b/src/timezone/tznames/meson.build
new file mode 100644
index 00000000000..7e0a682bd9e
--- /dev/null
+++ b/src/timezone/tznames/meson.build
@@ -0,0 +1,21 @@
+tznames = files(
+  'Africa.txt',
+  'America.txt',
+  'Antarctica.txt',
+  'Asia.txt',
+  'Atlantic.txt',
+  'Australia.txt',
+  'Etc.txt',
+  'Europe.txt',
+  'Indian.txt',
+  'Pacific.txt',
+)
+
+tznames_sets = files(
+  'Default',
+  'Australia',
+  'India')
+
+install_data(tznames, tznames_sets,
+  install_dir: dir_data / 'timezonesets',
+)
diff --git a/src/tools/find_meson b/src/tools/find_meson
new file mode 100755
index 00000000000..50e501a8011
--- /dev/null
+++ b/src/tools/find_meson
@@ -0,0 +1,30 @@
+#!/usr/bin/env python3
+#
+# Returns the path to the meson binary, for cases where we need to call it as
+# part of the build, e.g. to install into tmp_install/ for the tests.
+
+import os
+import shlex
+import sys
+
+to_print = []
+
+if 'MUON_PATH' in os.environ:
+    to_print += ['muon', os.environ['MUON_PATH']]
+else:
+    mesonintrospect = os.environ['MESONINTROSPECT']
+    components = shlex.split(mesonintrospect)
+
+    if len(components) < 2:
+        print('expected more than two components, got: %s' % components)
+        sys.exit(1)
+
+    if components[-1] != 'introspect':
+        print('expected introspection at the end')
+        sys.exit(1)
+
+    to_print += ['meson'] + components[:-1]
+
+print('\n'.join(to_print), end='')
+
+sys.exit(0)
diff --git a/src/tools/pgflex b/src/tools/pgflex
new file mode 100755
index 00000000000..baabe2df1c8
--- /dev/null
+++ b/src/tools/pgflex
@@ -0,0 +1,85 @@
+#!/usr/bin/env python3
+
+#
+# Wrapper around flex that:
+# - ensures lex.backup is created in a private directory
+# - can error out if lex.backup is created (--no-backup)
+# - can fix warnings (--fix-warnings)
+# - works around concurrency issues with win_flex.exe:
+#   https://github.com/lexxmark/winflexbison/issues/86
+
+import argparse
+import os
+import subprocess
+import sys
+from os.path import abspath
+
+parser = argparse.ArgumentParser()
+
+parser.add_argument('--flex', type=abspath, required=True)
+parser.add_argument('--perl', type=abspath, required=True)
+parser.add_argument('--builddir', type=abspath, required=True)
+parser.add_argument('--srcdir', type=abspath, required=True)
+parser.add_argument('--privatedir', type=abspath, required=True,
+                    help='private directory for target')
+
+parser.add_argument('-o', dest='output_file', type=abspath, required=True,
+                    help='output file')
+parser.add_argument('-i', dest='input_file', type=abspath, help='input file')
+
+
+parser.add_argument('--fix-warnings', action='store_true',
+                    help='whether to fix warnings in generated file')
+parser.add_argument('--no-backup', action='store_true',
+                    help='whether no_backup is enabled or not')
+
+parser.add_argument('flex_flags', nargs='*', help='flags passed on to flex')
+
+args = parser.parse_args()
+
+# Since 'lex.backup' is always named that and ninja uses the top level build
+# directory as current directory for all commands, change directory to
+# temporary directory to avoid conflicts between concurrent flex
+# invocations. Only unreleased versions of flex have an argument to change
+# lex.filename to be named differently.
+if not os.path.isdir(args.privatedir):
+    os.mkdir(args.privatedir)
+os.chdir(args.privatedir)
+
+# win_flex.exe generates names in a racy way, sometimes leading to random
+# "error deleting file" failures and sometimes to intermingled file
+# contents. Set FLEX_TMP_DIR to the target private directory to avoid
+# that. That environment variable isn't consulted on other platforms, so we
+# don't even need to make this conditional.
+env = {'FLEX_TMP_DIR': args.privatedir}
+
+# build flex invocation
+command = [args.flex, '-o', args.output_file]
+if args.no_backup:
+    command += ['-b']
+command += args.flex_flags
+command += [args.input_file]
+
+# create .c file from .l file
+sp = subprocess.run(command, env=env)
+if sp.returncode != 0:
+    sys.exit(sp.returncode)
+
+# check lex.backup
+if args.no_backup:
+    with open('lex.backup') as lex:
+        if len(lex.readlines()) != 1:
+            sys.exit('Scanner requires backup; see lex.backup.')
+    os.remove('lex.backup')
+
+# fix warnings
+if args.fix_warnings:
+    fix_warning_script = os.path.join(args.srcdir,
+                                      'src/tools/fix-old-flex-code.pl')
+
+    command = [args.perl, fix_warning_script, args.output_file]
+    sp = subprocess.run(command)
+    if sp.returncode != 0:
+        sys.exit(sp.returncode)
+
+sys.exit(0)
diff --git a/src/tools/testwrap b/src/tools/testwrap
new file mode 100755
index 00000000000..7a64fe76a2d
--- /dev/null
+++ b/src/tools/testwrap
@@ -0,0 +1,47 @@
+#!/usr/bin/env python3
+
+import argparse
+import shutil
+import subprocess
+import os
+import sys
+
+parser = argparse.ArgumentParser()
+
+parser.add_argument('--srcdir', help='source directory of test', type=str)
+parser.add_argument('--basedir', help='base directory of test', type=str)
+parser.add_argument('--testgroup', help='test group', type=str)
+parser.add_argument('--testname', help='test name', type=str)
+parser.add_argument('test_command', nargs='*')
+
+args = parser.parse_args()
+
+testdir = '{}/testrun/{}/{}'.format(
+    args.basedir, args.testgroup, args.testname)
+
+print('# executing test in {} group {} test {}'.format(
+    testdir, args.testgroup, args.testname))
+sys.stdout.flush()
+
+if os.path.exists(testdir) and os.path.isdir(testdir):
+    shutil.rmtree(testdir)
+os.makedirs(testdir)
+
+os.chdir(args.srcdir)
+
+# mark test as having started
+open(os.path.join(testdir, 'test.start'), 'x')
+
+env_dict = {**os.environ,
+            'TESTDATADIR': os.path.join(testdir, 'data'),
+            'TESTLOGDIR': os.path.join(testdir, 'log')}
+
+sp = subprocess.run(args.test_command, env=env_dict)
+
+if sp.returncode == 0:
+    print('# test succeeded')
+    open(os.path.join(testdir, 'test.success'), 'x')
+else:
+    print('# test failed')
+    open(os.path.join(testdir, 'test.fail'), 'x')
+sys.exit(sp.returncode)
-- 
2.37.3.542.gdd3f6c4cae

