Stamp 16.5.
[pgsql.git] / meson.build
blob5f3766b426a4c64126c8737791d6df2542b6dff5
1 # Copyright (c) 2022-2023, PostgreSQL Global Development Group
3 # Entry point for building PostgreSQL with meson
5 # Good starting points for writing meson.build files are:
6 #  - https://mesonbuild.com/Syntax.html
7 #  - https://mesonbuild.com/Reference-manual.html
9 project('postgresql',
10   ['c'],
11   version: '16.5',
12   license: 'PostgreSQL',
14   # We want < 0.56 for python 3.5 compatibility on old platforms. EPEL for
15   # RHEL 7 has 0.55. < 0.54 would require replacing some uses of the fs
16   # module, < 0.53 all uses of fs. So far there's no need to go to >=0.56.
17   meson_version: '>=0.54',
18   default_options: [
19     'warning_level=1', #-Wall equivalent
20     'b_pch=false',
21     'buildtype=debugoptimized', # -O2 + debug
22     # For compatibility with the autoconf build, set a default prefix. This
23     # works even on windows, where it's a drive-relative path (i.e. when on
24     # d:/somepath it'll install to d:/usr/local/pgsql)
25     'prefix=/usr/local/pgsql',
26   ]
31 ###############################################################
32 # Basic prep
33 ###############################################################
35 fs = import('fs')
36 pkgconfig = import('pkgconfig')
38 host_system = host_machine.system()
39 build_system = build_machine.system()
40 host_cpu = host_machine.cpu_family()
42 cc = meson.get_compiler('c')
44 not_found_dep = dependency('', required: false)
45 thread_dep = dependency('threads')
46 auto_features = get_option('auto_features')
50 ###############################################################
51 # Safety first
52 ###############################################################
54 # It's very easy to get into confusing states when the source directory
55 # contains an in-place build. E.g. the wrong pg_config.h will be used. So just
56 # refuse to build in that case.
58 # There's a more elaborate check later, that checks for conflicts around all
59 # generated files. But we can only do that much further down the line, so this
60 # quick check seems worth it. Adhering to this advice should clean up the
61 # conflict, but won't protect against somebody doing make distclean or just
62 # removing pg_config.h
63 errmsg_nonclean_base = '''
64 ****
65 Non-clean source code directory detected.
67 To build with meson the source tree may not have an in-place, ./configure
68 style, build configured. You can have both meson and ./configure style builds
69 for the same source tree by building out-of-source / VPATH with
70 configure. Alternatively use a separate check out for meson based builds.
72 @0@
73 ****'''
74 if fs.exists(meson.current_source_dir() / 'src' / 'include' / 'pg_config.h')
75   errmsg_cleanup = 'To clean up, run make maintainer-clean in the source tree.'
76   error(errmsg_nonclean_base.format(errmsg_cleanup))
77 endif
81 ###############################################################
82 # Variables to be determined
83 ###############################################################
85 postgres_inc_d = ['src/include']
86 postgres_inc_d += get_option('extra_include_dirs')
88 postgres_lib_d = get_option('extra_lib_dirs')
90 cppflags = []
92 cflags = []
93 cxxflags = []
94 cflags_warn = []
95 cxxflags_warn = []
96 cflags_mod = []
97 cxxflags_mod = []
99 ldflags = []
100 ldflags_be = []
101 ldflags_sl = []
102 ldflags_mod = []
104 test_c_args = []
106 os_deps = []
107 backend_both_deps = []
108 backend_deps = []
109 libpq_deps = []
111 pg_sysroot = ''
113 # source of data for pg_config.h etc
114 cdata = configuration_data()
118 ###############################################################
119 # Version and other metadata
120 ###############################################################
122 pg_version = meson.project_version()
124 if pg_version.endswith('devel')
125   pg_version_arr = [pg_version.split('devel')[0], '0']
126 elif pg_version.contains('beta')
127   pg_version_arr = [pg_version.split('beta')[0], '0']
128 elif pg_version.contains('rc')
129   pg_version_arr = [pg_version.split('rc')[0], '0']
130 else
131   pg_version_arr = pg_version.split('.')
132 endif
134 pg_version_major = pg_version_arr[0].to_int()
135 pg_version_minor = pg_version_arr[1].to_int()
136 pg_version_num = (pg_version_major * 10000) + pg_version_minor
138 pg_url = 'https://www.postgresql.org/'
140 cdata.set_quoted('PACKAGE_NAME', 'PostgreSQL')
141 cdata.set_quoted('PACKAGE_BUGREPORT', 'pgsql-bugs@lists.postgresql.org')
142 cdata.set_quoted('PACKAGE_URL', pg_url)
143 cdata.set_quoted('PACKAGE_VERSION', pg_version)
144 cdata.set_quoted('PACKAGE_STRING', 'PostgreSQL @0@'.format(pg_version))
145 cdata.set_quoted('PACKAGE_TARNAME', 'postgresql')
147 pg_version += get_option('extra_version')
148 cdata.set_quoted('PG_VERSION', pg_version)
149 cdata.set_quoted('PG_MAJORVERSION', pg_version_major.to_string())
150 cdata.set('PG_MAJORVERSION_NUM', pg_version_major)
151 cdata.set('PG_MINORVERSION_NUM', pg_version_minor)
152 cdata.set('PG_VERSION_NUM', pg_version_num)
153 # PG_VERSION_STR is built later, it depends on compiler test results
154 cdata.set_quoted('CONFIGURE_ARGS', '')
158 ###############################################################
159 # Basic platform specific configuration
160 ###############################################################
162 exesuffix = '' # overridden below where necessary
163 dlsuffix = '.so' # overridden below where necessary
164 library_path_var = 'LD_LIBRARY_PATH'
166 # Format of file to control exports from libraries, and how to pass them to
167 # the compiler. For export_fmt @0@ is the path to the file export file.
168 export_file_format = 'gnu'
169 export_file_suffix = 'list'
170 export_fmt = '-Wl,--version-script=@0@'
172 # Flags to add when linking a postgres extension, @0@ is path to
173 # the relevant object on the platform.
174 mod_link_args_fmt = []
176 memset_loop_limit = 1024
178 # Choice of shared memory and semaphore implementation
179 shmem_kind = 'sysv'
180 sema_kind = 'sysv'
182 # We implement support for some operating systems by pretending they're
183 # another. Map here, before determining system properties below
184 if host_system == 'dragonfly'
185   # apparently the most similar
186   host_system = 'netbsd'
187 endif
189 # meson's system names don't quite map to our "traditional" names. In some
190 # places we need the "traditional" name, e.g., for mapping
191 # src/include/port/$os.h to src/include/pg_config_os.h. Define portname for
192 # that purpose.
193 portname = host_system
195 if host_system == 'aix'
196   library_path_var = 'LIBPATH'
198   export_file_format = 'aix'
199   export_fmt = '-Wl,-bE:@0@'
200   mod_link_args_fmt = ['-Wl,-bI:@0@']
201   mod_link_with_dir = 'libdir'
202   mod_link_with_name = '@0@.imp'
204   # M:SRE sets a flag indicating that an object is a shared library. Seems to
205   # work in some circumstances without, but required in others.
206   ldflags_sl += '-Wl,-bM:SRE'
207   ldflags_be += '-Wl,-brtllib'
209   # Native memset() is faster, tested on:
210   # - AIX 5.1 and 5.2, XLC 6.0 (IBM's cc)
211   # - AIX 5.3 ML3, gcc 4.0.1
212   memset_loop_limit = 0
214 elif host_system == 'cygwin'
215   sema_kind = 'unnamed_posix'
216   cppflags += '-D_GNU_SOURCE'
217   dlsuffix = '.dll'
218   mod_link_args_fmt = ['@0@']
219   mod_link_with_name = 'lib@0@.exe.a'
220   mod_link_with_dir = 'libdir'
222 elif host_system == 'darwin'
223   dlsuffix = '.dylib'
224   library_path_var = 'DYLD_LIBRARY_PATH'
226   export_file_format = 'darwin'
227   export_fmt = '-Wl,-exported_symbols_list,@0@'
229   mod_link_args_fmt = ['-bundle_loader', '@0@']
230   mod_link_with_dir = 'bindir'
231   mod_link_with_name = '@0@'
233   sysroot_args = [files('src/tools/darwin_sysroot'), get_option('darwin_sysroot')]
234   pg_sysroot = run_command(sysroot_args, check:true).stdout().strip()
235   message('darwin sysroot: @0@'.format(pg_sysroot))
236   if pg_sysroot != ''
237     cflags += ['-isysroot', pg_sysroot]
238     ldflags += ['-isysroot', pg_sysroot]
239   endif
241   # meson defaults to -Wl,-undefined,dynamic_lookup for modules, which we
242   # don't want because a) it's different from what we do for autoconf, b) it
243   # causes warnings in macOS Ventura. But using -Wl,-undefined,error causes a
244   # warning starting in Sonoma. So only add -Wl,-undefined,error if it does
245   # not cause a warning.
246   if cc.has_multi_link_arguments('-Wl,-undefined,error', '-Werror')
247     ldflags_mod += '-Wl,-undefined,error'
248   endif
250   # Starting in Sonoma, the linker warns about the same library being
251   # linked twice.  Which can easily happen when multiple dependencies
252   # depend on the same library. Quiesce the ill considered warning.
253   ldflags += cc.get_supported_link_arguments('-Wl,-no_warn_duplicate_libraries')
255 elif host_system == 'freebsd'
256   sema_kind = 'unnamed_posix'
258 elif host_system == 'linux'
259   sema_kind = 'unnamed_posix'
260   cppflags += '-D_GNU_SOURCE'
262 elif host_system == 'netbsd'
263   # We must resolve all dynamic linking in the core server at program start.
264   # Otherwise the postmaster can self-deadlock due to signals interrupting
265   # resolution of calls, since NetBSD's linker takes a lock while doing that
266   # and some postmaster signal handlers do things that will also acquire that
267   # lock.  As long as we need "-z now", might as well specify "-z relro" too.
268   # While there's not a hard reason to adopt these settings for our other
269   # executables, there's also little reason not to, so just add them to
270   # LDFLAGS.
271   ldflags += ['-Wl,-z,now', '-Wl,-z,relro']
273 elif host_system == 'openbsd'
274   # you're ok
276 elif host_system == 'sunos'
277   portname = 'solaris'
278   export_fmt = '-Wl,-M@0@'
279   cppflags += '-D_POSIX_PTHREAD_SEMANTICS'
281 elif host_system == 'windows'
282   portname = 'win32'
283   exesuffix = '.exe'
284   dlsuffix = '.dll'
285   library_path_var = ''
287   export_file_format = 'win'
288   export_file_suffix = 'def'
289   if cc.get_id() == 'msvc'
290     export_fmt = '/DEF:@0@'
291     mod_link_with_name = '@0@.exe.lib'
292   else
293     export_fmt = '@0@'
294     mod_link_with_name = 'lib@0@.exe.a'
295   endif
296   mod_link_args_fmt = ['@0@']
297   mod_link_with_dir = 'libdir'
299   shmem_kind = 'win32'
300   sema_kind = 'win32'
302   cdata.set('WIN32_STACK_RLIMIT', 4194304)
303   if cc.get_id() == 'msvc'
304     ldflags += '/INCREMENTAL:NO'
305     ldflags += '/STACK:@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))
306     # ldflags += '/nxcompat' # generated by msbuild, should have it for ninja?
307   else
308     ldflags += '-Wl,--stack,@0@'.format(cdata.get('WIN32_STACK_RLIMIT'))
309     # Need to allow multiple definitions, we e.g. want to override getopt.
310     ldflags += '-Wl,--allow-multiple-definition'
311     # Ensure we get MSVC-like linking behavior.
312     ldflags += '-Wl,--disable-auto-import'
313   endif
315   os_deps += cc.find_library('ws2_32', required: true)
316   secur32_dep = cc.find_library('secur32', required: true)
317   backend_deps += secur32_dep
318   libpq_deps += secur32_dep
320   postgres_inc_d += 'src/include/port/win32'
321   if cc.get_id() == 'msvc'
322     postgres_inc_d += 'src/include/port/win32_msvc'
323   endif
325   windows = import('windows')
327 else
328   # XXX: Should we add an option to override the host_system as an escape
329   # hatch?
330   error('unknown host system: @0@'.format(host_system))
331 endif
335 ###############################################################
336 # Program paths
337 ###############################################################
339 # External programs
340 perl = find_program(get_option('PERL'), required: true, native: true)
341 python = find_program(get_option('PYTHON'), required: true, native: true)
342 flex = find_program(get_option('FLEX'), native: true, version: '>= 2.5.35')
343 bison = find_program(get_option('BISON'), native: true, version: '>= 2.3')
344 sed = find_program(get_option('SED'), 'sed', native: true)
345 prove = find_program(get_option('PROVE'), native: true, required: false)
346 tar = find_program(get_option('TAR'), native: true)
347 gzip = find_program(get_option('GZIP'), native: true)
348 program_lz4 = find_program(get_option('LZ4'), native: true, required: false)
349 openssl = find_program(get_option('OPENSSL'), native: true, required: false)
350 program_zstd = find_program(get_option('ZSTD'), native: true, required: false)
351 dtrace = find_program(get_option('DTRACE'), native: true, required: get_option('dtrace'))
352 missing = find_program('config/missing', native: true)
353 cp = find_program('cp', required: false, native: true)
354 xmllint_bin = find_program(get_option('XMLLINT'), native: true, required: false)
355 xsltproc_bin = find_program(get_option('XSLTPROC'), native: true, required: false)
357 bison_flags = []
358 if bison.found()
359   bison_version_c = run_command(bison, '--version', check: true)
360   # bison version string helpfully is something like
361   # >>bison (GNU bison) 3.8.1<<
362   bison_version = bison_version_c.stdout().split(' ')[3].split('\n')[0]
363   if bison_version.version_compare('>=3.0')
364     bison_flags += ['-Wno-deprecated']
365   endif
366 endif
367 bison_cmd = [bison, bison_flags, '-o', '@OUTPUT0@', '-d', '@INPUT@']
368 bison_kw = {
369   'output': ['@BASENAME@.c', '@BASENAME@.h'],
370   'command': bison_cmd,
373 flex_flags = []
374 flex_wrapper = files('src/tools/pgflex')
375 flex_cmd = [python, flex_wrapper,
376   '--builddir', '@BUILD_ROOT@',
377   '--srcdir', '@SOURCE_ROOT@',
378   '--privatedir', '@PRIVATE_DIR@',
379   '--flex', flex, '--perl', perl,
380   '-i', '@INPUT@', '-o', '@OUTPUT0@',
383 wget = find_program('wget', required: false, native: true)
384 wget_flags = ['-O', '@OUTPUT0@', '--no-use-server-timestamps']
386 install_files = files('src/tools/install_files')
390 ###############################################################
391 # Path to meson (for tests etc)
392 ###############################################################
394 # NB: this should really be part of meson, see
395 # https://github.com/mesonbuild/meson/issues/8511
396 meson_binpath_r = run_command(python, 'src/tools/find_meson', check: true)
398 if meson_binpath_r.stdout() == ''
399   error('huh, could not run find_meson.\nerrcode: @0@\nstdout: @1@\nstderr: @2@'.format(
400     meson_binpath_r.returncode(),
401     meson_binpath_r.stdout(),
402     meson_binpath_r.stderr()))
403 endif
405 meson_binpath_s = meson_binpath_r.stdout().split('\n')
406 meson_binpath_len = meson_binpath_s.length()
408 if meson_binpath_len < 1
409   error('unexpected introspect line @0@'.format(meson_binpath_r.stdout()))
410 endif
412 i = 0
413 meson_impl = ''
414 meson_binpath = ''
415 meson_args = []
416 foreach e : meson_binpath_s
417   if i == 0
418     meson_impl = e
419   elif i == 1
420     meson_binpath = e
421   else
422     meson_args += e
423   endif
424   i += 1
425 endforeach
427 if meson_impl not in ['muon', 'meson']
428   error('unknown meson implementation "@0@"'.format(meson_impl))
429 endif
431 meson_bin = find_program(meson_binpath, native: true)
435 ###############################################################
436 # Option Handling
437 ###############################################################
439 cdata.set('USE_ASSERT_CHECKING', get_option('cassert') ? 1 : false)
441 blocksize = get_option('blocksize').to_int() * 1024
443 if get_option('segsize_blocks') != 0
444   if get_option('segsize') != 1
445     warning('both segsize and segsize_blocks specified, segsize_blocks wins')
446   endif
448   segsize = get_option('segsize_blocks')
449 else
450   segsize = (get_option('segsize') * 1024 * 1024 * 1024) / blocksize
451 endif
453 cdata.set('BLCKSZ', blocksize, description:
454 '''Size of a disk block --- this also limits the size of a tuple. You can set
455    it bigger if you need bigger tuples (although TOAST should reduce the need
456    to have large tuples, since fields can be spread across multiple tuples).
457    BLCKSZ must be a power of 2. The maximum possible value of BLCKSZ is
458    currently 2^15 (32768). This is determined by the 15-bit widths of the
459    lp_off and lp_len fields in ItemIdData (see include/storage/itemid.h).
460    Changing BLCKSZ requires an initdb.''')
462 cdata.set('XLOG_BLCKSZ', get_option('wal_blocksize').to_int() * 1024)
463 cdata.set('RELSEG_SIZE', segsize)
464 cdata.set('DEF_PGPORT', get_option('pgport'))
465 cdata.set_quoted('DEF_PGPORT_STR', get_option('pgport').to_string())
466 cdata.set_quoted('PG_KRB_SRVNAM', get_option('krb_srvnam'))
467 if get_option('system_tzdata') != ''
468   cdata.set_quoted('SYSTEMTZDIR', get_option('system_tzdata'))
469 endif
473 ###############################################################
474 # Directories
475 ###############################################################
477 # These are set by the equivalent --xxxdir configure options.  We
478 # append "postgresql" to some of them, if the string does not already
479 # contain "pgsql" or "postgres", in order to avoid directory clutter.
481 pkg = 'postgresql'
483 dir_prefix = get_option('prefix')
485 dir_prefix_contains_pg = (dir_prefix.contains('pgsql') or dir_prefix.contains('postgres'))
487 dir_bin = get_option('bindir')
489 dir_data = get_option('datadir')
490 if not (dir_prefix_contains_pg or dir_data.contains('pgsql') or dir_data.contains('postgres'))
491   dir_data = dir_data / pkg
492 endif
494 dir_sysconf = get_option('sysconfdir')
495 if not (dir_prefix_contains_pg or dir_sysconf.contains('pgsql') or dir_sysconf.contains('postgres'))
496   dir_sysconf = dir_sysconf / pkg
497 endif
499 dir_lib = get_option('libdir')
501 dir_lib_pkg = dir_lib
502 if not (dir_prefix_contains_pg or dir_lib_pkg.contains('pgsql') or dir_lib_pkg.contains('postgres'))
503   dir_lib_pkg = dir_lib_pkg / pkg
504 endif
506 dir_pgxs = dir_lib_pkg / 'pgxs'
508 dir_include = get_option('includedir')
510 dir_include_pkg = dir_include
511 dir_include_pkg_rel = ''
512 if not (dir_prefix_contains_pg or dir_include_pkg.contains('pgsql') or dir_include_pkg.contains('postgres'))
513   dir_include_pkg = dir_include_pkg / pkg
514   dir_include_pkg_rel = pkg
515 endif
517 dir_man = get_option('mandir')
519 # FIXME: These used to be separately configurable - worth adding?
520 dir_doc = get_option('datadir') / 'doc' / 'postgresql'
521 dir_doc_html = dir_doc / 'html'
523 dir_locale = get_option('localedir')
526 # Derived values
527 dir_bitcode = dir_lib_pkg / 'bitcode'
528 dir_include_internal = dir_include_pkg / 'internal'
529 dir_include_server = dir_include_pkg / 'server'
530 dir_include_extension = dir_include_server / 'extension'
531 dir_data_extension = dir_data / 'extension'
535 ###############################################################
536 # Search paths, preparation for compiler tests
538 # NB: Arguments added later are not automatically used for subsequent
539 # configuration-time checks (so they are more isolated). If they should be
540 # used, they need to be added to test_c_args as well.
541 ###############################################################
543 postgres_inc = [include_directories(postgres_inc_d)]
544 test_lib_d = postgres_lib_d
545 test_c_args = cppflags + cflags
549 ###############################################################
550 # Library: bsd-auth
551 ###############################################################
553 bsd_authopt = get_option('bsd_auth')
554 bsd_auth = not_found_dep
555 if cc.check_header('bsd_auth.h', required: bsd_authopt,
556     args: test_c_args, include_directories: postgres_inc)
557   cdata.set('USE_BSD_AUTH', 1)
558   bsd_auth = declare_dependency()
559 endif
563 ###############################################################
564 # Library: bonjour
566 # For now don't search for DNSServiceRegister in a library - only Apple's
567 # Bonjour implementation, which is always linked, works.
568 ###############################################################
570 bonjouropt = get_option('bonjour')
571 bonjour = not_found_dep
572 if cc.check_header('dns_sd.h', required: bonjouropt,
573     args: test_c_args, include_directories: postgres_inc) and \
574    cc.has_function('DNSServiceRegister',
575     args: test_c_args, include_directories: postgres_inc)
576   cdata.set('USE_BONJOUR', 1)
577   bonjour = declare_dependency()
578 endif
582 ###############################################################
583 # Option: docs in HTML and man page format
584 ###############################################################
586 docs_opt = get_option('docs')
587 docs_dep = not_found_dep
588 if not docs_opt.disabled()
589   if xmllint_bin.found() and xsltproc_bin.found()
590     docs_dep = declare_dependency()
591   elif docs_opt.enabled()
592     error('missing required tools for docs in HTML / man page format')
593   endif
594 endif
598 ###############################################################
599 # Option: docs in PDF format
600 ###############################################################
602 docs_pdf_opt = get_option('docs_pdf')
603 docs_pdf_dep = not_found_dep
604 if not docs_pdf_opt.disabled()
605   fop = find_program(get_option('FOP'), native: true, required: docs_pdf_opt)
606   if xmllint_bin.found() and xsltproc_bin.found() and fop.found()
607     docs_pdf_dep = declare_dependency()
608   elif docs_pdf_opt.enabled()
609     error('missing required tools for docs in PDF format')
610   endif
611 endif
615 ###############################################################
616 # Library: GSSAPI
617 ###############################################################
619 gssapiopt = get_option('gssapi')
620 krb_srvtab = ''
621 have_gssapi = false
622 if not gssapiopt.disabled()
623   gssapi = dependency('krb5-gssapi', required: false)
624   have_gssapi = gssapi.found()
626   if have_gssapi
627       gssapi_deps = [gssapi]
628   elif not have_gssapi
629     # Hardcoded lookup for gssapi. This is necessary as gssapi on windows does
630     # not install neither pkg-config nor cmake dependency information.
631     if host_system == 'windows'
632       is_64  = cc.sizeof('void *', args: test_c_args) == 8
633       if is_64
634         gssapi_search_libs = ['gssapi64', 'krb5_64', 'comerr64']
635       else
636         gssapi_search_libs = ['gssapi32', 'krb5_32', 'comerr32']
637       endif
638     else
639       gssapi_search_libs = ['gssapi_krb5']
640     endif
642     gssapi_deps = []
643     foreach libname : gssapi_search_libs
644       lib = cc.find_library(libname, dirs: test_lib_d, required: false)
645       if lib.found()
646         have_gssapi = true
647         gssapi_deps += lib
648       endif
649     endforeach
651     if have_gssapi
652       # Meson before 0.57.0 did not support using check_header() etc with
653       # declare_dependency(). Thus the tests below use the library looked up
654       # above.  Once we require a newer meson version, we can simplify.
655       gssapi = declare_dependency(dependencies: gssapi_deps)
656     endif
657   endif
659   if not have_gssapi
660   elif cc.check_header('gssapi/gssapi.h', dependencies: gssapi_deps, required: false,
661       args: test_c_args, include_directories: postgres_inc)
662     cdata.set('HAVE_GSSAPI_GSSAPI_H', 1)
663   elif cc.check_header('gssapi.h', dependencies: gssapi_deps, required: gssapiopt,
664       args: test_c_args, include_directories: postgres_inc)
665     cdata.set('HAVE_GSSAPI_H', 1)
666   else
667     have_gssapi = false
668   endif
670   if not have_gssapi
671   elif cc.check_header('gssapi/gssapi_ext.h', dependencies: gssapi_deps, required: false,
672       args: test_c_args, include_directories: postgres_inc)
673     cdata.set('HAVE_GSSAPI_GSSAPI_EXT_H', 1)
674   elif cc.check_header('gssapi_ext.h', dependencies: gssapi_deps, required: gssapiopt,
675       args: test_c_args, include_directories: postgres_inc)
676     cdata.set('HAVE_GSSAPI_EXT_H', 1)
677   else
678     have_gssapi = false
679   endif
681   if not have_gssapi
682   elif cc.has_function('gss_store_cred_into', dependencies: gssapi_deps,
683       args: test_c_args, include_directories: postgres_inc)
684     cdata.set('ENABLE_GSS', 1)
686     krb_srvtab = 'FILE:/@0@/krb5.keytab)'.format(get_option('sysconfdir'))
687     cdata.set_quoted('PG_KRB_SRVTAB', krb_srvtab)
688   elif gssapiopt.enabled()
689     error('''could not find function 'gss_store_cred_into' required for GSSAPI''')
690   else
691     have_gssapi = false
692   endif
694   if not have_gssapi and gssapiopt.enabled()
695     error('dependency lookup for gssapi failed')
696   endif
698 endif
699 if not have_gssapi
700   gssapi = not_found_dep
701 endif
705 ###############################################################
706 # Library: ldap
707 ###############################################################
709 ldapopt = get_option('ldap')
710 if ldapopt.disabled()
711   ldap = not_found_dep
712   ldap_r = not_found_dep
713 elif host_system == 'windows'
714   ldap = cc.find_library('wldap32', required: ldapopt)
715   ldap_r = ldap
716 else
717   # macos framework dependency is buggy for ldap (one can argue whether it's
718   # Apple's or meson's fault), leading to an endless recursion with ldap.h
719   # including itself. See https://github.com/mesonbuild/meson/issues/10002
720   # Luckily we only need pkg-config support, so the workaround isn't
721   # complicated.
722   ldap = dependency('ldap', method: 'pkg-config', required: false)
723   ldap_r = ldap
725   # Before 2.5 openldap didn't have a pkg-config file, and it might not be
726   # installed
727   if not ldap.found()
728     ldap = cc.find_library('ldap', required: ldapopt, dirs: test_lib_d,
729       has_headers: 'ldap.h', header_include_directories: postgres_inc)
731     # The separate ldap_r library only exists in OpenLDAP < 2.5, and if we
732     # have 2.5 or later, we shouldn't even probe for ldap_r (we might find a
733     # library from a separate OpenLDAP installation).  The most reliable
734     # way to check that is to check for a function introduced in 2.5.
735     if not ldap.found()
736       # don't have ldap, we shouldn't check for ldap_r
737     elif cc.has_function('ldap_verify_credentials',
738         dependencies: ldap, args: test_c_args)
739       ldap_r = ldap # ldap >= 2.5, no need for ldap_r
740     else
742       # Use ldap_r for FE if available, else assume ldap is thread-safe.
743       ldap_r = cc.find_library('ldap_r', required: false, dirs: test_lib_d,
744         has_headers: 'ldap.h', header_include_directories: postgres_inc)
745       if not ldap_r.found()
746         ldap_r = ldap
747       else
748         # On some platforms ldap_r fails to link without PTHREAD_LIBS.
749         ldap_r = declare_dependency(dependencies: [ldap_r, thread_dep])
750       endif
752       # PostgreSQL sometimes loads libldap_r and plain libldap into the same
753       # process.  Check for OpenLDAP versions known not to tolerate doing so;
754       # assume non-OpenLDAP implementations are safe.  The dblink test suite
755       # exercises the hazardous interaction directly.
756       compat_test_code = '''
757 #include <ldap.h>
758 #if !defined(LDAP_VENDOR_VERSION) || \
759      (defined(LDAP_API_FEATURE_X_OPENLDAP) && \
760       LDAP_VENDOR_VERSION >= 20424 && LDAP_VENDOR_VERSION <= 20431)
761 choke me
762 #endif
764       if not cc.compiles(compat_test_code,
765           name: 'LDAP implementation compatible',
766           dependencies: ldap, args: test_c_args)
767         warning('''
768 *** With OpenLDAP versions 2.4.24 through 2.4.31, inclusive, each backend
769 *** process that loads libpq (via WAL receiver, dblink, or postgres_fdw) and
770 *** also uses LDAP will crash on exit.''')
771       endif
772     endif
773   endif
775   if ldap.found() and cc.has_function('ldap_initialize',
776       dependencies: ldap, args: test_c_args)
777     cdata.set('HAVE_LDAP_INITIALIZE', 1)
778   endif
779 endif
781 if ldap.found()
782   assert(ldap_r.found())
783   cdata.set('USE_LDAP', 1)
784 else
785   assert(not ldap_r.found())
786 endif
790 ###############################################################
791 # Library: LLVM
792 ###############################################################
794 llvmopt = get_option('llvm')
795 llvm = not_found_dep
796 if add_languages('cpp', required: llvmopt, native: false)
797   llvm = dependency('llvm', version: '>=3.9', method: 'config-tool', required: llvmopt)
799   if llvm.found()
801     cdata.set('USE_LLVM', 1)
803     cpp = meson.get_compiler('cpp')
805     llvm_binpath = llvm.get_variable(configtool: 'bindir')
807     ccache = find_program('ccache', native: true, required: false)
809     # Some distros put LLVM and clang in different paths, so fallback to
810     # find via PATH, too.
811     clang = find_program(llvm_binpath / 'clang', 'clang', required: true)
812   endif
813 elif llvmopt.auto()
814   message('llvm requires a C++ compiler')
815 endif
819 ###############################################################
820 # Library: icu
821 ###############################################################
823 icuopt = get_option('icu')
824 if not icuopt.disabled()
825   icu = dependency('icu-uc', required: false)
826   if icu.found()
827     icu_i18n = dependency('icu-i18n', required: true)
828   endif
830   # Unfortunately the dependency is named differently with cmake
831   if not icu.found() # combine with above once meson 0.60.0 is required
832     icu = dependency('ICU', required: icuopt,
833                      components: ['uc'], modules: ['ICU::uc'], method: 'cmake')
834     if icu.found()
835       icu_i18n = dependency('ICU', required: true,
836                             components: ['i18n'], modules: ['ICU::i18n'])
837     endif
838   endif
840   if icu.found()
841     cdata.set('USE_ICU', 1)
842   else
843     icu_i18n = not_found_dep
844   endif
846 else
847   icu = not_found_dep
848   icu_i18n = not_found_dep
849 endif
853 ###############################################################
854 # Library: libxml
855 ###############################################################
857 libxmlopt = get_option('libxml')
858 if not libxmlopt.disabled()
859   libxml = dependency('libxml-2.0', required: false, version: '>= 2.6.23')
860   # Unfortunately the dependency is named differently with cmake
861   if not libxml.found() # combine with above once meson 0.60.0 is required
862     libxml = dependency('LibXml2', required: libxmlopt, version: '>= 2.6.23',
863       method: 'cmake')
864   endif
866   if libxml.found()
867     cdata.set('USE_LIBXML', 1)
868   endif
869 else
870   libxml = not_found_dep
871 endif
875 ###############################################################
876 # Library: libxslt
877 ###############################################################
879 libxsltopt = get_option('libxslt')
880 if not libxsltopt.disabled()
881   libxslt = dependency('libxslt', required: false)
882   # Unfortunately the dependency is named differently with cmake
883   if not libxslt.found() # combine with above once meson 0.60.0 is required
884     libxslt = dependency('LibXslt', required: libxsltopt, method: 'cmake')
885   endif
887   if libxslt.found()
888     cdata.set('USE_LIBXSLT', 1)
889   endif
890 else
891   libxslt = not_found_dep
892 endif
896 ###############################################################
897 # Library: lz4
898 ###############################################################
900 lz4opt = get_option('lz4')
901 if not lz4opt.disabled()
902   lz4 = dependency('liblz4', required: false)
903   # Unfortunately the dependency is named differently with cmake
904   if not lz4.found() # combine with above once meson 0.60.0 is required
905     lz4 = dependency('lz4', required: lz4opt,
906                      method: 'cmake', modules: ['LZ4::lz4_shared'],
907                     )
908   endif
910   if lz4.found()
911     cdata.set('USE_LZ4', 1)
912     cdata.set('HAVE_LIBLZ4', 1)
913   endif
915 else
916   lz4 = not_found_dep
917 endif
921 ###############################################################
922 # Library: Tcl (for pltcl)
924 # NB: tclConfig.sh is used in autoconf build for getting
925 # TCL_SHARED_BUILD, TCL_INCLUDE_SPEC, TCL_LIBS and TCL_LIB_SPEC
926 # variables. For now we have not seen a need to copy
927 # that behaviour to the meson build.
928 ###############################################################
930 tclopt = get_option('pltcl')
931 tcl_version = get_option('tcl_version')
932 tcl_dep = not_found_dep
933 if not tclopt.disabled()
935   # via pkg-config
936   tcl_dep = dependency(tcl_version, required: false)
938   if not tcl_dep.found()
939     tcl_dep = cc.find_library(tcl_version,
940       required: tclopt,
941       dirs: test_lib_d)
942   endif
944   if not cc.has_header('tcl.h', dependencies: tcl_dep, required: tclopt)
945     tcl_dep = not_found_dep
946   endif
947 endif
951 ###############################################################
952 # Library: pam
953 ###############################################################
955 pamopt = get_option('pam')
956 if not pamopt.disabled()
957   pam = dependency('pam', required: false)
959   if not pam.found()
960     pam = cc.find_library('pam', required: pamopt, dirs: test_lib_d)
961   endif
963   if pam.found()
964     pam_header_found = false
966     # header file <security/pam_appl.h> or <pam/pam_appl.h> is required for PAM.
967     if cc.check_header('security/pam_appl.h', dependencies: pam, required: false,
968         args: test_c_args, include_directories: postgres_inc)
969       cdata.set('HAVE_SECURITY_PAM_APPL_H', 1)
970       pam_header_found = true
971     elif cc.check_header('pam/pam_appl.h', dependencies: pam, required: pamopt,
972         args: test_c_args, include_directories: postgres_inc)
973       cdata.set('HAVE_PAM_PAM_APPL_H', 1)
974       pam_header_found = true
975     endif
977     if pam_header_found
978       cdata.set('USE_PAM', 1)
979     else
980       pam = not_found_dep
981     endif
982   endif
983 else
984   pam = not_found_dep
985 endif
989 ###############################################################
990 # Library: Perl (for plperl)
991 ###############################################################
993 perlopt = get_option('plperl')
994 perl_dep = not_found_dep
995 if not perlopt.disabled()
996   perl_may_work = true
998   # First verify that perl has the necessary dependencies installed
999   perl_mods = run_command(
1000     [perl,
1001      '-MConfig', '-MOpcode', '-MExtUtils::Embed', '-MExtUtils::ParseXS',
1002      '-e', ''],
1003     check: false)
1004   if perl_mods.returncode() != 0
1005     perl_may_work = false
1006     perl_msg = 'perl installation does not have the required modules'
1007   endif
1009   # Then inquire perl about its configuration
1010   if perl_may_work
1011     perl_conf_cmd = [perl, '-MConfig', '-e', 'print $Config{$ARGV[0]}']
1012     perlversion = run_command(perl_conf_cmd, 'api_versionstring', check: true).stdout()
1013     archlibexp = run_command(perl_conf_cmd, 'archlibexp', check: true).stdout()
1014     privlibexp = run_command(perl_conf_cmd, 'privlibexp', check: true).stdout()
1015     useshrplib = run_command(perl_conf_cmd, 'useshrplib', check: true).stdout()
1017     perl_inc_dir = '@0@/CORE'.format(archlibexp)
1019     if perlversion.version_compare('< 5.14')
1020       perl_may_work = false
1021       perl_msg = 'Perl version 5.14 or later is required, but this is @0@'.format(perlversion)
1022     elif useshrplib != 'true'
1023       perl_may_work = false
1024       perl_msg = 'need a shared perl'
1025     endif
1026   endif
1028   if perl_may_work
1029     # On most platforms, archlibexp is also where the Perl include files live ...
1030     perl_ccflags = ['-I@0@'.format(perl_inc_dir)]
1031     # ... but on newer macOS versions, we must use -iwithsysroot to look
1032     # under sysroot
1033     if not fs.is_file('@0@/perl.h'.format(perl_inc_dir)) and \
1034        fs.is_file('@0@@1@/perl.h'.format(pg_sysroot, perl_inc_dir))
1035       perl_ccflags = ['-iwithsysroot', perl_inc_dir]
1036     endif
1038     # check compiler finds header
1039     if not cc.has_header('perl.h', required: false,
1040         args: test_c_args + perl_ccflags, include_directories: postgres_inc)
1041       perl_may_work = false
1042       perl_msg = 'missing perl.h'
1043     endif
1044   endif
1046   if perl_may_work
1047     perl_ccflags_r = run_command(perl_conf_cmd, 'ccflags', check: true).stdout()
1049     # See comments for PGAC_CHECK_PERL_EMBED_CCFLAGS in perl.m4
1050     foreach flag : perl_ccflags_r.split(' ')
1051       if flag.startswith('-D') and \
1052           (not flag.startswith('-D_') or flag == '_USE_32BIT_TIME_T')
1053         perl_ccflags += flag
1054       endif
1055     endforeach
1057     if host_system == 'windows'
1058       perl_ccflags += ['-DPLPERL_HAVE_UID_GID']
1060       if cc.get_id() == 'msvc'
1061         # prevent binary mismatch between MSVC built plperl and Strawberry or
1062         # msys ucrt perl libraries
1063         perl_v = run_command(perl, '-V').stdout()
1064         if not perl_v.contains('USE_THREAD_SAFE_LOCALE')
1065           perl_ccflags += ['-DNO_THREAD_SAFE_LOCALE']
1066         endif
1067       endif
1068     endif
1070     message('CCFLAGS recommended by perl: @0@'.format(perl_ccflags_r))
1071     message('CCFLAGS for embedding perl: @0@'.format(' '.join(perl_ccflags)))
1073     # We are after Embed's ldopts, but without the subset mentioned in
1074     # Config's ccdlflags and ldflags.  (Those are the choices of those who
1075     # built the Perl installation, which are not necessarily appropriate
1076     # for building PostgreSQL.)
1077     perl_ldopts = run_command(perl, '-e', '''
1078 use ExtUtils::Embed;
1079 use Text::ParseWords;
1080 # tell perl to suppress including these in ldopts
1081 *ExtUtils::Embed::_ldflags =*ExtUtils::Embed::_ccdlflags = sub { return ""; };
1082 # adding an argument to ldopts makes it return a value instead of printing
1083 # print one of these per line so splitting will preserve spaces in file names.
1084 # shellwords eats backslashes, so we need to escape them.
1085 (my $opts = ldopts(undef)) =~ s!\\!\\\\!g;
1086 print "$_\n" foreach shellwords($opts);
1087 ''',
1088      check: true).stdout().strip().split('\n')
1090     message('LDFLAGS for embedding perl: "@0@"'.format(' '.join(perl_ldopts)))
1092     perl_dep_int = declare_dependency(
1093       compile_args: perl_ccflags,
1094       link_args: perl_ldopts,
1095       version: perlversion,
1096     )
1098     # While we're at it, check that we can link to libperl.
1099     # On most platforms, if perl.h is there then libperl.so will be too, but
1100     # at this writing Debian packages them separately.
1101     perl_link_test = '''
1102 /* see plperl.h */
1103 #ifdef _MSC_VER
1104 #define __inline__ inline
1105 #endif
1106 #include <EXTERN.h>
1107 #include <perl.h>
1108 int main(void)
1110 perl_alloc();
1111 }'''
1112     if not cc.links(perl_link_test, name: 'libperl',
1113           args: test_c_args + perl_ccflags + perl_ldopts,
1114           include_directories: postgres_inc)
1115       perl_may_work = false
1116       perl_msg = 'missing libperl'
1117     endif
1119   endif # perl_may_work
1121   if perl_may_work
1122     perl_dep = perl_dep_int
1123   else
1124     if perlopt.enabled()
1125       error('dependency plperl failed: @0@'.format(perl_msg))
1126     else
1127       message('disabling optional dependency plperl: @0@'.format(perl_msg))
1128     endif
1129   endif
1130 endif
1134 ###############################################################
1135 # Library: Python (for plpython)
1136 ###############################################################
1138 pyopt = get_option('plpython')
1139 python3_dep = not_found_dep
1140 if not pyopt.disabled()
1141   pm = import('python')
1142   python3_inst = pm.find_installation(python.path(), required: pyopt)
1143   if python3_inst.found()
1144     python3_dep = python3_inst.dependency(embed: true, required: pyopt)
1145     # Remove this check after we depend on Meson >= 1.1.0
1146     if not cc.check_header('Python.h', dependencies: python3_dep, required: pyopt, include_directories: postgres_inc)
1147       python3_dep = not_found_dep
1148     endif
1149   endif
1150 endif
1154 ###############################################################
1155 # Library: Readline
1156 ###############################################################
1158 if not get_option('readline').disabled()
1159   libedit_preferred = get_option('libedit_preferred')
1160   # Set the order of readline dependencies.
1161   # cc.find_library breaks and throws on the first dependency which
1162   # is marked as required=true and can't be found. Thus, we only mark
1163   # the last dependency to look up as required, to not throw too early.
1164   check_readline_deps = [
1165     {
1166       'name': libedit_preferred ? 'libedit' : 'readline',
1167       'required': false
1168     },
1169     {
1170       'name': libedit_preferred ? 'readline' : 'libedit',
1171       'required': get_option('readline')
1172     }
1173   ]
1175   foreach readline_dep : check_readline_deps
1176     readline = dependency(readline_dep['name'], required: false)
1177     if not readline.found()
1178       readline = cc.find_library(readline_dep['name'],
1179         required: readline_dep['required'],
1180         dirs: test_lib_d)
1181     endif
1182     if readline.found()
1183       break
1184     endif
1185   endforeach
1187   if readline.found()
1188     cdata.set('HAVE_LIBREADLINE', 1)
1190     editline_prefix = {
1191       'header_prefix': 'editline/',
1192       'flag_prefix': 'EDITLINE_',
1193     }
1194     readline_prefix = {
1195       'header_prefix': 'readline/',
1196       'flag_prefix': 'READLINE_',
1197     }
1198     default_prefix = {
1199       'header_prefix': '',
1200       'flag_prefix': '',
1201     }
1203     # Set the order of prefixes
1204     prefixes = libedit_preferred ? \
1205       [editline_prefix, default_prefix, readline_prefix] : \
1206       [readline_prefix, default_prefix, editline_prefix]
1208     at_least_one_header_found = false
1209     foreach header : ['history', 'readline']
1210       is_found = false
1211       foreach prefix : prefixes
1212         header_file = '@0@@1@.h'.format(prefix['header_prefix'], header)
1213         # Check history.h and readline.h
1214         if not is_found and cc.has_header(header_file,
1215             args: test_c_args, include_directories: postgres_inc,
1216             dependencies: [readline], required: false)
1217           if header == 'readline'
1218             readline_h = header_file
1219           endif
1220           cdata.set('HAVE_@0@@1@_H'.format(prefix['flag_prefix'], header).to_upper(), 1)
1221           is_found = true
1222           at_least_one_header_found = true
1223         endif
1224       endforeach
1225     endforeach
1227     if not at_least_one_header_found
1228       error('''readline header not found
1229 If you have @0@ already installed, see meson-logs/meson-log.txt for details on the
1230 failure. It is possible the compiler isn't looking in the proper directory.
1231 Use -Dreadline=disabled to disable readline support.'''.format(readline_dep))
1232     endif
1234     check_funcs = [
1235       'append_history',
1236       'history_truncate_file',
1237       'rl_completion_matches',
1238       'rl_filename_completion_function',
1239       'rl_reset_screen_size',
1240       'rl_variable_bind',
1241     ]
1243     foreach func : check_funcs
1244       found = cc.has_function(func, dependencies: [readline],
1245         args: test_c_args, include_directories: postgres_inc)
1246       cdata.set('HAVE_' + func.to_upper(), found ? 1 : false)
1247     endforeach
1249     check_vars = [
1250       'rl_completion_suppress_quote',
1251       'rl_filename_quote_characters',
1252       'rl_filename_quoting_function',
1253     ]
1255     foreach var : check_vars
1256       cdata.set('HAVE_' + var.to_upper(),
1257         cc.has_header_symbol(readline_h, var,
1258           args: test_c_args, include_directories: postgres_inc,
1259           prefix: '#include <stdio.h>',
1260           dependencies: [readline]) ? 1 : false)
1261     endforeach
1263     # If found via cc.find_library() ensure headers are found when using the
1264     # dependency. On meson < 0.57 one cannot do compiler checks using the
1265     # dependency returned by declare_dependency(), so we can't do this above.
1266     if readline.type_name() == 'library'
1267       readline = declare_dependency(dependencies: readline,
1268         include_directories: postgres_inc)
1269     endif
1271     # On windows with mingw readline requires auto-import to successfully
1272     # link, as the headers don't use declspec(dllimport)
1273     if host_system == 'windows' and cc.get_id() != 'msvc'
1274       readline = declare_dependency(dependencies: readline,
1275         link_args: '-Wl,--enable-auto-import')
1276     endif
1277   endif
1279   # XXX: Figure out whether to implement mingw warning equivalent
1280 else
1281   readline = not_found_dep
1282 endif
1286 ###############################################################
1287 # Library: selinux
1288 ###############################################################
1290 selinux = not_found_dep
1291 selinuxopt = get_option('selinux')
1292 if meson.version().version_compare('>=0.59')
1293   selinuxopt = selinuxopt.disable_auto_if(host_system != 'linux')
1294 endif
1295 selinux = dependency('libselinux', required: selinuxopt, version: '>= 2.1.10')
1296 cdata.set('HAVE_LIBSELINUX',
1297   selinux.found() ? 1 : false)
1301 ###############################################################
1302 # Library: systemd
1303 ###############################################################
1305 systemd = not_found_dep
1306 systemdopt = get_option('systemd')
1307 if meson.version().version_compare('>=0.59')
1308   systemdopt = systemdopt.disable_auto_if(host_system != 'linux')
1309 endif
1310 systemd = dependency('libsystemd', required: systemdopt)
1311 cdata.set('USE_SYSTEMD', systemd.found() ? 1 : false)
1315 ###############################################################
1316 # Library: SSL
1317 ###############################################################
1319 ssl = not_found_dep
1320 ssl_library = 'none'
1321 sslopt = get_option('ssl')
1323 if sslopt == 'auto' and auto_features.disabled()
1324   sslopt = 'none'
1325 endif
1327 if sslopt in ['auto', 'openssl']
1328   openssl_required = (sslopt == 'openssl')
1330   # Try to find openssl via pkg-config et al, if that doesn't work
1331   # (e.g. because it's provided as part of the OS, like on FreeBSD), look for
1332   # the library names that we know about.
1334   # via pkg-config et al
1335   ssl = dependency('openssl', required: false)
1336   # only meson >= 0.57 supports declare_dependency() in cc.has_function(), so
1337   # we pass cc.find_library() results if necessary
1338   ssl_int = []
1340   # via library + headers
1341   if not ssl.found()
1342     ssl_lib = cc.find_library('ssl',
1343       dirs: test_lib_d,
1344       header_include_directories: postgres_inc,
1345       has_headers: ['openssl/ssl.h', 'openssl/err.h'],
1346       required: openssl_required)
1347     crypto_lib = cc.find_library('crypto',
1348       dirs: test_lib_d,
1349       required: openssl_required)
1350     if ssl_lib.found() and crypto_lib.found()
1351       ssl_int = [ssl_lib, crypto_lib]
1352       ssl = declare_dependency(dependencies: ssl_int, include_directories: postgres_inc)
1353     endif
1354   elif cc.has_header('openssl/ssl.h', args: test_c_args, dependencies: ssl, required: openssl_required) and \
1355        cc.has_header('openssl/err.h', args: test_c_args, dependencies: ssl, required: openssl_required)
1356     ssl_int = [ssl]
1357   else
1358     ssl = not_found_dep
1359   endif
1361   if ssl.found()
1362     check_funcs = [
1363       ['CRYPTO_new_ex_data', {'required': true}],
1364       ['SSL_new', {'required': true}],
1366       # Functions introduced in OpenSSL 1.0.2.
1367       ['X509_get_signature_nid'],
1368       ['SSL_CTX_set_cert_cb'], # not in LibreSSL
1370       # Functions introduced in OpenSSL 1.1.0. We used to check for
1371       # OPENSSL_VERSION_NUMBER, but that didn't work with 1.1.0, because LibreSSL
1372       # defines OPENSSL_VERSION_NUMBER to claim version 2.0.0, even though it
1373       # doesn't have these OpenSSL 1.1.0 functions. So check for individual
1374       # functions.
1375       ['OPENSSL_init_ssl'],
1376       ['BIO_meth_new'],
1377       ['ASN1_STRING_get0_data'],
1378       ['HMAC_CTX_new'],
1379       ['HMAC_CTX_free'],
1381       # OpenSSL versions before 1.1.0 required setting callback functions, for
1382       # thread-safety. In 1.1.0, it's no longer required, and CRYPTO_lock()
1383       # function was removed.
1384       ['CRYPTO_lock'],
1386       # Function introduced in OpenSSL 1.1.1
1387       ['X509_get_signature_info'],
1388       ['SSL_CTX_set_num_tickets'],
1389     ]
1391     are_openssl_funcs_complete = true
1392     foreach c : check_funcs
1393       func = c.get(0)
1394       val = cc.has_function(func, args: test_c_args, dependencies: ssl_int)
1395       required = c.get(1, {}).get('required', false)
1396       if required and not val
1397         are_openssl_funcs_complete = false
1398         if openssl_required
1399           error('openssl function @0@ is required'.format(func))
1400         endif
1401         break
1402       elif not required
1403         cdata.set('HAVE_' + func.to_upper(), val ? 1 : false)
1404       endif
1405     endforeach
1407     if are_openssl_funcs_complete
1408       cdata.set('USE_OPENSSL', 1,
1409                 description: 'Define to 1 to build with OpenSSL support. (-Dssl=openssl)')
1410       cdata.set('OPENSSL_API_COMPAT', '0x10001000L',
1411                 description: 'Define to the OpenSSL API version in use. This avoids deprecation warnings from newer OpenSSL versions.')
1412       ssl_library = 'openssl'
1413     else
1414       ssl = not_found_dep
1415     endif
1416   endif
1417 endif
1419 if sslopt == 'auto' and auto_features.enabled() and not ssl.found()
1420   error('no SSL library found')
1421 endif
1425 ###############################################################
1426 # Library: uuid
1427 ###############################################################
1429 uuidopt = get_option('uuid')
1430 if uuidopt != 'none'
1431   uuidname = uuidopt.to_upper()
1432   if uuidopt == 'e2fs'
1433     uuid = dependency('uuid', required: true)
1434     uuidfunc = 'uuid_generate'
1435     uuidheader = 'uuid/uuid.h'
1436   elif uuidopt == 'bsd'
1437     # libc should have uuid function
1438     uuid = declare_dependency()
1439     uuidfunc = 'uuid_to_string'
1440     uuidheader = 'uuid.h'
1441   elif uuidopt == 'ossp'
1442     # In upstream, the package and library is called just 'uuid', but many
1443     # distros change it to 'ossp-uuid'.
1444     uuid = dependency('ossp-uuid', 'uuid', required: false)
1445     uuidfunc = 'uuid_export'
1446     uuidheader = 'uuid.h'
1448     # Hardcoded lookup for ossp-uuid. This is necessary as ossp-uuid on
1449     # windows installs neither a pkg-config nor a cmake dependency
1450     # information. Nor is there another supported uuid implementation
1451     # available on windows.
1452     if not uuid.found()
1453       uuid = cc.find_library('ossp-uuid',
1454         required: false, dirs: test_lib_d,
1455         has_headers: uuidheader, header_include_directories: postgres_inc)
1456     endif
1457     if not uuid.found()
1458       uuid = cc.find_library('uuid',
1459         required: true, dirs: test_lib_d,
1460         has_headers: uuidheader, header_include_directories: postgres_inc)
1461     endif
1462   else
1463     error('unknown uuid build option value: @0@'.format(uuidopt))
1464   endif
1466   if not cc.has_header_symbol(uuidheader, uuidfunc, args: test_c_args, dependencies: uuid)
1467     error('uuid library @0@ missing required function @1@'.format(uuidopt, uuidfunc))
1468   endif
1469   cdata.set('HAVE_@0@'.format(uuidheader.underscorify().to_upper()), 1)
1471   cdata.set('HAVE_UUID_@0@'.format(uuidname), 1,
1472            description: 'Define to 1 if you have @0@ UUID support.'.format(uuidname))
1473 else
1474   uuid = not_found_dep
1475 endif
1479 ###############################################################
1480 # Library: zlib
1481 ###############################################################
1483 zlibopt = get_option('zlib')
1484 zlib = not_found_dep
1485 if not zlibopt.disabled()
1486   zlib_t = dependency('zlib', required: zlibopt)
1488   if zlib_t.type_name() == 'internal'
1489     # if fallback was used, we don't need to test if headers are present (they
1490     # aren't built yet, so we can't test)
1491     zlib = zlib_t
1492   elif not zlib_t.found()
1493     warning('did not find zlib')
1494   elif not cc.has_header('zlib.h',
1495       args: test_c_args, include_directories: postgres_inc,
1496       dependencies: [zlib_t], required: zlibopt)
1497     warning('zlib header not found')
1498   elif not cc.has_type('z_streamp',
1499       dependencies: [zlib_t], prefix: '#include <zlib.h>',
1500       args: test_c_args, include_directories: postgres_inc)
1501     if zlibopt.enabled()
1502       error('zlib version is too old')
1503     else
1504       warning('zlib version is too old')
1505     endif
1506   else
1507     zlib = zlib_t
1508   endif
1510   if zlib.found()
1511     cdata.set('HAVE_LIBZ', 1)
1512   endif
1513 endif
1517 ###############################################################
1518 # Library: tap test dependencies
1519 ###############################################################
1521 # Check whether tap tests are enabled or not
1522 tap_tests_enabled = false
1523 tapopt = get_option('tap_tests')
1524 if not tapopt.disabled()
1525   # Checking for perl modules for tap tests
1526   perl_ipc_run_check = run_command(perl, 'config/check_modules.pl', check: false)
1527   if perl_ipc_run_check.returncode() != 0
1528     message(perl_ipc_run_check.stderr().strip())
1529     if tapopt.enabled()
1530       error('Additional Perl modules are required to run TAP tests.')
1531     else
1532       warning('Additional Perl modules are required to run TAP tests.')
1533     endif
1534   else
1535     tap_tests_enabled = true
1536   endif
1537 endif
1541 ###############################################################
1542 # Library: zstd
1543 ###############################################################
1545 zstdopt = get_option('zstd')
1546 if not zstdopt.disabled()
1547   zstd = dependency('libzstd', required: false, version: '>=1.4.0')
1548   # Unfortunately the dependency is named differently with cmake
1549   if not zstd.found() # combine with above once meson 0.60.0 is required
1550     zstd = dependency('zstd', required: zstdopt, version: '>=1.4.0',
1551                       method: 'cmake', modules: ['zstd::libzstd_shared'])
1552   endif
1554   if zstd.found()
1555     cdata.set('USE_ZSTD', 1)
1556     cdata.set('HAVE_LIBZSTD', 1)
1557   endif
1559 else
1560   zstd = not_found_dep
1561 endif
1565 ###############################################################
1566 # Compiler tests
1567 ###############################################################
1569 # Do we need -std=c99 to compile C99 code? We don't want to add -std=c99
1570 # unnecessarily, because we optionally rely on newer features.
1571 c99_test = '''
1572 #include <stdbool.h>
1573 #include <complex.h>
1574 #include <tgmath.h>
1575 #include <inttypes.h>
1577 struct named_init_test {
1578   int a;
1579   int b;
1582 extern void structfunc(struct named_init_test);
1584 int main(int argc, char **argv)
1586   struct named_init_test nit = {
1587     .a = 3,
1588     .b = 5,
1589   };
1591   for (int loop_var = 0; loop_var < 3; loop_var++)
1592   {
1593     nit.a += nit.b;
1594   }
1596   structfunc((struct named_init_test){1, 0});
1598   return nit.a != 0;
1602 if not cc.compiles(c99_test, name: 'c99', args: test_c_args)
1603   if cc.compiles(c99_test, name: 'c99 with -std=c99',
1604         args: test_c_args + ['-std=c99'])
1605     test_c_args += '-std=c99'
1606     cflags += '-std=c99'
1607   else
1608     error('C compiler does not support C99')
1609   endif
1610 endif
1612 sizeof_long = cc.sizeof('long', args: test_c_args)
1613 cdata.set('SIZEOF_LONG', sizeof_long)
1614 if sizeof_long == 8
1615   cdata.set('HAVE_LONG_INT_64', 1)
1616   cdata.set('PG_INT64_TYPE', 'long int')
1617   cdata.set_quoted('INT64_MODIFIER', 'l')
1618 elif sizeof_long == 4 and cc.sizeof('long long', args: test_c_args) == 8
1619   cdata.set('HAVE_LONG_LONG_INT_64', 1)
1620   cdata.set('PG_INT64_TYPE', 'long long int')
1621   cdata.set_quoted('INT64_MODIFIER', 'll')
1622 else
1623   error('do not know how to get a 64bit int')
1624 endif
1626 if host_machine.endian() == 'big'
1627   cdata.set('WORDS_BIGENDIAN', 1)
1628 endif
1630 alignof_types = ['short', 'int', 'long', 'double']
1631 maxalign = 0
1632 foreach t : alignof_types
1633   align = cc.alignment(t, args: test_c_args)
1634   if maxalign < align
1635     maxalign = align
1636   endif
1637   cdata.set('ALIGNOF_@0@'.format(t.to_upper()), align)
1638 endforeach
1639 cdata.set('MAXIMUM_ALIGNOF', maxalign)
1641 cdata.set('SIZEOF_VOID_P', cc.sizeof('void *', args: test_c_args))
1642 cdata.set('SIZEOF_SIZE_T', cc.sizeof('size_t', args: test_c_args))
1645 # Check if __int128 is a working 128 bit integer type, and if so
1646 # define PG_INT128_TYPE to that typename.
1648 # This currently only detects a GCC/clang extension, but support for other
1649 # environments may be added in the future.
1651 # For the moment we only test for support for 128bit math; support for
1652 # 128bit literals and snprintf is not required.
1653 if cc.links('''
1654   /*
1655    * We don't actually run this test, just link it to verify that any support
1656    * functions needed for __int128 are present.
1657    *
1658    * These are globals to discourage the compiler from folding all the
1659    * arithmetic tests down to compile-time constants.  We do not have
1660    * convenient support for 128bit literals at this point...
1661    */
1662   __int128 a = 48828125;
1663   __int128 b = 97656250;
1665   int main(void)
1666   {
1667       __int128 c,d;
1668       a = (a << 12) + 1; /* 200000000001 */
1669       b = (b << 12) + 5; /* 400000000005 */
1670       /* try the most relevant arithmetic ops */
1671       c = a * b;
1672       d = (c + b) / b;
1673       /* must use the results, else compiler may optimize arithmetic away */
1674       return d != a+1;
1675   }''',
1676   name: '__int128',
1677   args: test_c_args)
1679   buggy_int128 = false
1681   # Use of non-default alignment with __int128 tickles bugs in some compilers.
1682   # If not cross-compiling, we can test for bugs and disable use of __int128
1683   # with buggy compilers.  If cross-compiling, hope for the best.
1684   # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83925
1685   if not meson.is_cross_build()
1686     r = cc.run('''
1687     /* This must match the corresponding code in c.h: */
1688     #if defined(__GNUC__) || defined(__SUNPRO_C) || defined(__IBMC__)
1689     #define pg_attribute_aligned(a) __attribute__((aligned(a)))
1690     #elif defined(_MSC_VER)
1691     #define pg_attribute_aligned(a) __declspec(align(a))
1692     #endif
1693     typedef __int128 int128a
1694     #if defined(pg_attribute_aligned)
1695     pg_attribute_aligned(8)
1696     #endif
1697     ;
1699     int128a holder;
1700     void pass_by_val(void *buffer, int128a par) { holder = par; }
1702     int main(void)
1703     {
1704         long int i64 = 97656225L << 12;
1705         int128a q;
1706         pass_by_val(main, (int128a) i64);
1707         q = (int128a) i64;
1708         return q != holder;
1709     }''',
1710     name: '__int128 alignment bug',
1711     args: test_c_args)
1712     assert(r.compiled())
1713     if r.returncode() != 0
1714       buggy_int128 = true
1715       message('__int128 support present but buggy and thus disabled')
1716     endif
1717   endif
1719   if not buggy_int128
1720     cdata.set('PG_INT128_TYPE', '__int128')
1721     cdata.set('ALIGNOF_PG_INT128_TYPE', cc.alignment('__int128', args: test_c_args))
1722   endif
1723 endif
1726 # Check if the C compiler knows computed gotos (gcc extension, also
1727 # available in at least clang).  If so, define HAVE_COMPUTED_GOTO.
1729 # Checking whether computed gotos are supported syntax-wise ought to
1730 # be enough, as the syntax is otherwise illegal.
1731 if cc.compiles('''
1732     static inline int foo(void)
1733     {
1734       void *labeladdrs[] = {&&my_label};
1735       goto *labeladdrs[0];
1736       my_label:
1737       return 1;
1738     }''',
1739     args: test_c_args)
1740   cdata.set('HAVE_COMPUTED_GOTO', 1)
1741 endif
1744 # Check if the C compiler understands _Static_assert(),
1745 # and define HAVE__STATIC_ASSERT if so.
1747 # We actually check the syntax ({ _Static_assert(...) }), because we need
1748 # gcc-style compound expressions to be able to wrap the thing into macros.
1749 if cc.compiles('''
1750     int main(int arg, char **argv)
1751     {
1752         ({ _Static_assert(1, "foo"); });
1753     }
1754     ''',
1755     args: test_c_args)
1756   cdata.set('HAVE__STATIC_ASSERT', 1)
1757 endif
1760 # We use <stdbool.h> if we have it and it declares type bool as having
1761 # size 1.  Otherwise, c.h will fall back to declaring bool as unsigned char.
1762 if cc.has_type('_Bool', args: test_c_args) \
1763     and cc.has_type('bool', prefix: '#include <stdbool.h>', args: test_c_args) \
1764     and cc.sizeof('bool', prefix: '#include <stdbool.h>', args: test_c_args) == 1
1765   cdata.set('HAVE__BOOL', 1)
1766   cdata.set('PG_USE_STDBOOL', 1)
1767 endif
1770 # Need to check a call with %m because netbsd supports gnu_printf but emits a
1771 # warning for each use of %m.
1772 printf_attributes = ['gnu_printf', '__syslog__', 'printf']
1773 testsrc = '''
1774 extern void emit_log(int ignore, const char *fmt,...) __attribute__((format(@0@, 2,3)));
1775 static void call_log(void)
1777     emit_log(0, "error: %s: %m", "foo");
1780 attrib_error_args = cc.get_supported_arguments('-Werror=format', '-Werror=ignored-attributes')
1781 foreach a : printf_attributes
1782   if cc.compiles(testsrc.format(a),
1783       args: test_c_args + attrib_error_args, name: 'format ' + a)
1784     cdata.set('PG_PRINTF_ATTRIBUTE', a)
1785     break
1786   endif
1787 endforeach
1790 if cc.has_function_attribute('visibility:default') and \
1791     cc.has_function_attribute('visibility:hidden')
1792   cdata.set('HAVE_VISIBILITY_ATTRIBUTE', 1)
1794   # Only newer versions of meson know not to apply gnu_symbol_visibility =
1795   # inlineshidden to C code as well... And either way, we want to put these
1796   # flags into exported files (pgxs, .pc files).
1797   cflags_mod += '-fvisibility=hidden'
1798   cxxflags_mod += ['-fvisibility=hidden', '-fvisibility-inlines-hidden']
1799   ldflags_mod += '-fvisibility=hidden'
1800 endif
1803 # Check if various builtins exist. Some builtins are tested separately,
1804 # because we want to test something more complicated than the generic case.
1805 builtins = [
1806   'bswap16',
1807   'bswap32',
1808   'bswap64',
1809   'clz',
1810   'ctz',
1811   'constant_p',
1812   'frame_address',
1813   'popcount',
1814   'unreachable',
1817 foreach builtin : builtins
1818   fname = '__builtin_@0@'.format(builtin)
1819   if cc.has_function(fname, args: test_c_args)
1820     cdata.set('HAVE@0@'.format(fname.to_upper()), 1)
1821   endif
1822 endforeach
1825 # Check if the C compiler understands __builtin_types_compatible_p,
1826 # and define HAVE__BUILTIN_TYPES_COMPATIBLE_P if so.
1828 # We check usage with __typeof__, though it's unlikely any compiler would
1829 # have the former and not the latter.
1830 if cc.compiles('''
1831     static int x;
1832     static int y[__builtin_types_compatible_p(__typeof__(x), int)];
1833     ''',
1834     name: '__builtin_types_compatible_p',
1835     args: test_c_args)
1836   cdata.set('HAVE__BUILTIN_TYPES_COMPATIBLE_P', 1)
1837 endif
1840 # Check if the C compiler understands __builtin_$op_overflow(),
1841 # and define HAVE__BUILTIN_OP_OVERFLOW if so.
1843 # Check for the most complicated case, 64 bit multiplication, as a
1844 # proxy for all of the operations.  To detect the case where the compiler
1845 # knows the function but library support is missing, we must link not just
1846 # compile, and store the results in global variables so the compiler doesn't
1847 # optimize away the call.
1848 if cc.links('''
1849     INT64 a = 1;
1850     INT64 b = 1;
1851     INT64 result;
1853     int main(void)
1854     {
1855         return __builtin_mul_overflow(a, b, &result);
1856     }''',
1857     name: '__builtin_mul_overflow',
1858     args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))],
1859     )
1860   cdata.set('HAVE__BUILTIN_OP_OVERFLOW', 1)
1861 endif
1864 # XXX: The configure.ac check for __cpuid() is broken, we don't copy that
1865 # here. To prevent problems due to two detection methods working, stop
1866 # checking after one.
1867 if cc.links('''
1868     #include <cpuid.h>
1869     int main(int arg, char **argv)
1870     {
1871         unsigned int exx[4] = {0, 0, 0, 0};
1872         __get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
1873     }
1874     ''', name: '__get_cpuid',
1875     args: test_c_args)
1876   cdata.set('HAVE__GET_CPUID', 1)
1877 elif cc.links('''
1878     #include <intrin.h>
1879     int main(int arg, char **argv)
1880     {
1881         unsigned int exx[4] = {0, 0, 0, 0};
1882         __cpuid(exx, 1);
1883     }
1884     ''', name: '__cpuid',
1885     args: test_c_args)
1886   cdata.set('HAVE__CPUID', 1)
1887 endif
1890 # Defend against clang being used on x86-32 without SSE2 enabled.  As current
1891 # versions of clang do not understand -fexcess-precision=standard, the use of
1892 # x87 floating point operations leads to problems like isinf possibly returning
1893 # false for a value that is infinite when converted from the 80bit register to
1894 # the 8byte memory representation.
1896 # Only perform the test if the compiler doesn't understand
1897 # -fexcess-precision=standard, that way a potentially fixed compiler will work
1898 # automatically.
1899 if '-fexcess-precision=standard' not in cflags
1900   if not cc.compiles('''
1901 #if defined(__clang__) && defined(__i386__) && !defined(__SSE2_MATH__)
1902 choke me
1903 #endif''',
1904       name: '', args: test_c_args)
1905     error('Compiling PostgreSQL with clang, on 32bit x86, requires SSE2 support. Use -msse2 or use gcc.')
1906   endif
1907 endif
1911 ###############################################################
1912 # Compiler flags
1913 ###############################################################
1915 common_functional_flags = [
1916   # Disable strict-aliasing rules; needed for gcc 3.3+
1917   '-fno-strict-aliasing',
1918   # Disable optimizations that assume no overflow; needed for gcc 4.3+
1919   '-fwrapv',
1920   '-fexcess-precision=standard',
1923 cflags += cc.get_supported_arguments(common_functional_flags)
1924 if llvm.found()
1925   cxxflags += cpp.get_supported_arguments(common_functional_flags)
1926 endif
1928 vectorize_cflags = cc.get_supported_arguments(['-ftree-vectorize'])
1929 unroll_loops_cflags = cc.get_supported_arguments(['-funroll-loops'])
1931 common_warning_flags = [
1932   '-Wmissing-prototypes',
1933   '-Wpointer-arith',
1934   # Really don't want VLAs to be used in our dialect of C
1935   '-Werror=vla',
1936   # On macOS, complain about usage of symbols newer than the deployment target
1937   '-Werror=unguarded-availability-new',
1938   '-Wendif-labels',
1939   '-Wmissing-format-attribute',
1940   '-Wimplicit-fallthrough=3',
1941   '-Wcast-function-type',
1942   '-Wshadow=compatible-local',
1943   # This was included in -Wall/-Wformat in older GCC versions
1944   '-Wformat-security',
1947 cflags_warn += cc.get_supported_arguments(common_warning_flags)
1948 if llvm.found()
1949   cxxflags_warn += cpp.get_supported_arguments(common_warning_flags)
1950 endif
1952 # A few places with imported code get a pass on -Wdeclaration-after-statement, remember
1953 # the result for them
1954 cflags_no_decl_after_statement = []
1955 if cc.has_argument('-Wdeclaration-after-statement')
1956   cflags_warn += '-Wdeclaration-after-statement'
1957   cflags_no_decl_after_statement += '-Wno-declaration-after-statement'
1958 endif
1961 # The following tests want to suppress various unhelpful warnings by adding
1962 # -Wno-foo switches.  But gcc won't complain about unrecognized -Wno-foo
1963 # switches, so we have to test for the positive form and if that works,
1964 # add the negative form.
1966 negative_warning_flags = [
1967   # Suppress clang's unhelpful unused-command-line-argument warnings.
1968   'unused-command-line-argument',
1970   # Remove clang 12+'s compound-token-split-by-macro, as this causes a lot
1971   # of warnings when building plperl because of usages in the Perl headers.
1972   'compound-token-split-by-macro',
1974   # Similarly disable useless truncation warnings from gcc 8+
1975   'format-truncation',
1976   'stringop-truncation',
1978   # Suppress clang 16's strict warnings about function casts
1979   'cast-function-type-strict',
1981   # To make warning_level=2 / -Wextra work, we'd need at least the following
1982   # 'clobbered',
1983   # 'missing-field-initializers',
1984   # 'sign-compare',
1985   # 'unused-parameter',
1988 foreach w : negative_warning_flags
1989   if cc.has_argument('-W' + w)
1990     cflags_warn += '-Wno-' + w
1991   endif
1992   if llvm.found() and cpp.has_argument('-W' + w)
1993     cxxflags_warn += '-Wno-' + w
1994   endif
1995 endforeach
1998 # From Project.pm
1999 if cc.get_id() == 'msvc'
2000   cflags_warn += [
2001     '/wd4018', # signed/unsigned mismatch
2002     '/wd4244', # conversion from 'type1' to 'type2', possible loss of data
2003     '/wd4273', # inconsistent DLL linkage
2004     '/wd4101', # unreferenced local variable
2005     '/wd4102', # unreferenced label
2006     '/wd4090', # different 'modifier' qualifiers
2007     '/wd4267', # conversion from 'size_t' to 'type', possible loss of data
2008   ]
2010   cppflags += [
2011     '/DWIN32',
2012     '/DWINDOWS',
2013     '/D__WINDOWS__',
2014     '/D__WIN32__',
2015     '/D_CRT_SECURE_NO_DEPRECATE',
2016     '/D_CRT_NONSTDC_NO_DEPRECATE',
2017   ]
2019   # We never need export libraries. As link.exe reports their creation, they
2020   # are unnecessarily noisy. Similarly, we don't need import library for
2021   # modules, we only import them dynamically, and they're also noisy.
2022   ldflags += '/NOEXP'
2023   ldflags_mod += '/NOIMPLIB'
2024 endif
2028 ###############################################################
2029 # Atomics
2030 ###############################################################
2032 if not get_option('spinlocks')
2033   warning('Not using spinlocks will cause poor performance')
2034 else
2035   cdata.set('HAVE_SPINLOCKS', 1)
2036 endif
2038 if not get_option('atomics')
2039   warning('Not using atomics will cause poor performance')
2040 else
2041   # XXX: perhaps we should require some atomics support in this case these
2042   # days?
2043   cdata.set('HAVE_ATOMICS', 1)
2045   atomic_checks = [
2046     {'name': 'HAVE_GCC__SYNC_CHAR_TAS',
2047      'desc': '__sync_lock_test_and_set(char)',
2048      'test': '''
2049 char lock = 0;
2050 __sync_lock_test_and_set(&lock, 1);
2051 __sync_lock_release(&lock);'''},
2053     {'name': 'HAVE_GCC__SYNC_INT32_TAS',
2054      'desc': '__sync_lock_test_and_set(int32)',
2055      'test': '''
2056 int lock = 0;
2057 __sync_lock_test_and_set(&lock, 1);
2058 __sync_lock_release(&lock);'''},
2060     {'name': 'HAVE_GCC__SYNC_INT32_CAS',
2061      'desc': '__sync_val_compare_and_swap(int32)',
2062      'test': '''
2063 int val = 0;
2064 __sync_val_compare_and_swap(&val, 0, 37);'''},
2066     {'name': 'HAVE_GCC__SYNC_INT64_CAS',
2067      'desc': '__sync_val_compare_and_swap(int64)',
2068      'test': '''
2069 INT64 val = 0;
2070 __sync_val_compare_and_swap(&val, 0, 37);'''},
2072     {'name': 'HAVE_GCC__ATOMIC_INT32_CAS',
2073      'desc': ' __atomic_compare_exchange_n(int32)',
2074      'test': '''
2075 int val = 0;
2076 int expect = 0;
2077 __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
2079     {'name': 'HAVE_GCC__ATOMIC_INT64_CAS',
2080      'desc': ' __atomic_compare_exchange_n(int64)',
2081      'test': '''
2082 INT64 val = 0;
2083 INT64 expect = 0;
2084 __atomic_compare_exchange_n(&val, &expect, 37, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);'''},
2085   ]
2087   foreach check : atomic_checks
2088     test = '''
2089 int main(void)
2092 }'''.format(check['test'])
2094     cdata.set(check['name'],
2095       cc.links(test,
2096         name: check['desc'],
2097         args: test_c_args + ['-DINT64=@0@'.format(cdata.get('PG_INT64_TYPE'))]) ? 1 : false
2098     )
2099   endforeach
2101 endif
2105 ###############################################################
2106 # Select CRC-32C implementation.
2108 # If we are targeting a processor that has Intel SSE 4.2 instructions, we can
2109 # use the special CRC instructions for calculating CRC-32C. If we're not
2110 # targeting such a processor, but we can nevertheless produce code that uses
2111 # the SSE intrinsics, perhaps with some extra CFLAGS, compile both
2112 # implementations and select which one to use at runtime, depending on whether
2113 # SSE 4.2 is supported by the processor we're running on.
2115 # Similarly, if we are targeting an ARM processor that has the CRC
2116 # instructions that are part of the ARMv8 CRC Extension, use them. And if
2117 # we're not targeting such a processor, but can nevertheless produce code that
2118 # uses the CRC instructions, compile both, and select at runtime.
2119 ###############################################################
2121 have_optimized_crc = false
2122 cflags_crc = []
2123 if host_cpu == 'x86' or host_cpu == 'x86_64'
2125   if cc.get_id() == 'msvc'
2126     cdata.set('USE_SSE42_CRC32C', false)
2127     cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
2128     have_optimized_crc = true
2129   else
2131     prog = '''
2132 #include <nmmintrin.h>
2134 int main(void)
2136     unsigned int crc = 0;
2137     crc = _mm_crc32_u8(crc, 0);
2138     crc = _mm_crc32_u32(crc, 0);
2139     /* return computed value, to prevent the above being optimized away */
2140     return crc == 0;
2144     if cc.links(prog, name: '_mm_crc32_u8 and _mm_crc32_u32 without -msse4.2',
2145           args: test_c_args)
2146       # Use Intel SSE 4.2 unconditionally.
2147       cdata.set('USE_SSE42_CRC32C', 1)
2148       have_optimized_crc = true
2149     elif cc.links(prog, name: '_mm_crc32_u8 and _mm_crc32_u32 with -msse4.2',
2150           args: test_c_args + ['-msse4.2'])
2151       # Use Intel SSE 4.2, with runtime check. The CPUID instruction is needed for
2152       # the runtime check.
2153       cflags_crc += '-msse4.2'
2154       cdata.set('USE_SSE42_CRC32C', false)
2155       cdata.set('USE_SSE42_CRC32C_WITH_RUNTIME_CHECK', 1)
2156       have_optimized_crc = true
2157     endif
2159   endif
2161 elif host_cpu == 'arm' or host_cpu == 'aarch64'
2163   prog = '''
2164 #include <arm_acle.h>
2166 int main(void)
2168     unsigned int crc = 0;
2169     crc = __crc32cb(crc, 0);
2170     crc = __crc32ch(crc, 0);
2171     crc = __crc32cw(crc, 0);
2172     crc = __crc32cd(crc, 0);
2174     /* return computed value, to prevent the above being optimized away */
2175     return crc == 0;
2179   if cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd without -march=armv8-a+crc',
2180       args: test_c_args)
2181     # Use ARM CRC Extension unconditionally
2182     cdata.set('USE_ARMV8_CRC32C', 1)
2183     have_optimized_crc = true
2184   elif cc.links(prog, name: '__crc32cb, __crc32ch, __crc32cw, and __crc32cd with -march=armv8-a+crc',
2185       args: test_c_args + ['-march=armv8-a+crc'])
2186     # Use ARM CRC Extension, with runtime check
2187     cflags_crc += '-march=armv8-a+crc'
2188     cdata.set('USE_ARMV8_CRC32C', false)
2189     cdata.set('USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK', 1)
2190     have_optimized_crc = true
2191   endif
2192 endif
2194 if not have_optimized_crc
2195   # fall back to slicing-by-8 algorithm, which doesn't require any special CPU
2196   # support.
2197   cdata.set('USE_SLICING_BY_8_CRC32C', 1)
2198 endif
2202 ###############################################################
2203 # Other CPU specific stuff
2204 ###############################################################
2206 if host_cpu == 'x86_64'
2208   if cc.compiles('''
2209       void main(void)
2210       {
2211           long long x = 1; long long r;
2212           __asm__ __volatile__ (" popcntq %1,%0\n" : "=q"(r) : "rm"(x));
2213       }''',
2214       name: '@0@: popcntq instruction'.format(host_cpu),
2215       args: test_c_args)
2216     cdata.set('HAVE_X86_64_POPCNTQ', 1)
2217   endif
2219 elif host_cpu == 'ppc' or host_cpu == 'ppc64'
2220   # Check if compiler accepts "i"(x) when __builtin_constant_p(x).
2221   if cdata.has('HAVE__BUILTIN_CONSTANT_P')
2222     if cc.compiles('''
2223       static inline int
2224       addi(int ra, int si)
2225       {
2226           int res = 0;
2227           if (__builtin_constant_p(si))
2228               __asm__ __volatile__(
2229                   " addi %0,%1,%2\n" : "=r"(res) : "b"(ra), "i"(si));
2230           return res;
2231       }
2232       int test_adds(int x) { return addi(3, x) + addi(x, 5); }
2233       ''',
2234       args: test_c_args)
2235       cdata.set('HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P', 1)
2236     endif
2237   endif
2238 endif
2242 ###############################################################
2243 # Library / OS tests
2244 ###############################################################
2246 # XXX: Might be worth conditioning some checks on the OS, to avoid doing
2247 # unnecessary checks over and over, particularly on windows.
2248 header_checks = [
2249   'atomic.h',
2250   'copyfile.h',
2251   'crtdefs.h',
2252   'execinfo.h',
2253   'getopt.h',
2254   'ifaddrs.h',
2255   'langinfo.h',
2256   'mbarrier.h',
2257   'stdbool.h',
2258   'strings.h',
2259   'sys/epoll.h',
2260   'sys/event.h',
2261   'sys/personality.h',
2262   'sys/prctl.h',
2263   'sys/procctl.h',
2264   'sys/signalfd.h',
2265   'sys/ucred.h',
2266   'termios.h',
2267   'ucred.h',
2270 foreach header : header_checks
2271   varname = 'HAVE_' + header.underscorify().to_upper()
2273   # Emulate autoconf behaviour of not-found->undef, found->1
2274   found = cc.has_header(header,
2275     include_directories: postgres_inc, args: test_c_args)
2276   cdata.set(varname, found ? 1 : false,
2277             description: 'Define to 1 if you have the <@0@> header file.'.format(header))
2278 endforeach
2281 decl_checks = [
2282   ['F_FULLFSYNC', 'fcntl.h'],
2283   ['fdatasync', 'unistd.h'],
2284   ['posix_fadvise', 'fcntl.h'],
2285   ['strlcat', 'string.h'],
2286   ['strlcpy', 'string.h'],
2287   ['strnlen', 'string.h'],
2290 # Need to check for function declarations for these functions, because
2291 # checking for library symbols wouldn't handle deployment target
2292 # restrictions on macOS
2293 decl_checks += [
2294   ['preadv', 'sys/uio.h'],
2295   ['pwritev', 'sys/uio.h'],
2298 foreach c : decl_checks
2299   func = c.get(0)
2300   header = c.get(1)
2301   args = c.get(2, {})
2302   varname = 'HAVE_DECL_' + func.underscorify().to_upper()
2304   found = cc.has_header_symbol(header, func,
2305     args: test_c_args, include_directories: postgres_inc,
2306     kwargs: args)
2307   cdata.set10(varname, found, description:
2308 '''Define to 1 if you have the declaration of `@0@', and to 0 if you
2309    don't.'''.format(func))
2310 endforeach
2313 if cc.has_type('struct option',
2314     args: test_c_args, include_directories: postgres_inc,
2315     prefix: '@0@'.format(cdata.get('HAVE_GETOPT_H')) == '1' ? '#include <getopt.h>' : '')
2316   cdata.set('HAVE_STRUCT_OPTION', 1)
2317 endif
2320 foreach c : ['opterr', 'optreset']
2321   varname = 'HAVE_INT_' + c.underscorify().to_upper()
2323   if cc.links('''
2324 #include <unistd.h>
2325 int main(void)
2327     extern int @0@;
2328     @0@ = 1;
2330 '''.format(c), name: c, args: test_c_args)
2331     cdata.set(varname, 1)
2332   else
2333     cdata.set(varname, false)
2334   endif
2335 endforeach
2337 if cc.has_type('socklen_t',
2338     args: test_c_args, include_directories: postgres_inc,
2339     prefix: '''
2340 #include <sys/socket.h>''')
2341   cdata.set('HAVE_SOCKLEN_T', 1)
2342 endif
2344 if cc.has_member('struct sockaddr', 'sa_len',
2345     args: test_c_args, include_directories: postgres_inc,
2346     prefix: '''
2347 #include <sys/types.h>
2348 #include <sys/socket.h>''')
2349   cdata.set('HAVE_STRUCT_SOCKADDR_SA_LEN', 1)
2350 endif
2352 if cc.has_member('struct tm', 'tm_zone',
2353     args: test_c_args, include_directories: postgres_inc,
2354     prefix: '''
2355 #include <sys/types.h>
2356 #include <time.h>
2357 ''')
2358   cdata.set('HAVE_STRUCT_TM_TM_ZONE', 1)
2359 endif
2361 if cc.compiles('''
2362 #include <time.h>
2363 extern int foo(void);
2364 int foo(void)
2366     return timezone / 60;
2368 ''',
2369     name: 'global variable `timezone\' exists',
2370     args: test_c_args, include_directories: postgres_inc)
2371   cdata.set('HAVE_INT_TIMEZONE', 1)
2372 else
2373   cdata.set('HAVE_INT_TIMEZONE', false)
2374 endif
2376 if cc.has_type('union semun',
2377     args: test_c_args,
2378     include_directories: postgres_inc,
2379     prefix: '''
2380 #include <sys/types.h>
2381 #include <sys/ipc.h>
2382 #include <sys/sem.h>
2383 ''')
2384   cdata.set('HAVE_UNION_SEMUN', 1)
2385 endif
2387 if cc.compiles('''
2388 #include <string.h>
2389 int main(void)
2391   char buf[100];
2392   switch (strerror_r(1, buf, sizeof(buf)))
2393   { case 0: break; default: break; }
2394 }''',
2395     name: 'strerror_r',
2396     args: test_c_args, include_directories: postgres_inc)
2397   cdata.set('STRERROR_R_INT', 1)
2398 else
2399   cdata.set('STRERROR_R_INT', false)
2400 endif
2402 # Check for the locale_t type and find the right header file.  macOS
2403 # needs xlocale.h; standard is locale.h, but glibc also has an
2404 # xlocale.h file that we should not use.  MSVC has a replacement
2405 # defined in src/include/port/win32_port.h.
2406 if cc.has_type('locale_t', prefix: '#include <locale.h>')
2407   cdata.set('HAVE_LOCALE_T', 1)
2408 elif cc.has_type('locale_t', prefix: '#include <xlocale.h>')
2409   cdata.set('HAVE_LOCALE_T', 1)
2410   cdata.set('LOCALE_T_IN_XLOCALE', 1)
2411 elif cc.get_id() == 'msvc'
2412   cdata.set('HAVE_LOCALE_T', 1)
2413 endif
2415 # Check if the C compiler understands typeof or a variant.  Define
2416 # HAVE_TYPEOF if so, and define 'typeof' to the actual key word.
2417 foreach kw : ['typeof', '__typeof__', 'decltype']
2418   if cc.compiles('''
2419 int main(void)
2421     int x = 0;
2422     @0@(x) y;
2423     y = x;
2424     return y;
2426 '''.format(kw),
2427     name: 'typeof()',
2428     args: test_c_args, include_directories: postgres_inc)
2430     cdata.set('HAVE_TYPEOF', 1)
2431     if kw != 'typeof'
2432       cdata.set('typeof', kw)
2433     endif
2435     break
2436   endif
2437 endforeach
2440 # Try to find a declaration for wcstombs_l().  It might be in stdlib.h
2441 # (following the POSIX requirement for wcstombs()), or in locale.h, or in
2442 # xlocale.h.  If it's in the latter, define WCSTOMBS_L_IN_XLOCALE.
2443 wcstombs_l_test = '''
2444 #include <stdlib.h>
2445 #include <locale.h>
2448 void main(void)
2450 #ifndef wcstombs_l
2451     (void) wcstombs_l;
2452 #endif
2455 if (not cc.compiles(wcstombs_l_test.format(''),
2456       name: 'wcstombs_l') and
2457     cc.compiles(wcstombs_l_test.format('#include <xlocale.h>'),
2458       name: 'wcstombs_l in xlocale.h'))
2459     cdata.set('WCSTOMBS_L_IN_XLOCALE', 1)
2460 endif
2463 # MSVC doesn't cope well with defining restrict to __restrict, the spelling it
2464 # understands, because it conflicts with __declspec(restrict). Therefore we
2465 # define pg_restrict to the appropriate definition, which presumably won't
2466 # conflict.
2468 # We assume C99 support, so we don't need to make this conditional.
2470 # XXX: Historically we allowed platforms to disable restrict in template
2471 # files, but that was only added for AIX when building with XLC, which we
2472 # don't support yet.
2473 cdata.set('pg_restrict', '__restrict')
2476 # Most libraries are included only if they demonstrably provide a function we
2477 # need, but libm is an exception: always include it, because there are too
2478 # many compilers that play cute optimization games that will break probes for
2479 # standard functions such as pow().
2480 os_deps += cc.find_library('m', required: false)
2482 rt_dep = cc.find_library('rt', required: false)
2484 dl_dep = cc.find_library('dl', required: false)
2486 util_dep = cc.find_library('util', required: false)
2487 posix4_dep = cc.find_library('posix4', required: false)
2489 getopt_dep = cc.find_library('getopt', required: false)
2490 gnugetopt_dep = cc.find_library('gnugetopt', required: false)
2491 # Check if we want to replace getopt/getopt_long even if provided by the system
2492 # - Mingw has adopted a GNU-centric interpretation of optind/optreset,
2493 #   so always use our version on Windows
2494 # - On OpenBSD and Solaris, getopt() doesn't do what we want for long options
2495 #   (i.e., allow '-' as a flag character), so use our version on those platforms
2496 # - We want to use system's getopt_long() only if the system provides struct
2497 #   option
2498 always_replace_getopt = host_system in ['windows', 'cygwin', 'openbsd', 'solaris']
2499 always_replace_getopt_long = host_system in ['windows', 'cygwin'] or not cdata.has('HAVE_STRUCT_OPTION')
2501 # Required on BSDs
2502 execinfo_dep = cc.find_library('execinfo', required: false)
2504 if host_system == 'cygwin'
2505   cygipc_dep = cc.find_library('cygipc', required: false)
2506 else
2507   cygipc_dep = not_found_dep
2508 endif
2510 if host_system == 'sunos'
2511   socket_dep = cc.find_library('socket', required: false)
2512 else
2513   socket_dep = not_found_dep
2514 endif
2516 # XXX: Might be worth conditioning some checks on the OS, to avoid doing
2517 # unnecessary checks over and over, particularly on windows.
2518 func_checks = [
2519   ['_configthreadlocale', {'skip': host_system != 'windows'}],
2520   ['backtrace_symbols', {'dependencies': [execinfo_dep]}],
2521   ['clock_gettime', {'dependencies': [rt_dep, posix4_dep], 'define': false}],
2522   ['copyfile'],
2523   # gcc/clang's sanitizer helper library provides dlopen but not dlsym, thus
2524   # when enabling asan the dlopen check doesn't notice that -ldl is actually
2525   # required. Just checking for dlsym() ought to suffice.
2526   ['dlsym', {'dependencies': [dl_dep], 'define': false}],
2527   ['explicit_bzero'],
2528   ['fdatasync', {'dependencies': [rt_dep, posix4_dep], 'define': false}], # Solaris
2529   ['getifaddrs'],
2530   ['getopt', {'dependencies': [getopt_dep, gnugetopt_dep], 'skip': always_replace_getopt}],
2531   ['getopt_long', {'dependencies': [getopt_dep, gnugetopt_dep], 'skip': always_replace_getopt_long}],
2532   ['getpeereid'],
2533   ['getpeerucred'],
2534   ['inet_aton'],
2535   ['inet_pton'],
2536   ['kqueue'],
2537   ['mbstowcs_l'],
2538   ['memset_s'],
2539   ['mkdtemp'],
2540   ['posix_fadvise'],
2541   ['posix_fallocate'],
2542   ['ppoll'],
2543   ['pthread_barrier_wait', {'dependencies': [thread_dep]}],
2544   ['pthread_is_threaded_np', {'dependencies': [thread_dep]}],
2545   ['sem_init', {'dependencies': [rt_dep, thread_dep], 'skip': sema_kind != 'unnamed_posix', 'define': false}],
2546   ['setproctitle', {'dependencies': [util_dep]}],
2547   ['setproctitle_fast'],
2548   ['shm_open', {'dependencies': [rt_dep], 'define': false}],
2549   ['shm_unlink', {'dependencies': [rt_dep], 'define': false}],
2550   ['shmget', {'dependencies': [cygipc_dep], 'define': false}],
2551   ['socket', {'dependencies': [socket_dep], 'define': false}],
2552   ['strchrnul'],
2553   ['strerror_r', {'dependencies': [thread_dep]}],
2554   ['strlcat'],
2555   ['strlcpy'],
2556   ['strnlen'],
2557   ['strsignal'],
2558   ['sync_file_range'],
2559   ['syncfs'],
2560   ['uselocale'],
2561   ['wcstombs_l'],
2564 func_check_results = {}
2565 foreach c : func_checks
2566   func = c.get(0)
2567   kwargs = c.get(1, {})
2568   deps = kwargs.get('dependencies', [])
2570   if kwargs.get('skip', false)
2571     continue
2572   endif
2574   found = cc.has_function(func, args: test_c_args)
2576   if not found
2577     foreach dep : deps
2578       if not dep.found()
2579         continue
2580       endif
2581       found = cc.has_function(func, args: test_c_args,
2582                               dependencies: [dep])
2583       if found
2584         os_deps += dep
2585         break
2586       endif
2587     endforeach
2588   endif
2590   func_check_results += {func: found}
2592   if kwargs.get('define', true)
2593     # Emulate autoconf behaviour of not-found->undef, found->1
2594     cdata.set('HAVE_' + func.underscorify().to_upper(),
2595               found  ? 1 : false,
2596               description: 'Define to 1 if you have the `@0@\' function.'.format(func))
2597   endif
2598 endforeach
2601 if cc.has_function('syslog', args: test_c_args) and \
2602     cc.check_header('syslog.h', args: test_c_args)
2603   cdata.set('HAVE_SYSLOG', 1)
2604 endif
2607 # MSVC has replacements defined in src/include/port/win32_port.h.
2608 if cc.get_id() == 'msvc'
2609   cdata.set('HAVE_WCSTOMBS_L', 1)
2610   cdata.set('HAVE_MBSTOWCS_L', 1)
2611 endif
2614 # if prerequisites for unnamed posix semas aren't fulfilled, fall back to sysv
2615 # semaphores
2616 if sema_kind == 'unnamed_posix' and \
2617    not func_check_results.get('sem_init', false)
2618   sema_kind = 'sysv'
2619 endif
2621 cdata.set('USE_@0@_SHARED_MEMORY'.format(shmem_kind.to_upper()), 1)
2622 cdata.set('USE_@0@_SEMAPHORES'.format(sema_kind.to_upper()), 1)
2624 cdata.set('MEMSET_LOOP_LIMIT', memset_loop_limit)
2625 cdata.set_quoted('DLSUFFIX', dlsuffix)
2628 # built later than the rest of the version metadata, we need SIZEOF_VOID_P
2629 cdata.set_quoted('PG_VERSION_STR',
2630   'PostgreSQL @0@ on @1@-@2@, compiled by @3@-@4@, @5@-bit'.format(
2631     pg_version, host_machine.cpu_family(), host_system,
2632     cc.get_id(), cc.version(), cdata.get('SIZEOF_VOID_P') * 8,
2633   )
2638 ###############################################################
2639 # Threading
2640 ###############################################################
2642 # XXX: About to rely on thread safety in the autoconf build, so not worth
2643 # implementing a fallback.
2644 cdata.set('ENABLE_THREAD_SAFETY', 1)
2648 ###############################################################
2649 # NLS / Gettext
2650 ###############################################################
2652 nlsopt = get_option('nls')
2653 libintl = not_found_dep
2655 if not nlsopt.disabled()
2656   # otherwise there'd be lots of
2657   # "Gettext not found, all translation (po) targets will be ignored."
2658   # warnings if not found.
2659   msgfmt = find_program('msgfmt', required: nlsopt, native: true)
2661   # meson 0.59 has this wrapped in dependency('intl')
2662   if (msgfmt.found() and
2663       cc.check_header('libintl.h', required: nlsopt,
2664         args: test_c_args, include_directories: postgres_inc))
2666     # in libc
2667     if cc.has_function('ngettext')
2668       libintl = declare_dependency()
2669     else
2670       libintl = cc.find_library('intl',
2671         has_headers: ['libintl.h'], required: nlsopt,
2672         header_include_directories: postgres_inc,
2673         dirs: test_lib_d)
2674     endif
2675   endif
2677   if libintl.found()
2678     i18n = import('i18n')
2679     cdata.set('ENABLE_NLS', 1)
2680   endif
2681 endif
2685 ###############################################################
2686 # Build
2687 ###############################################################
2689 # Set up compiler / linker arguments to be used everywhere, individual targets
2690 # can add further args directly, or indirectly via dependencies
2691 add_project_arguments(cflags, language: ['c'])
2692 add_project_arguments(cppflags, language: ['c'])
2693 add_project_arguments(cflags_warn, language: ['c'])
2694 add_project_arguments(cxxflags, language: ['cpp'])
2695 add_project_arguments(cppflags, language: ['cpp'])
2696 add_project_arguments(cxxflags_warn, language: ['cpp'])
2697 add_project_link_arguments(ldflags, language: ['c', 'cpp'])
2700 # Collect a number of lists of things while recursing through the source
2701 # tree. Later steps then can use those.
2703 # list of targets for various alias targets
2704 backend_targets = []
2705 bin_targets = []
2706 pl_targets = []
2707 contrib_targets = []
2708 testprep_targets = []
2709 nls_targets = []
2712 # Define the tests to distribute them to the correct test styles later
2713 test_deps = []
2714 tests = []
2717 # Default options for targets
2719 # First identify rpaths
2720 bin_install_rpaths = []
2721 lib_install_rpaths = []
2722 mod_install_rpaths = []
2725 # Don't add rpaths on darwin for now - as long as only absolute references to
2726 # libraries are needed, absolute LC_ID_DYLIB ensures libraries can be found in
2727 # their final destination.
2728 if host_system != 'darwin'
2729   # Add absolute path to libdir to rpath. This ensures installed binaries /
2730   # libraries find our libraries (mainly libpq).
2731   bin_install_rpaths += dir_prefix / dir_lib
2732   lib_install_rpaths += dir_prefix / dir_lib
2733   mod_install_rpaths += dir_prefix / dir_lib
2735   # Add extra_lib_dirs to rpath. This ensures we find libraries we depend on.
2736   #
2737   # Not needed on darwin even if we use relative rpaths for our own libraries,
2738   # as the install_name of libraries in extra_lib_dirs will point to their
2739   # location anyway.
2740   bin_install_rpaths += postgres_lib_d
2741   lib_install_rpaths += postgres_lib_d
2742   mod_install_rpaths += postgres_lib_d
2743 endif
2746 # Define arguments for default targets
2748 default_target_args = {
2749   'implicit_include_directories': false,
2750   'install': true,
2753 default_lib_args = default_target_args + {
2754   'name_prefix': '',
2757 internal_lib_args = default_lib_args + {
2758   'build_by_default': false,
2759   'install': false,
2762 default_mod_args = default_lib_args + {
2763   'name_prefix': '',
2764   'install_dir': dir_lib_pkg,
2767 default_bin_args = default_target_args + {
2768   'install_dir': dir_bin,
2771 if get_option('rpath')
2772   default_lib_args += {
2773     'install_rpath': ':'.join(lib_install_rpaths),
2774   }
2776   default_mod_args += {
2777     'install_rpath': ':'.join(mod_install_rpaths),
2778   }
2780   default_bin_args += {
2781     'install_rpath': ':'.join(bin_install_rpaths),
2782   }
2783 endif
2786 # Helper for exporting a limited number of symbols
2787 gen_export_kwargs = {
2788   'input': 'exports.txt',
2789   'output': '@BASENAME@.'+export_file_suffix,
2790   'command': [perl, files('src/tools/gen_export.pl'),
2791    '--format', export_file_format,
2792    '--input', '@INPUT0@', '--output', '@OUTPUT0@'],
2793   'build_by_default': false,
2794   'install': false,
2800 ### Helpers for custom targets used across the tree
2803 catalog_pm = files('src/backend/catalog/Catalog.pm')
2804 perfect_hash_pm = files('src/tools/PerfectHash.pm')
2805 gen_kwlist_deps = [perfect_hash_pm]
2806 gen_kwlist_cmd = [
2807   perl, '-I', '@SOURCE_ROOT@/src/tools',
2808   files('src/tools/gen_keywordlist.pl'),
2809   '--output', '@OUTDIR@', '@INPUT@']
2814 ### windows resources related stuff
2817 if host_system == 'windows'
2818   pg_ico = meson.source_root() / 'src' / 'port' / 'win32.ico'
2819   win32ver_rc = files('src/port/win32ver.rc')
2820   rcgen = find_program('src/tools/rcgen', native: true)
2822   rcgen_base_args = [
2823     '--srcdir', '@SOURCE_DIR@',
2824     '--builddir', meson.build_root(),
2825     '--rcout', '@OUTPUT0@',
2826     '--out', '@OUTPUT1@',
2827     '--input', '@INPUT@',
2828     '@EXTRA_ARGS@',
2829   ]
2831   if cc.get_argument_syntax() == 'msvc'
2832     rc = find_program('rc', required: true)
2833     rcgen_base_args += ['--rc', rc.path()]
2834     rcgen_outputs = ['@BASENAME@.rc', '@BASENAME@.res']
2835   else
2836     windres = find_program('windres', required: true)
2837     rcgen_base_args += ['--windres', windres.path()]
2838     rcgen_outputs = ['@BASENAME@.rc', '@BASENAME@.obj']
2839   endif
2841   # msbuild backend doesn't support this atm
2842   if meson.backend() == 'ninja'
2843     rcgen_base_args += ['--depfile', '@DEPFILE@']
2844   endif
2846   rcgen_bin_args = rcgen_base_args + [
2847     '--VFT_TYPE', 'VFT_APP',
2848     '--FILEENDING', 'exe',
2849     '--ICO', pg_ico
2850   ]
2852   rcgen_lib_args = rcgen_base_args + [
2853     '--VFT_TYPE', 'VFT_DLL',
2854     '--FILEENDING', 'dll',
2855   ]
2857   rc_bin_gen = generator(rcgen,
2858     depfile: '@BASENAME@.d',
2859     arguments: rcgen_bin_args,
2860     output: rcgen_outputs,
2861   )
2863   rc_lib_gen = generator(rcgen,
2864     depfile: '@BASENAME@.d',
2865     arguments: rcgen_lib_args,
2866     output: rcgen_outputs,
2867   )
2868 endif
2872 # headers that the whole build tree depends on
2873 generated_headers = []
2874 # headers that the backend build depends on
2875 generated_backend_headers = []
2876 # configure_files() output, needs a way of converting to file names
2877 configure_files = []
2879 # generated files that might conflict with a partial in-tree autoconf build
2880 generated_sources = []
2881 # same, for paths that differ between autoconf / meson builds
2882 # elements are [dir, [files]]
2883 generated_sources_ac = {}
2886 # First visit src/include - all targets creating headers are defined
2887 # within. That makes it easy to add the necessary dependencies for the
2888 # subsequent build steps.
2890 subdir('src/include')
2892 subdir('config')
2894 # Then through src/port and src/common, as most other things depend on them
2896 frontend_port_code = declare_dependency(
2897   compile_args: ['-DFRONTEND'],
2898   include_directories: [postgres_inc],
2899   dependencies: os_deps,
2902 backend_port_code = declare_dependency(
2903   compile_args: ['-DBUILDING_DLL'],
2904   include_directories: [postgres_inc],
2905   sources: [errcodes], # errcodes.h is needed due to use of ereport
2906   dependencies: os_deps,
2909 subdir('src/port')
2911 frontend_common_code = declare_dependency(
2912   compile_args: ['-DFRONTEND'],
2913   include_directories: [postgres_inc],
2914   sources: generated_headers,
2915   dependencies: [os_deps, zlib, zstd],
2918 backend_common_code = declare_dependency(
2919   compile_args: ['-DBUILDING_DLL'],
2920   include_directories: [postgres_inc],
2921   sources: generated_headers,
2922   dependencies: [os_deps, zlib, zstd],
2925 subdir('src/common')
2927 # all shared libraries should depend on shlib_code
2928 shlib_code = declare_dependency(
2929   link_args: ldflags_sl,
2932 # all static libraries not part of the backend should depend on this
2933 frontend_stlib_code = declare_dependency(
2934   include_directories: [postgres_inc],
2935   link_with: [common_static, pgport_static],
2936   sources: generated_headers,
2937   dependencies: [os_deps, libintl],
2940 # all shared libraries not part of the backend should depend on this
2941 frontend_shlib_code = declare_dependency(
2942   include_directories: [postgres_inc],
2943   link_with: [common_shlib, pgport_shlib],
2944   sources: generated_headers,
2945   dependencies: [shlib_code, os_deps, libintl],
2948 # Dependencies both for static and shared libpq
2949 libpq_deps += [
2950   thread_dep,
2952   gssapi,
2953   ldap_r,
2954   libintl,
2955   ssl,
2958 subdir('src/interfaces/libpq')
2959 # fe_utils depends on libpq
2960 subdir('src/fe_utils')
2962 # for frontend binaries
2963 frontend_code = declare_dependency(
2964   include_directories: [postgres_inc],
2965   link_with: [fe_utils, common_static, pgport_static],
2966   sources: generated_headers,
2967   dependencies: [os_deps, libintl],
2970 backend_both_deps += [
2971   thread_dep,
2972   bsd_auth,
2973   gssapi,
2974   icu,
2975   icu_i18n,
2976   ldap,
2977   libintl,
2978   libxml,
2979   lz4,
2980   pam,
2981   ssl,
2982   systemd,
2983   zlib,
2984   zstd,
2987 backend_mod_deps = backend_both_deps + os_deps
2989 backend_code = declare_dependency(
2990   compile_args: ['-DBUILDING_DLL'],
2991   include_directories: [postgres_inc],
2992   link_args: ldflags_be,
2993   link_with: [],
2994   sources: generated_headers + generated_backend_headers,
2995   dependencies: os_deps + backend_both_deps + backend_deps,
2998 # install these files only during test, not main install
2999 test_install_data = []
3000 test_install_libs = []
3002 # src/backend/meson.build defines backend_mod_code used for extension
3003 # libraries.
3006 # Then through the main sources. That way contrib can have dependencies on
3007 # main sources. Note that this explicitly doesn't enter src/test, right now a
3008 # few regression tests depend on contrib files.
3010 subdir('src')
3012 subdir('contrib')
3014 subdir('src/test')
3015 subdir('src/interfaces/libpq/test')
3016 subdir('src/interfaces/ecpg/test')
3018 subdir('doc/src/sgml')
3020 generated_sources_ac += {'': ['GNUmakefile']}
3022 # After processing src/test, add test_install_libs to the testprep_targets
3023 # to build them
3024 testprep_targets += test_install_libs
3027 # If there are any files in the source directory that we also generate in the
3028 # build directory, they might get preferred over the newly generated files,
3029 # e.g. because of a #include "file", which always will search in the current
3030 # directory first.
3031 message('checking for file conflicts between source and build directory')
3032 conflicting_files = []
3033 potentially_conflicting_files_t = []
3034 potentially_conflicting_files_t += generated_headers
3035 potentially_conflicting_files_t += generated_backend_headers
3036 potentially_conflicting_files_t += generated_backend_sources
3037 potentially_conflicting_files_t += generated_sources
3039 potentially_conflicting_files = []
3041 # convert all sources of potentially conflicting files into uniform shape
3042 foreach t : potentially_conflicting_files_t
3043   potentially_conflicting_files += t.full_path()
3044 endforeach
3045 foreach t1 : configure_files
3046   if meson.version().version_compare('>=0.59')
3047     t = fs.parent(t1) / fs.name(t1)
3048   else
3049     t = '@0@'.format(t1)
3050   endif
3051   potentially_conflicting_files += meson.current_build_dir() / t
3052 endforeach
3053 foreach sub, fnames : generated_sources_ac
3054   sub = meson.build_root() / sub
3055   foreach fname : fnames
3056     potentially_conflicting_files += sub / fname
3057   endforeach
3058 endforeach
3060 # find and report conflicting files
3061 foreach build_path : potentially_conflicting_files
3062   build_path = host_system == 'windows' ? fs.as_posix(build_path) : build_path
3063   # str.replace is in 0.56
3064   src_path = meson.current_source_dir() / build_path.split(meson.current_build_dir() / '')[1]
3065   if fs.exists(src_path) or fs.is_symlink(src_path)
3066     conflicting_files += src_path
3067   endif
3068 endforeach
3069 # XXX: Perhaps we should generate a file that would clean these up? The list
3070 # can be long.
3071 if conflicting_files.length() > 0
3072   errmsg_cleanup = '''
3073 Conflicting files in source directory:
3074   @0@
3076 The conflicting files need to be removed, either by removing the files listed
3077 above, or by running configure and then make maintainer-clean.
3079   errmsg_cleanup = errmsg_cleanup.format(' '.join(conflicting_files))
3080   error(errmsg_nonclean_base.format(errmsg_cleanup))
3081 endif
3085 ###############################################################
3086 # Install targets
3087 ###############################################################
3090 # We want to define additional install targets beyond what meson provides. For
3091 # that we need to define targets depending on nearly everything. We collected
3092 # the results of i18n.gettext() invocations into nls_targets, that also
3093 # includes maintainer targets though. Collect the ones we want as a dependency.
3095 # i18n.gettext() doesn't return the dependencies before 0.60 - but the gettext
3096 # generation happens during install, so that's not a real issue.
3097 nls_mo_targets = []
3098 if libintl.found() and meson.version().version_compare('>=0.60')
3099   # use range() to avoid the flattening of the list that foreach() would do
3100   foreach off : range(0, nls_targets.length())
3101     # i18n.gettext() list containing 1) list of built .mo files 2) maintainer
3102     # -pot target 3) maintainer -pot target
3103     nls_mo_targets += nls_targets[off][0]
3104   endforeach
3105   alias_target('nls', nls_mo_targets)
3106 endif
3109 all_built = [
3110   backend_targets,
3111   bin_targets,
3112   libpq_st,
3113   pl_targets,
3114   contrib_targets,
3115   nls_mo_targets,
3116   testprep_targets,
3117   ecpg_targets,
3120 # Meson's default install target is quite verbose. Provide one that is quiet.
3121 install_quiet = custom_target('install-quiet',
3122   output: 'install-quiet',
3123   build_always_stale: true,
3124   build_by_default: false,
3125   command: [meson_bin, meson_args, 'install', '--quiet', '--no-rebuild'],
3126   depends: all_built,
3129 # Target to install files used for tests, which aren't installed by default
3130 install_test_files_args = [
3131   install_files,
3132   '--prefix', dir_prefix,
3133   '--install', contrib_data_dir, test_install_data,
3134   '--install', dir_lib_pkg, test_install_libs,
3136 run_target('install-test-files',
3137   command: [python] + install_test_files_args,
3138   depends: testprep_targets,
3143 ###############################################################
3144 # Test prep
3145 ###############################################################
3147 # DESTDIR for the installation we'll run tests in
3148 test_install_destdir = meson.build_root() / 'tmp_install/'
3150 # DESTDIR + prefix appropriately munged
3151 if build_system != 'windows'
3152   # On unixoid systems this is trivial, we just prepend the destdir
3153   assert(dir_prefix.startswith('/')) # enforced by meson
3154   temp_install_bindir = '@0@@1@'.format(test_install_destdir, dir_prefix / dir_bin)
3155   temp_install_libdir = '@0@@1@'.format(test_install_destdir, dir_prefix / dir_lib)
3156 else
3157   # drives, drive-relative paths, etc make this complicated on windows, call
3158   # into a copy of meson's logic for it
3159   command = [
3160     python, '-c',
3161     'import sys; from pathlib import PurePath; d1=sys.argv[1]; d2=sys.argv[2]; print(str(PurePath(d1, *PurePath(d2).parts[1:])))',
3162     test_install_destdir]
3163   temp_install_bindir = run_command(command, dir_prefix / dir_bin, check: true).stdout().strip()
3164   temp_install_libdir = run_command(command, dir_prefix / dir_lib, check: true).stdout().strip()
3165 endif
3167 meson_install_args = meson_args + ['install'] + {
3168     'meson': ['--quiet', '--only-changed', '--no-rebuild'],
3169     'muon': []
3170 }[meson_impl]
3172 # setup tests should be run first,
3173 # so define priority for these
3174 setup_tests_priority = 100
3175 test('tmp_install',
3176     meson_bin, args: meson_install_args ,
3177     env: {'DESTDIR':test_install_destdir},
3178     priority: setup_tests_priority,
3179     timeout: 300,
3180     is_parallel: false,
3181     suite: ['setup'])
3183 test('install_test_files',
3184     python,
3185     args: install_test_files_args + ['--destdir', test_install_destdir],
3186     priority: setup_tests_priority,
3187     is_parallel: false,
3188     suite: ['setup'])
3190 test_result_dir = meson.build_root() / 'testrun'
3193 # XXX: pg_regress doesn't assign unique ports on windows. To avoid the
3194 # inevitable conflicts from running tests in parallel, hackishly assign
3195 # different ports for different tests.
3197 testport = 40000
3199 test_env = environment()
3201 test_initdb_template = meson.build_root() / 'tmp_install' / 'initdb-template'
3202 test_env.set('PG_REGRESS', pg_regress.full_path())
3203 test_env.set('REGRESS_SHLIB', regress_module.full_path())
3205 # Test suites that are not safe by default but can be run if selected
3206 # by the user via the whitespace-separated list in variable PG_TEST_EXTRA.
3207 # Export PG_TEST_EXTRA so it can be checked in individual tap tests.
3208 test_env.set('PG_TEST_EXTRA', get_option('PG_TEST_EXTRA'))
3210 # Add the temporary installation to the library search path on platforms where
3211 # that works (everything but windows, basically). On windows everything
3212 # library-like gets installed into bindir, solving that issue.
3213 if library_path_var != ''
3214   test_env.prepend(library_path_var, temp_install_libdir)
3215 endif
3219 ###############################################################
3220 # Test Generation
3221 ###############################################################
3223 # When using a meson version understanding exclude_suites, define a
3224 # 'tmp_install' test setup (the default) that excludes tests running against a
3225 # pre-existing install and a 'running' setup that conflicts with creation of
3226 # the temporary installation and tap tests (which don't support running
3227 # against a running server).
3229 running_suites = []
3230 install_suites = []
3231 if meson.version().version_compare('>=0.57')
3232   runningcheck = true
3233 else
3234   runningcheck = false
3235 endif
3237 testwrap = files('src/tools/testwrap')
3239 foreach test_dir : tests
3240   testwrap_base = [
3241     testwrap,
3242     '--basedir', meson.build_root(),
3243     '--srcdir', test_dir['sd'],
3244   ]
3246   foreach kind, v : test_dir
3247     if kind in ['sd', 'bd', 'name']
3248       continue
3249     endif
3251     t = test_dir[kind]
3253     if kind in ['regress', 'isolation', 'ecpg']
3254       if kind == 'regress'
3255         runner = pg_regress
3256         fallback_dbname = 'regression_@0@'
3257       elif kind == 'isolation'
3258         runner = pg_isolation_regress
3259         fallback_dbname = 'isolation_regression_@0@'
3260       elif kind == 'ecpg'
3261         runner = pg_regress_ecpg
3262         fallback_dbname = 'ecpg_regression_@0@'
3263       endif
3265       test_group = test_dir['name']
3266       test_group_running = test_dir['name'] + '-running'
3268       test_output = test_result_dir / test_group / kind
3269       test_output_running = test_result_dir / test_group_running/ kind
3271       # Unless specified by the test, choose a non-conflicting database name,
3272       # to avoid conflicts when running against existing server.
3273       dbname = t.get('dbname',
3274         fallback_dbname.format(test_dir['name']))
3276       test_command_base = [
3277         runner.full_path(),
3278         '--inputdir', t.get('inputdir', test_dir['sd']),
3279         '--expecteddir', t.get('expecteddir', test_dir['sd']),
3280         '--bindir', '',
3281         '--dlpath', test_dir['bd'],
3282         '--max-concurrent-tests=20',
3283         '--dbname', dbname,
3284       ] + t.get('regress_args', [])
3286       test_selection = []
3287       if t.has_key('schedule')
3288         test_selection += ['--schedule', t['schedule'],]
3289       endif
3291       if kind == 'isolation'
3292         test_selection += t.get('specs', [])
3293       else
3294         test_selection += t.get('sql', [])
3295       endif
3297       env = test_env
3298       env.prepend('PATH', temp_install_bindir, test_dir['bd'])
3300       test_kwargs = {
3301         'protocol': 'tap',
3302         'priority': 10,
3303         'timeout': 1000,
3304         'depends': test_deps + t.get('deps', []),
3305         'env': env,
3306       } + t.get('test_kwargs', {})
3308       test(test_group / kind,
3309         python,
3310         args: [
3311           testwrap_base,
3312           '--testgroup', test_group,
3313           '--testname', kind,
3314           '--',
3315           test_command_base,
3316           '--outputdir', test_output,
3317           '--temp-instance', test_output / 'tmp_check',
3318           '--port', testport.to_string(),
3319           test_selection,
3320         ],
3321         suite: test_group,
3322         kwargs: test_kwargs,
3323       )
3324       install_suites += test_group
3326       # some tests can't support running against running DB
3327       if runningcheck and t.get('runningcheck', true)
3328         test(test_group_running / kind,
3329           python,
3330           args: [
3331             testwrap_base,
3332             '--testgroup', test_group_running,
3333             '--testname', kind,
3334             '--',
3335             test_command_base,
3336             '--outputdir', test_output_running,
3337             test_selection,
3338           ],
3339           is_parallel: t.get('runningcheck-parallel', true),
3340           suite: test_group_running,
3341           kwargs: test_kwargs,
3342         )
3343         running_suites += test_group_running
3344       endif
3346       testport += 1
3347     elif kind == 'tap'
3348       if not tap_tests_enabled
3349         continue
3350       endif
3352       test_command = [
3353         perl.path(),
3354         '-I', meson.source_root() / 'src/test/perl',
3355         '-I', test_dir['sd'],
3356       ]
3358       # Add temporary install, the build directory for non-installed binaries and
3359       # also test/ for non-installed test binaries built separately.
3360       env = test_env
3361       env.prepend('PATH', temp_install_bindir, test_dir['bd'], test_dir['bd'] / 'test')
3363       foreach name, value : t.get('env', {})
3364         env.set(name, value)
3365       endforeach
3367       test_group = test_dir['name']
3368       test_kwargs = {
3369         'protocol': 'tap',
3370         'suite': test_group,
3371         'timeout': 1000,
3372         'depends': test_deps + t.get('deps', []),
3373         'env': env,
3374       } + t.get('test_kwargs', {})
3376       foreach onetap : t['tests']
3377         # Make tap test names prettier, remove t/ and .pl
3378         onetap_p = onetap
3379         if onetap_p.startswith('t/')
3380           onetap_p = onetap.split('t/')[1]
3381         endif
3382         if onetap_p.endswith('.pl')
3383           onetap_p = fs.stem(onetap_p)
3384         endif
3386         test(test_dir['name'] / onetap_p,
3387           python,
3388           kwargs: test_kwargs,
3389           args: testwrap_base + [
3390             '--testgroup', test_dir['name'],
3391             '--testname', onetap_p,
3392             '--', test_command,
3393             test_dir['sd'] / onetap,
3394           ],
3395         )
3396       endforeach
3397       install_suites += test_group
3398     else
3399       error('unknown kind @0@ of test in @1@'.format(kind, test_dir['sd']))
3400     endif
3402   endforeach # kinds of tests
3404 endforeach # directories with tests
3406 # repeat condition so meson realizes version dependency
3407 if meson.version().version_compare('>=0.57')
3408   add_test_setup('tmp_install',
3409     is_default: true,
3410     exclude_suites: running_suites)
3411   add_test_setup('running',
3412     exclude_suites: ['setup'] + install_suites)
3413 endif
3417 ###############################################################
3418 # Pseudo targets
3419 ###############################################################
3421 alias_target('backend', backend_targets)
3422 alias_target('bin', bin_targets + [libpq_st])
3423 alias_target('pl', pl_targets)
3424 alias_target('contrib', contrib_targets)
3425 alias_target('testprep', testprep_targets)
3426 alias_target('install-world', install_quiet, installdocs)
3430 ###############################################################
3431 # The End, The End, My Friend
3432 ###############################################################
3434 if meson.version().version_compare('>=0.57')
3436   summary(
3437     {
3438       'data block size': '@0@ kB'.format(cdata.get('BLCKSZ') / 1024),
3439       'WAL block size': '@0@ kB'.format(cdata.get('XLOG_BLCKSZ') / 1024),
3440       'segment size': get_option('segsize_blocks') != 0 ?
3441         '@0@ blocks'.format(cdata.get('RELSEG_SIZE')) :
3442         '@0@ GB'.format(get_option('segsize')),
3443     },
3444     section: 'Data layout',
3445   )
3447   summary(
3448     {
3449       'host system': '@0@ @1@'.format(host_system, host_cpu),
3450       'build system': '@0@ @1@'.format(build_machine.system(),
3451                                        build_machine.cpu_family()),
3452     },
3453     section: 'System',
3454   )
3456   summary(
3457     {
3458       'linker': '@0@'.format(cc.get_linker_id()),
3459       'C compiler': '@0@ @1@'.format(cc.get_id(), cc.version()),
3460     },
3461     section: 'Compiler',
3462   )
3464   summary(
3465     {
3466       'CPP FLAGS': ' '.join(cppflags),
3467       'C FLAGS, functional': ' '.join(cflags),
3468       'C FLAGS, warnings': ' '.join(cflags_warn),
3469       'C FLAGS, modules': ' '.join(cflags_mod),
3470       'C FLAGS, user specified': ' '.join(get_option('c_args')),
3471       'LD FLAGS': ' '.join(ldflags + get_option('c_link_args')),
3472     },
3473     section: 'Compiler Flags',
3474   )
3476   if llvm.found()
3477     summary(
3478       {
3479         'C++ compiler': '@0@ @1@'.format(cpp.get_id(), cpp.version()),
3480       },
3481       section: 'Compiler',
3482     )
3484     summary(
3485       {
3486         'C++ FLAGS, functional': ' '.join(cxxflags),
3487         'C++ FLAGS, warnings': ' '.join(cxxflags_warn),
3488         'C++ FLAGS, user specified': ' '.join(get_option('cpp_args')),
3489       },
3490       section: 'Compiler Flags',
3491     )
3492   endif
3494   summary(
3495     {
3496       'bison': '@0@ @1@'.format(bison.full_path(), bison_version),
3497       'dtrace': dtrace,
3498     },
3499     section: 'Programs',
3500   )
3502   summary(
3503     {
3504       'bonjour': bonjour,
3505       'bsd_auth': bsd_auth,
3506       'docs': docs_dep,
3507       'docs_pdf': docs_pdf_dep,
3508       'gss': gssapi,
3509       'icu': icu,
3510       'ldap': ldap,
3511       'libxml': libxml,
3512       'libxslt': libxslt,
3513       'llvm': llvm,
3514       'lz4': lz4,
3515       'nls': libintl,
3516       'openssl': ssl,
3517       'pam': pam,
3518       'plperl': perl_dep,
3519       'plpython': python3_dep,
3520       'pltcl': tcl_dep,
3521       'readline': readline,
3522       'selinux': selinux,
3523       'systemd': systemd,
3524       'uuid': uuid,
3525       'zlib': zlib,
3526       'zstd': zstd,
3527     },
3528     section: 'External libraries',
3529   )
3531 endif